Skip Menu |

This queue is for tickets about the Tree-Binary CPAN distribution.

Report information
The Basics
Id: 44801
Status: resolved
Worked: 8 hours (480 min)
Priority: 0/
Queue: Tree-Binary

People
Owner: Nobody in particular
Requestors: kastner.karl [...] googlemail.com
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 0.06
Fixed in: (no value)



Subject: Entire branch is deleted instead of single nodes in some cases
Hello, in some cases the sub delete() does delete an entire branch instead of a single node only. The attached test script yields following output: 7 L ( K ( ) P ( N ( M ( ) O ( ) ) Q ( ) ) ) 5 N ( K ( ) P ( O ( ) Q ( ) ) ) While deleting node "L" the node "N" becomes the root and it's left child "M" gets lost. The size is reduced to 5 nodes instead of 6. This bug makes the sub delete virtually useless and leads silently to data losses. Please fix this bug as soon as possible. Thanks Karl
Subject: test-tree.pl
# Test case : entire branch is deleted instead of single node only # # Copyright (C) Karl Kästner - Berlin, Germany # Sun Apr 5 07:24:11 MSD 2009 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. use Tree::Binary::Search; my $tree = Tree::Binary::Search->new(); $tree->useStringComparison(); $tree->insert("L", "L"); $tree->insert("K", "K"); $tree->insert("P", "P"); $tree->insert("N", "N"); $tree->insert("M", "M"); $tree->insert("O", "O"); $tree->insert("Q", "Q"); print $tree->size()."\n"; _print(Tree::Binary::Search::getTree($tree)); print "\n"; $tree->delete("L"); print $tree->size()."\n"; _print(Tree::Binary::Search::getTree($tree)); sub _print { my $self = shift; # rekursiv linken und rechten Ast ausgeben if (defined $self) { my $value = $self->getNodeValue(); print $value." "; print " ( "; _print($self->getLeft); _print($self->getRight); print " ) "; } }
Hello, here is a patch resolving this issue and a more sophisticated test script. Please integrate the patch. Karl Without patch (node M in last test gets lost): K L P Q -- 4 3 -- K P Q K L N P Q -- 5 4 -- K N P Q K L M N P Q -- 6 5 -- K M N P Q K L N O P Q -- 6 5 -- K N O P Q Number of elements incorrect K L M N O P Q -- 7 5 -- K N O P Q Patched: K L P Q -- 4 3 -- K P Q K L N P Q -- 5 4 -- K N P Q K L M N P Q -- 6 5 -- K M N P Q K L N O P Q -- 6 5 -- K N O P Q K L M N O P Q -- 7 6 -- K M N O P Q
# Test case : entire branch is deleted instead of single node only # # Copyright (C) Karl Kästner - Berlin, Germany # Sun Apr 5 07:24:11 MSD 2009 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. use strict; use Tree::Binary::Search; my @nodes = ( [ "L", "K", "P", "Q" ] ,[ "L", "K", "P", "N", "Q" ] ,[ "L", "K", "P", "N", "M", "Q" ] ,[ "L", "K", "P", "N", "O", "Q" ] ,[ "L", "K", "P", "N", "M", "O", "Q" ] ); foreach ( @nodes ) { test( "L", @{$_} ); } sub test { my @nodes = @_; my $delNode = shift(@nodes); my $tree = Tree::Binary::Search->new(); $tree->useStringComparison(); foreach ( @nodes ) { $tree->insert($_, $_); } warn "search order inconsistent\n" if verify(Tree::Binary::Search::getTree($tree)); my $size_1 = $tree->size(); $tree->delete($delNode); my $size_2 = $tree->size(); print "\t-- ".$size_1." ".$size_2." --\t"; warn "Number of elements incorrect\n" if ($size_2 + 1 != $size_1); warn "search order inconsistent\n" if verify(Tree::Binary::Search::getTree($tree)); print "\n"; #_print(Tree::Binary::Search::getTree($tree)); } # test sub verify { my $tree = shift; my @value = _verify( $tree ); my $retval = 0; while ( @value >= 2 ) { if ( ( @value[0] cmp @value[1] ) > 0) { $retval = -1; } print shift(@value)." "; } print shift(@value); return $retval; } # verify sub _verify { my $self = shift; if (defined $self) { my $value = $self->getNodeValue(); _verify($self->getLeft); print $value." "; _verify($self->getRight); } } # _verify sub _print { my $self = shift; # rekursiv linken und rechten Ast ausgeben print " ( "; if (defined $self) { my $value = $self->getNodeValue(); print $value; _print($self->getLeft); _print($self->getRight); } print " ) "; }
*** /usr/lib/perl5/site_perl/5.10.0/Tree/Binary/Search.pm 2005-05-27 01:41:56.000000000 +0400 --- /home/pia/wissensbaum//Search.pm 2009-04-05 17:02:43.000000000 +0400 *************** *** 394,425 **** return TRUE; } else { ! # we need to find the inorder successor ! my $inorder_successor; ! my $current_right = $right; ! while (1) { ! # on the first pass, we can safely do ! # this since we know that right has a ! # left (see above 'if' statement) ! $inorder_successor = $current_right->getLeft(); ! # however, if we dont have a left on ! # subsequent rounds, then we need to ... ! unless ($inorder_successor) { ! # ... back up a bit, and get the parent ! # of the current right node and get ! # the inorder successor of that node ! $current_right = $current_right->getParent(); ! $inorder_successor = $current_right->getLeft(); ! last; ! } ! # we leave this loop if we are leftmost ! last if $inorder_successor->hasRight(); ! # otherwise, we keep moving down $current_right = $inorder_successor; ! } ! # print STDERR ">>> right: " . $right->getNodeValue() . "\n"; ! # print STDERR ">>> current right: " . $current_right->getNodeValue() . "\n"; ! # print STDERR ">>> inorder successor: " . $inorder_successor->getNodeValue() . "\n"; # now that are here, we can adjust the tree if ($inorder_successor->hasRight()) { $current_right->setLeft($inorder_successor->getRight()); --- 394,408 ---- return TRUE; } else { ! # go to the leftmost node in the right subtree ! my $inorder_successor = $right; ! my $current_right; ! ! do { $current_right = $inorder_successor; ! $inorder_successor = $inorder_successor->getLeft(); ! } while ( $inorder_successor->hasLeft() ); ! # now that are here, we can adjust the tree if ($inorder_successor->hasRight()) { $current_right->setLeft($inorder_successor->getRight());
Hi Karl Fixed in V 1.00. Many thanx for your patch and test programs. Cheers Ron Savage (New co-maintainer)