在上一篇文章中用函数方式实现了一个二叉树,本篇用闭包模拟类的方式来重新实现,不同于传统意义的Perl 类,否则也不用去费力重新实现,本篇用闭包来模拟类的一些行为,以消息传递的方式调用方法。
1。 模拟类行为,开放类方法
3。 消息类型多样,自己可以随便控制
特点:
1。 每次取得一个节点(增加,删除,修改)都是一个闭包Node 的返回,可以看作对应的类实例,可通过进一步调用来获取相应的值
2。 只有两个模拟类,Node and BNSTree,通篇都是通过这两个闭包类来进行操作
附代码以及编写过程中的一些注释:
use strict; use warnings; use Data::Dumper; sub Node { my $_node = { left => undef,right => undef,key => undef,parent => undef }; # set multiple value at same time my %params = @_; map { $_node->{$_} = $params{$_} if defined $params{$_} } keys %$_node; # set or get value for each item return sub { my ( $msg,$value ) = @_; if ( exists $_node->{$msg} ) { defined $value ? $_node->{$msg} = $value : $_node->{$msg}; } # because cannot set one of attribute of _node to undef,so add one method delete to set to undef elsif ( $msg eq 'delete' && $value ) { $_node->{$value} = undef; } else { die "Undefined key: $msg"; } } } sub BNSTree { my $root = undef; my $empty = sub { return !$root; }; #this is original version for insert,logic is clear but code is too much my $insert_old = sub { my ($value) = @_; if ( $empty->() ) { my $node = Node( key => $value ); return $root = $node; } my $tmp = $root; while ( $value != $tmp->('key') ) { if ( $value < $tmp->('key') && $tmp->('left') ) { $tmp = $tmp->('left'); } elsif ( $value > $tmp->('key') && $tmp->('right') ) { $tmp = $tmp->('right'); } else { last; } } if ( $value < $tmp->('key') ) { my $node = Node( key => $value,parent => $tmp ); return $tmp->( left => $node ); } elsif ( $value > $tmp->('key') ) { my $node = Node( key => $value,parent => $tmp ); return $tmp->( right => $node ); } else { return $tmp; } }; #this is optimized version for insert,almost 1/2 less code than prevIoUs and tight my $insert = sub { my ($value) = @_; return $root = Node( key => $value ) if $empty->(); my $tmp = $root; while ( $value != $tmp->('key') ) { if ( $value < $tmp->('key') ) { $tmp->('left') ? $tmp = $tmp->('left') : return $tmp->( left => Node( key => $value,parent => $tmp ) ); } elsif ( $value > $tmp->('key') ) { $tmp->('right') ? $tmp = $tmp->('right') : return $tmp->( right => Node( key => $value,parent => $tmp ) ); } #~ else{ last; } } return $tmp; }; my $min_max = sub { #~ my ($msg) = @_; #~ return if $empty->(); #~ my $tmp = $root; #~ while($tmp->($msg)){ #~ $tmp = $tmp->($msg); #~ } #~ return $tmp; #prevIoUs version work for the whole tree,but successor need it,so modify it that can be used by sub-tree min max my ( $msg,$tmp_root ) = @_; return if !$tmp_root; while ( $tmp_root->($msg) ) { $tmp_root = $tmp_root->($msg); } return $tmp_root; }; my $search = sub { my ($value) = @_; return if $empty->(); my $tmp = $root; while ( $value != $tmp->('key') ) { if ( $value < $tmp->('key') ) { $tmp->('left') ? $tmp = $tmp->('left') : return; } elsif ( $value > $tmp->('key') ) { $tmp->('right') ? $tmp = $tmp->('right') : return; } else { last; } } return $tmp; }; my $successor = sub { my ($value) = @_; #~ return undef if $empty->(); my $search_item = $search->($value); return if !$search_item; if ( $search_item->('right') ) { #~ my $tmp = $search_item->('right'); #~ while($tmp->('left')){ #~ $tmp = $tmp->('left'); #~ } #~ return $tmp; # prevIoUs version need expend min function,so modify it use subtree min return $min_max->( 'left',$search_item->('right') ); } my $tmp = $search_item; while ($tmp->('parent') && $tmp->('parent')->('right') && $tmp->('parent')->('right') == $tmp ) { $tmp = $tmp->('parent'); } return $tmp->('parent'); }; my $predecessor = sub { my ($value) = @_; #~ return undef if $empty->(); my $search_item = $search->($value); return undef if !$search_item; if ( $search_item->('left') ) { #~ my $tmp = $search_item->('right'); #~ while($tmp->('left')){ #~ $tmp = $tmp->('left'); #~ } #~ return $tmp; # prevIoUs version need expend min function,so modify it use subtree min return $min_max->( 'right',$search_item->('left') ); } my $tmp = $search_item; while ($tmp->('parent') && $tmp->('parent')->('left') && $tmp->('parent')->('left') == $tmp ) { $tmp = $tmp->('parent'); } return $tmp->('parent'); }; #go through from upper level to lower level my $level_order = sub { return if $empty->(); #~ my $tmp = $root; my @stack = ($root); while (@stack) { my $tmp = shift @stack; print $tmp->('key'),' '; push @stack,$tmp->('left') if $tmp->('left'); push @stack,$tmp->('right') if $tmp->('right'); } }; my $in_order = sub { return if $empty->(); my $tmp = $root; my @stack = (); while ( $tmp || @stack ) { if ($tmp) { print $tmp->('key'),' '; push @stack,$tmp; $tmp = $tmp->('left'); } else { $tmp = pop @stack; #~ print $tmp->('key'),' '; $tmp = $tmp->('right'); } } }; my $pre_order = sub { return if $empty->(); my $tmp = $root; my @stack = (); while ( $tmp || @stack ) { if ($tmp) { push @stack,$tmp; $tmp = $tmp->('left'); } else { $tmp = pop @stack; print $tmp->('key'),' '; $tmp = $tmp->('right'); } } }; my $suc_order = sub { return if $empty->(); my $tmp = $root; my @stack = (); while ( $tmp || @stack ) { if ($tmp) { push @stack,$tmp; $tmp = $tmp->('right'); } else { $tmp = pop @stack; print $tmp->('key'),' '; $tmp = $tmp->('left'); } } }; my $internal_delete = sub { my ($node) = @_; if ( $node->('parent') ) { my $pchild = $node->('parent')->('key') > $node->('key') ? 'left' : 'right'; if ( !$node->('left') && !$node->('right') ) { $node->('parent')->( delete => $pchild ); } elsif ( !$node->('left') || !$node->('right') ) { my $child = $node->('left') ? 'left' : 'right'; $node->('parent')->( $pchild => $node->($child) ); $node->($child)->( parent => $node->('parent') ); } } else { if ( !$node->('left') && !$node->('right') ) { $root = undef; } elsif ( !$node->('left') || !$node->('right') ) { my $child = $node->('left') ? 'left' : 'right'; $root = $node->($child); $node->($child)->( delete => 'parent' ); } } }; my $delete = sub { my ($value) = @_; my $tmp = $search->($value); if ( !$tmp ) { return; } elsif ( !$tmp->('left') || !$tmp->('right') ) { $internal_delete->($tmp); } else { my $suc = $successor->($value); $internal_delete->($suc); $tmp->( 'key',$suc->('key') ); } }; #initial binary search tree with more values for (@_) { $insert->($_); } return sub { my ( $msg,$value ) = @_; if ( $msg eq 'empty' ) { $empty->(); } elsif ( $msg eq 'insert' ) { $insert->($value); } elsif ( $msg eq 'min' ) { $min_max->( 'left',$root ); } elsif ( $msg eq 'max' ) { $min_max->( 'right',$root ); } elsif ( $msg eq 'search' ) { $search->($value); } elsif ( $msg eq 'successor' ) { $successor->($value); } elsif ( $msg eq 'predecessor' ) { $predecessor->($value); } elsif ( $msg eq 'print' && $value && $value eq 'pre' ) { $pre_order->(); } elsif ( $msg eq 'print' && $value && $value eq 'suc' ) { $suc_order->(); } elsif ( $msg eq 'print' ) { $in_order->(); } elsif ( $msg eq 'delete' ) { $delete->($value); } } } my $a = BNSTree(qw(14 20 18 21 7 )); $a->( 'delete',14 ); $a->( parent => undef ); $a->('print'); print "\n"; $a->( 'print','pre' ); print "\n"; $a->( 'print','suc' ); print "\n";
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。