近几天来研究伸展树,但一直都没有进展,想既然伸展树是一棵二叉查找树,那么先把二叉查找树的各种操作弄清楚了,再来研究伸展树也许会有突破!
二叉查找树是一种在log复杂度内实现快速查找元素的一种数据结构。其改进的树有红黑树,AVL树,平衡二叉树,节点大小平衡树,伸展树。
同其它数据结构一下,二叉查找树的操作有 查插删改 四种。我个人觉得,二叉查找树的删除是最难的,需要考虑的因素比较多,但毕竟还是可以实现出来的。这里呢,我主要把我自己实现删除操作的思路整理出来,供大家参考。
首先要说明的,一般的二叉查找树是不允许元素重复的,这里我稍微改动了一下,允许元素的重复。
删除元素步骤如下:
第一步:找到要删除元素的结点(*cur)及其父节点(*parent)。
第二步:删除元素,删除元素分以下几种情况;
如果cur的值在树中有多个,则只删除一个,返回。
如果cur是叶子节点,则直接删除,并把其parent指向cur的指针置为空。
如果cur只有一个孩子,则把parent原来指向cur的指针指向cur的孩子。
如果cur有两个孩子(我们称之为左子树和右子树),则把其左子树接到右子树的最左边的叶子结点上,然后把parent原来指向cur的指针指向cur的右子树。
第三步:delete cur.
这样的话,就实现了二叉查找树的删除操作。
我们知道,如果把二叉树中序遍历,则是让它从小到大的输出,那么怎么使其从大到小的输出呢?把遍历的顺序变一下就可以了,先输出右子树,再输出当前结点,最后输出左子树。我把这个操作定义为:变异的中序遍历(variation_inorder_traversal)。
其查找和更新操作就很简单了,这里就把代码贴出来吧!
- /*
- * BinarySearchTree.cpp
- *
- * Created on: 2012-9-15
- * Author: Administrator
- */
- #include<stdio.h>
- #include<string.h>
- struct Node{
- int value;
- int count;
- Node *left,*right;
- Node(){
- count=1;
- left=NULL;right=NULL;
- }
- };
- bool insert(Node **cur,int value){
- if((*cur)!=NULL){
- if((*cur)->value>value){
- return insert(&((*cur)->left),value);
- }else if((*cur)->value<value){
- return insert(&((*cur)->right),value);
- }else{
- printf("the element %d has been in the tree\n",value);
- (*cur)->count+=1;
- return false;
- }
- }else{
- Node *p=new Node();
- p->value=value;
- *cur=p;
- return true;
- }
- }
- //从树中查找某个元素
- Node* search(Node *cur,const int &value){
- if(cur->value==value){//如果找到了怎么办
- return cur;
- }else if(cur->value>value&&cur->left!=NULL){
- return search(cur->left,value);
- }else if(cur->value<value&&cur->right!=NULL){
- return search(cur->right,value);
- }else{
- printf("No Element!\n");
- return NULL;
- }
- }
- //从树中删除指定值的元素
- void deleteElement(Node **root,const int &value){
- if(*root==NULL){
- printf("the tree is empty!\n");
- return;
- }
- //找到要删除的结点,及父结点
- Node *parent,*cur;
- parent=cur=(*root);
- bool find=false;
- while(cur&&!find){
- if(cur->value==value){
- find=true;
- }else if(value>cur->value){
- parent=cur;
- cur=cur->right;
- }else{
- parent=cur;
- cur=cur->left;
- }
- }
- if(!find){
- printf("can not find the element %d!\n",value);
- return ;
- }
- //如果有多个元素,只删除一个
- if(cur->count>1){
- cur->count-=1;
- return ;
- }
- //如果是叶子结点,直接删除
- if(cur->left==NULL&&cur->right==NULL){
- if(parent==cur){//如果是根结点
- (*root)=NULL;
- }else if(parent->left==cur){//是左孩子
- parent->left=NULL;
- }else if(parent->right==cur){//是右孩子
- parent->right=NULL;
- }
- }else if(cur->right!=NULL){//树只有右孩子
- if(parent==cur){//如果是根结点
- (*root)=cur->right;
- }else if(parent->left==cur){//是左孩子
- parent->left=cur->right;
- }else if(parent->right==cur){//是右孩子
- parent->right=cur->right;
- }
- }else if(cur->left!=NULL){//树只有左孩子
- if(parent==cur){//如果是根结点
- (*root)=cur->left;
- }else if(parent->left==cur){//是左孩子
- parent->left=cur->left;
- }else if(parent->right==cur){//是右孩子
- parent->right=cur->left;
- }
- }else{//两个孩子都在:把左子树的根结点,接到右子树最左边的叶子结点
- Node *leaf;
- leaf=cur->right;
- while(leaf->left!=NULL){
- leaf=leaf->left;
- }
- leaf->left=cur->left;
- if(parent==cur){//如果是根结点
- (*root)=cur->right;
- }else if(parent->left==cur){//是左孩子
- parent->left=cur->right;
- }else if(parent->right==cur){//是右孩子
- parent->right=cur->right;
- }
- }
- delete cur;
- printf("delete %d success!\n",value);
- }
- //中序输出二叉查找树:这其实也相当与排序了:将二叉树按元素的大小 ,从小到大输出
- void inorder_traversal(Node *cur){
- if(cur==NULL)return ;
- inorder_traversal(cur->left);
- for(int i=0;i<cur->count;i++)
- printf("%d ",cur->value);
- inorder_traversal(cur->right);
- }
- //我将其定义为变异的中序输出:将二叉树按元素的大小 ,从大到小输出
- void variation_inorder_traversal(Node *cur){
- if(cur==NULL)return ;
- variation_inorder_traversal(cur->right);
- for(int i=0;i<cur->count;i++)
- printf("%d ",cur->value);
- variation_inorder_traversal(cur->left);
- }
- //程序运行完,回收内存
- void recycle(Node **cur,Node **parent){
- if((*cur)==NULL)return;
- recycle(&((*cur)->left),cur);
- recycle(&((*cur)->right),cur);
- if(((*cur)->left)==NULL&&((*cur)->right)==NULL){
- if((*parent)!=NULL){
- if(((*parent)->left)==(*cur))
- (*parent)->left=NULL;
- else (*parent)->right=NULL;
- }
- delete (*cur);
- (*cur)=NULL;
- }
- }
- int main(){
- int a[8]={0,4,6,23,567,34,8566,4};
- Node *root;
- root=NULL;
- for(int i=0;i<8;i++){
- insert(&root,a[i]);
- }
- printf("root=%d\n",root->value);
- printf("\nascending order: ");
- inorder_traversal(root);puts("");
- printf("descending order: ");
- variation_inorder_traversal(root);puts("");
- // Node *p;
- // p=search(root,9);
- // if(p)printf("%d",p->value);
- // else printf("No data");
- deleteElement(&root,7);
- deleteElement(&root,2);
- // deleteElement(&root,1);
- // deleteElement(&root,4);
- // deleteElement(&root,3);
- // deleteElement(&root,3);
- printf("after deleted,the left elements are: ");
- inorder_traversal(root);puts("");
- Node *q=NULL;recycle(&root,&q);
- if(root==NULL)printf("after recycle the root points NULL");//结点正常回收后,应输出NULL
- }
参考文档:
http://www.cnblogs.com/aiyelinglong/archive/2012/03/27/2419972.html