基于树的查找
Posted tianzeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于树的查找相关的知识,希望对你有一定的参考价值。
二叉排序树
二叉排序树或者是一颗空树
若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
若它的右子树不空,则右子树上所有节点的值均大于其根节点的值。
左右子树分别为二叉排序树
存储结构:
typedef struct node { int key;//关键字的值 struct node *lchild,*rchild;//左右指针 }BSTNode,*BSTree;
二叉排序树插入
算法思想:
- 若二叉排序树是空树,则key成为二叉排序树的根
- 若二叉排序树是非空空树,则key与二叉排序树的根比较
a.若果key的值等于根节点的值停止插入
b.如果key的值小于根节点的值,则将key插入左子树
c.如果key的值大于根节点的值,则将key插入右子树
//二叉排序树的插入递归算法 void InsertBST(BSTree &bst,int key) { BSTree s; if(bst==NULL)//递归结束,也就是找到了叶子结点,申请内存,为此叶子结点插入新元素 { s=(BSTree)malloc(sizeof(BSTNode)); s->key=key; s->lchild=s->rchild=NULL; bst=s; } else if(key<bst->key)//key的值小于根结点的值,插入左子树 InsertBST(bst->lchild,key); else if(key>bst->key)//key的值小于根结点的值,插入右子树 InsertBST(bst->rchild,key); }
二叉排序树创建
算法思想:
首先将二叉排序树初始化为一棵空树,然后逐个读入元素,读入每一个元素就建立一个新的结点,并插入到当前已经生成的二叉排序树中,插入时比较始终是从二叉排序树的根开始的
//创建二叉排序树 void CreateBST(BSTree &bst) { int key; bst=NULL; scanf("%d",&key); while(key!=0)//输入零结束插入 { InsertBST(bst,key); scanf("%d",&key); } }
二叉排序树查找
算法思想:
将关键字key的值与根结点的值比较
- key==t,返回跟节点的地址
- key<t,进一步查找左子树
- key>t,进一步查找右子树
//二叉排序树的查找---递归,查找成功返回该元素的指针,否则返回NULL BSTree SearchBST(BSTree bst,int key) { if(!bst) return NULL; else if(bst->key==key) return bst; else if(bst->key<key) return SearchBST(bst->rchild,key); else return SearchBST(bst->lchild,key); }
//二叉排序树的查找---非递归,查找成功返回该元素的指针,否则返回NULL BSTree _SearchBST(BSTree bst,int key) { BSTree t=bst; while(t) { if(t->key==key) return t; else if(t->key>key) t=t->lchild; else t=t->rchild; } return NULL; }
二叉树中找出查找最大最小元素是极简单的事情,从根节点一直往左走,直到无路可走就可得到最小值;从根节点一直往右走,直到无路可走,就可以得到最大值
//查找最小的元素 BSTree SearchMin(BSTree bst) { if(!bst) return NULL; if(bst->lchild==NULL) return bst; else SearchMin(bst->lchild); } //查找最大的元素 BSTree SearchMax(BSTree bst) { if(!bst) return NULL; if(bst->rchild==NULL) return bst; else SearchMax(bst->rchild); }
二叉排序树删除
算法思想:
方法一:
- 若p为叶子结点,则可以将其直接删除f->lchild=NULL,free(p);
- 若p结点只有左子树或右子树,将p的左子树或右子树直接改为双亲的左子树,f-lchild=p-lchild or f->lchild=p->rchild;
- 既有左子树又有右子树
a.找到p结点在中序序列中的直接前序s,然后将p的左子树改为f的左子树,p右子树改为s的右子树
b.找到p结点在中序序列中的直接前序s,用s结点的值代替p结点的值,再将s删除,原s结点的左子树改为s的双亲结点q的右子树。
a方法的代码实例如下
BSTree DelBST(BSTree bst,int key) { BSTree p=bst,f=NULL; while(p) { if(p->key==key)//找到跳出循环,p指向要删除的结点 break; f=p;//f指向p的双亲 if(p->key>key) p=p->lchild; else p=p->rchild; } if(p==NULL)//查找失败 return NULL; if(p->lchild==NULL)//p无左子树 { if(f==NULL)//p是原来二叉排序树的根 bst=p->rchild; else if(f->lchild==p) //p是f的左孩子 f->lchild=p->rchild; else//p是f的右孩子 f->rchild=p->rchild; free(p) ; } else//p有左子树 { BSTree q=p,s=p->lchild; while(s->rchild)//p的左子树中找最右下的结点 { q=s; s=s->rchild; } if(q==p) q->lchild=s->lchild;//将s的左子树连接到q上 else q->rchild=s->lchild; p->key=s->key; free(s) ; } return bst; }
方法二:
对于二叉排序树中的节点A,对它的删除分为两种情况:
1、如果A只有一个子节点,就直接将A的子节点连至A的父节点上,并将A删除
2、如果A有两个子节点,我们就以右子树内的最小节点取代A
BSTree DelBST(BSTree &bst,int key) { BSTree p=bst,parent=NULL,s=NULL;//bst是要删除的结点 if(!p) return NULL; if(p->key==key) { if(!p->lchild&&!p->rchild)//叶子结点 bst=NULL; else if(p->lchild&&!p->rchild)//只有左结点 bst=p->lchild; else if(p->rchild&&!p->lchild) //只有右结点 bst=p->rchild; else { s=p->rchild;//找右子树中最小的结点来代替要删除的结点 if(!s->lchild)//s无左结点 s->lchild=p->lchild;//用s的左结点代替p的左结点,然后直接用s直接代替bst else//s有左孩子 { while(s->lchild) { parent=s;//parent是s的双亲结点 s=s->lchild; } parent->lchild=s->rchild;//因为要用s代替parent,所以要保存下s的左结点的值 s->lchild=p->lchild;//s的左结点的值代替p左结点的值 s->rchild=p->rchild;//s右结点的值代替p右结点的值 } bst=s;//s代替p的值 } } else if(p->key<key) DelBST(p->rchild,key); else if(p->key>key) DelBST(p->lchild,key); }
完整代码:
#include <stdio.h> #include <stdlib.h> typedef struct node { int key;//关键字的值 struct node *lchild,*rchild;//左右指针 }BSTNode,*BSTree; //二叉排序树的插入递归算法 void InsertBST(BSTree &bst,int key) { BSTree s; if(bst==NULL)//递归结束,也就是找到了叶子结点,申请内存,为此叶子结点插入新元素 { s=(BSTree)malloc(sizeof(BSTNode)); s->key=key; s->lchild=s->rchild=NULL; bst=s; } else if(key<bst->key)//key的值小于根结点的值,插入左子树 InsertBST(bst->lchild,key); else if(key>bst->key)//key的值小于根结点的值,插入右子树 InsertBST(bst->rchild,key); } //创建二叉排序树 void CreateBST(BSTree &bst) { int key; bst=NULL; scanf("%d",&key); while(key!=0)//输入零结束插入 { InsertBST(bst,key); scanf("%d",&key); } } //二叉排序树的查找---递归,查找成功返回该元素的指针,否则返回NULL BSTree SearchBST(BSTree bst,int key) { if(!bst) return NULL; else if(bst->key==key) return bst; else if(bst->key<key) return SearchBST(bst->rchild,key); else return SearchBST(bst->lchild,key); } //二叉排序树的查找---非递归,查找成功返回该元素的指针,否则返回NULL BSTree _SearchBST(BSTree bst,int key) { BSTree t=bst; while(t) { if(t->key==key) return t; else if(t->key>key) t=t->lchild; else t=t->rchild; } return NULL; } //查找最小的元素 BSTree SearchMin(BSTree bst) { if(!bst) return NULL; if(bst->lchild==NULL) return bst; else SearchMin(bst->lchild); } //查找最大的元素 BSTree SearchMax(BSTree bst) { if(!bst) return NULL; if(bst->rchild==NULL) return bst; else SearchMax(bst->rchild); } //删除结点 BSTree DelBST(BSTree &bst,int key) { BSTree p=bst,parent=NULL,s=NULL;//bst是要删除的结点 if(!p) return NULL; if(p->key==key) { if(!p->lchild&&!p->rchild)//叶子结点 bst=NULL; else if(p->lchild&&!p->rchild)//只有左结点 bst=p->lchild; else if(p->rchild&&!p->lchild) //只有右结点 bst=p->rchild; else { s=p->rchild;//找右子树中最小的结点来代替要删除的结点 if(!s->lchild)//s无左结点 s->lchild=p->lchild;//用s的左结点代替p的左结点,然后直接用s直接代替bst else//s有左孩子 { while(s->lchild) { parent=s;//parent是s的双亲结点 s=s->lchild; } parent->lchild=s->rchild;//因为要用s代替parent,所以要保存下s的左结点的值 s->lchild=p->lchild;//s的左结点的值代替p左结点的值 s->rchild=p->rchild;//s右结点的值代替p右结点的值 } bst=s;//s代替p的值 } } else if(p->key<key) DelBST(p->rchild,key); else if(p->key>key) DelBST(p->lchild,key); } //中序遍历二叉树 void InorderSearch(BSTree bst) { if(bst) { InorderSearch(bst->lchild); printf("%d ",bst->key); InorderSearch(bst->rchild); } } int main() { BSTree bst; CreateBST(bst); int key; printf("删除元素之前---请输入要查找的元素:"); scanf("%d",&key); BSTree temp=SearchBST(bst,key); if(temp) printf("(递归)查找成功,查找的元素是:%d ",temp->key); else printf("查找失败. "); BSTree temp1=_SearchBST(bst,key) ; if(temp1) printf("(非递归)查找成功,查找的元素是:%d ",temp1->key); else printf("查找失败. "); BSTree temp2=SearchMin(bst); if(temp2) printf("最小的元素是:%d ",temp2->key); else printf("最小的元素查找失败. "); BSTree temp3=SearchMax(bst); if(temp3) printf("最大的元素是:%d ",temp3->key); else printf("最大的元素查找失败. "); printf("请输入要删除的值:"); scanf("%d",&key); temp3=DelBST(bst,key); printf("中序遍历二叉树: "); InorderSearch(bst); printf(" "); return 0; }
以上是关于基于树的查找的主要内容,如果未能解决你的问题,请参考以下文章