下面的代码实现了:建立AVL树,在树中查找节点,册除节点,先序遍历,中序遍历,后序遍历。
创立方法:先把n个数从小到大排序,然后用了二分法建立 平衡二叉树(AVL);
册除方法:找到要册除节点的右子树中最小的一个节点,把要册除的节点值换成找到的那个节点值,然后把找到的这个最小节点的父节点的左子树变成最小节点的右子树,最后释放这个最小节点。
1.3BST删除元素的算法实现
删除总共有3种情况,1只有左子树;2,只有右子树;3,左右子树都有。
先看第一种
如上图所示 我们要删除4这个节点,我们就把他双亲节点的左孩子指向4的左子树。简单吧!。那我么看第二种吧
如上图所示我们所要删除的7节点只有右子树,想必一定想到了,那我们就把他双亲节点的右孩子指向7节点的右孩子,那不就ok啦,太棒了!!。现在看第三种情况吧。
大家看出这三幅图的变化了吗?我们所要删除节点4,为了要保持树的顺序我们就要找比4大的且要离4最近的,那就是他的后继,当然你找前继也是可以的。此图是找他的后继。我们找到后就用4的后继替换4,最后删除后继这个节点。
如果不信的话可以用先序遍历或后序遍历来验证正确性。
#include<stdio.h> #include<iostream> #include<malloc.h> #include<algorithm> using namespace std; typedef struct nn { int w; struct nn *lchilde,*rchilde; }tree,*Tree; int a[10000]; int cmp(int aa,int bb)//从小到大排 { return aa<bb; } void set_up(int l,int mid,int r,Tree &root)//建立平衡二叉树,左子树的所有值都小于根节点,右子树都大于根节点,l,mid,r的表示在a[]中的位置 { Tree node; if(mid==l) { root=NULL; return ; } node=(Tree)malloc(sizeof(tree));//创建一个节点 node->w=a[mid]; //当前节点的值 set_up(l,(mid+l)/2,mid,node->lchilde);//建立当前节点的左子树 set_up(mid,(mid+r)/2,r,node->rchilde);//建立当前节点的右子树 root=node; } Tree find(Tree node,int x)//查找x是不是在这棵树上,如果在反回这个节点,否则反回空 { if(node->w==x||node==NULL) return node; if(node->w>x) return find(node->lchilde,x); return find(node->rchilde,x); } int find_min_right(Tree &pre_root,Tree now_root)//用于查找册除的节点的右子树中最小的值 { if(now_root->lchilde!=NULL) { return find_min_right(now_root,now_root->lchilde); } else { int w; pre_root->lchilde=now_root->rchilde;//把最小节点的父节点的左子树指向最小节点的右子树 w=now_root->w; free(now_root);//释放册除的节点的右子树中最小节点 return w; //反回册除的节点的右子树中最小节点的值 } } int Delete_node(Tree &root,int x)//册除节点x,成功反回1,否则反回0 { if(root==NULL)//反回0说明树中没有x的这个节点 return 0; if(root->w!=x) { if(root->w>x)return Delete_node(root->lchilde,x); if(root->w<x)return Delete_node(root->rchilde,x); } else//当在树中找到x这个节点 { if(root->rchilde!=NULL&&root->rchilde->lchilde==NULL)//当x节点的右子树不空并且x节点右子树的左子树为空时, { //那么x节点一定是在倒数第二层(AVL树的特性(左右子树深度差的绝对值不超过1)) root->w=root->rchilde->w;//就直接把x节点的值变成右子树值 root->rchilde=NULL;//空是不需要占用内存空间的,所以下面可以释放 free(root->rchilde); return 1; } if(root->rchilde!=NULL)//当x节点不在倒数第一,二层时 root->w=find_min_right(root,root->rchilde); else //当x节点在倒数第一层时 root=NULL; return 1; } } void printTree_one(Tree root)//以先序遍历输出 { if(root==NULL) return ; printf("%d ",root->w); printTree_one(root->lchilde); printTree_one(root->rchilde); } void printTree_tow(Tree root)//以中序遍历输出 { if(root==NULL) return ; printTree_tow(root->lchilde); printf("%d ",root->w); printTree_tow(root->rchilde); } void printTree_three(Tree root)//以后序遍历输出 { if(root==NULL) return ; printTree_three(root->lchilde); printTree_three(root->rchilde); printf("%d ",root->w); } int main() { int n,mid,l,r; Tree root; while(scanf("%d",&n)>0) { for(int i=1;i<=n;i++)//输入n个数 scanf("%d",&a[i]); sort(a,a+n+1,cmp);//把n个数先按小到大排序 r=n+1; l=0; mid=(r+l)/2; root=(Tree)malloc(sizeof(tree));//创建根节点 root->w=a[mid]; set_up(l,(mid+l)/2,mid,root->lchilde);//建立根节点的左子树 set_up(mid,(mid+r)/2,r,root->rchilde);//建立根节点的右子树 printf("AVL树建好后 以先序遍历输出:"); printTree_one(root);//先序遍历输出 printf("\n"); Delete_node(root,a[4]); printf("册掉第4小节点 先序遍历输出:"); printTree_one(root);//先序遍历输出 printf("\n"); /* printTree_tow(root);//中序遍历输出 printf("\n"); printTree_three(root);//后序遍历输出 printf("\n"); */ } }