# Author: Chao-Kuei Hung
# For more info, including license, please see doc/index.html
package RBTree;
# Red-Black Tree
use strict;
use Carp;
use vars qw(@ISA);
@ISA = qw(BST);
use BST;
# sub new { my ($self) = shift; $self->SUPER::new(@_); }
sub insert {
my ($self, $sk_cont, %opts) = @_;
# $sk_cont is search key, should have the same structure as -content=>...
my ($nn, $r, $focus, $grand, $parent, $uncle);
$nn = $self->SUPER::insert($sk_cont, %opts);
$nn->configure(-status=>"discard");
$self->cget(-canvas)->set_mark(0);
$focus = $nn;
while (1) {
$parent = $focus->parent();
last if $parent->cget(-status) ne "discard";
die if $parent->level() <= 0; # impossibe, because root is always black
$grand = $parent->parent();
$uncle = $grand->child(1 - $parent->rank());
if (ref $uncle and $uncle->cget(-status) eq "discard") {
# then parent is not the root
$parent->configure(-status=>"done");
$uncle->configure(-status=>"done");
$grand->configure(-status=>"discard");
$self->cget(-canvas)->set_mark(0);
$focus = $grand;
} else {
if ($focus->rank() != $parent->rank()) {
if ($parent->rank() == 0) {
$parent->rotate_ccw();
} else {
$parent->rotate_cw();
}
$self->cget(-canvas)->set_mark(0);
($focus, $parent) = ($parent, $focus);
}
if ($parent->rank() == 0) {
$grand->rotate_cw();
} else {
$grand->rotate_ccw();
}
$parent->configure(-status=>"done");
$grand->configure(-status=>"discard");
$focus->configure(-status=>"discard");
$self->cget(-canvas)->set_mark(0);
last;
}
}
# make sure root is always black
$self->root()->configure(-status=>"done")
unless $self->root()->cget(-status) eq "done";
return $nn;
}
sub remove {
my ($self, $node) = @_;
print STDERR "remove() not implemented yet, ignored\n";
return undef;
}
$::Config->{RBTree} = {
-appearance => {
%{ ::deep_copy(Configurable::cget("BST", -appearance)) },
done => { -outline=>"Black",-fill=>"Gray",
-thick=>3, -stipple=>"" },
discard => { -outline=>"DarkRed", -fill=>"LightCoral",
-thick=>3, -stipple=>"gray25" },
focus => { -outline=>"DarkBlue", -fill=>"LightBlue",
-thick=>3, -stipple=>"gray25" },
},
};
if ($0 =~ /RBTree.pm$/) {
# being tested as a stand-alone program, so run test code.
require "utilalgo";
my ($mw, $ctrl, $can);
$mw = MainWindow->new(-title=>"main_test");
$can->{main} = gen_can($mw, undef, -elevation=>1, -maxlevel=>2);
$ctrl = gen_ctrl($mw, $can);
my ($tr) = RBTree->new(-canvas=>$can->{main}, %{ do "data/countries.gr" });
# $can->{main}->set_mark(1);
$ctrl->configure(-recorder=>0);
# If the canvas refuses to show any change, remember to verify that:
# - set_mark() was called at least once
# - -recorder is set to zero before entering MainLoop
# Failing to do either of the above will result in a mysterious bug
# that takes days to figure out !@#$%
Tk::MainLoop();
}
1;
syntax highlighted by Code2HTML, v. 0.9.1