12月 31st, 2008真·非递归实现二叉树的删除操作
××××××××特别声明×××××××
本文含有大量技术细节,请无技术背景者在专业人员指导下阅读本文。
同时,请对代码不适者不要继续阅读。
××××××××××××××××××××
呃……话说昨天那个很傻的代码不但效率低下,还有一个逻辑错误……唉,不得不说,CLRS的代码实在是太精辟了,完全就是经典级别的(这不是废话么……)。刚才的代码,完全就是CLRS伪代码的具体实现过程……不知道回头我看完了TAOCP以后,会不会也有这种高山仰止的感觉。
先说一下,昨天的两个问题,一个是,堆栈的存在毫无必要,因为,我们需要的父节点只有一个,就是需要移除的Y的父节点,而那个堆栈记录了全部的路径信息,太浪费。同时,我昨天抄CLRS的时候,抄的不认真,导致了一个bug,就是要删除的根节点,我那个会无论根节点是否有孩子,都直接返回一个空节点……
好,先代码再解释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #include <stdlib.h> #include <stdio.h> typedef struct tREE{ int data; struct tREE* left; struct tREE* right; }Tree; Tree* delete(Tree *root, int data) { Tree *z=NULL; Tree *y=NULL; Tree *x=NULL; Tree *p=NULL; if (root==NULL) { printf("EMPTY TREE\n"); return NULL; } z=root; while (z!=NULL) { if (z->data==data) break; p=z; if (z->data>data) z=z->left; else z=z->right; } if (z==NULL) { printf ("NO SUCH ELEMENT\n"); return root; } else { if (z->left==NULL || z->right==NULL) y=z; else { p=z; y=z->right; while (y->left!=NULL) { p=y; y=y->left; } } if (y->left==NULL) x=y->right; else x=y->left; if (y!=z) z->data=y->data; free (y); if (p==NULL) return x; if (y==p->left) p->left=x; else p->right=x; return root; } } |
再贴一段CLRS的伪代码
TREE-DELETE(T, z) 1 if left[z] = NIL or right[z] = NIL 2 then y ← z 3 else y ← TREE-SUCCESSOR(z) 4 if left[y] ≠ NIL 5 then x ← left[y] 6 else x ← right[y] 7 if x ≠ NIL 8 then p[x] ← p[y] 9 if p[y] = NIL 10 then root[T] ← x 11 else if y = left[p[y]] 12 then left[p[y]] ← x 13 else right[p[y]] ← x 14 if y ≠ z 15 then key[z] ← key[y] 16 copy y's satellite data into z 17 return y
伪代码解释在这里
In lines 1-3, the algorithm determines a node y to splice out. The node y is either the input node z (if z has at most 1 child) or the successor of z (if z has two children). Then, in lines 4-6, x is set to the non-NIL child of y, or to NIL if y has no children. The node y is spliced out in lines 7-13 by modifying pointers in p[y] and x. Splicing out y is somewhat complicated by the need for proper handling of the boundary conditions, which occur when x = NIL or when y is the root. Finally, in lines 14-16, if the successor of z was the node spliced out, y’s key and satellite data are moved to z, overwriting the previous key and satellite data. The node y is returned in line 17 so that the calling procedure can recycle it via the free list. The procedure runs in O(h) time on a tree of height h.
——Introduction to Algorithms,12.3 Insertion and deletion
接下来是我的代码简单说明,
10-17,定义变量,名称抄袭自CLRS,p用来标记y的父节点
19-23,空树,返回
27-36,定位z
38-42,要删除的元素不存在
46-57,对应CLRS伪代码的1-3行
59-62,对应4-6行
64-65,对应14-16行
67,偷偷提前释放了空间
= =#
这样貌似不是常规操作方式,不知道有没有问题。
69-70,对应9-10行
72-75,对应11-13行
77返回。
特别强调下,CLRS的伪代码里的7,8两行我这里没有相对应的代码,因为,我的数据结构里没有父节点。
