数据结构查找(1)--二叉查找树
2012-12-15 21:57
302 查看
准备在期末之前解决掉红黑树。为了解决红黑树,首先学习二叉查找树,然后学习平衡的二叉查找树(这里的关键是树的旋转操作)。
最后在已经有上面知识的基础上,再来解决红黑树。至于B树家族,实在是太复杂,自己先了解下。等到自己实力增强的时候再去深入。
首先我们来看看二叉查找树:
下面是二叉查找树的定义:
二叉排序树或者是一棵空树;或者是具有如下特性的二叉树:
(1)若它的左子树不空,则左子树上
所有结点的值均小于根结点的值
(2)若它的右子树不空,则右子树上
所有结点的值均大于根结点的值
(3)它的左、右子树也都分别是二叉
排序树
给出一颗二叉查找树:
我们可以看到,根节点为8。左子树的所有节点的数据都比8小,右子树的所有节点的数据都比8大。
而且子树也满足下面的规律。
二叉查找树的概念我们了解起来应该不难。
我们用二叉链表的数据结构就可以来表示二叉查找树:
下面是具体的基本算法实现。
1.查找,这里使用了递归来实现
2.插入
插入只有在查找失败的情况下面才进行。因为根据定义,二叉查找树不允许节点有相同的数据。
下面是插入算法
3.中序遍历的前驱和后继
根据算法导论来好了。
为什么这里要强调中序遍历的前驱和后继?因为在下面的删除操作中我们会用到求前驱或者是求后继的操作。
那么我们在中序遍历的前驱和后继之前,我们先写两个查找最大节点和最小节点的算法。因为我们在 进行中序遍历的前驱和后继的时候要用到。
有了这两个作为基础。现在我们来介绍下中序遍历的前驱和后继
我们以求后继作为例子:
求后继分为两种情况
1.如果结点的右子树非空,那么我们右子树的最左结点就是该节点的后继
2.如果结点的右子树为空,那么从x向上查找,直到遇到某个是其父结点的左儿子的结点为止。
下面以后继为例子,具体代码的实现。
前驱的方法与查找后继类似。具体代码如下:
4.结点的删除
结点的删除时我们要保证删除后的结点仍然符合 二叉查找树的性质。
大家可以参考下面这个博客:
http://blog.csdn.net/danielhf/article/details/81210 http://www.cnblogs.com/aiyelinglong/archive/2012/03/27/2419972.html
删除分为三种
1. 要删除的节点没有子节点, 即它是叶节点
2. 要删除的节点有一个子节点
3. 要删除的节点有两个子节点
这里有个比较巧妙地方法,我们把第1种情况和第2种情况合并起来处理
如果左子树为空,就重接右子树;如果右子树为空,就重接左子树
最难的就是第三种情况了。
通过看图,我们来理解一下。
我们要删除 z 这个节点
1.我们通过中序遍历找到z的后继为y,我们已经知道y肯定没有左子树(如果这里不明白,再回上去看看吧)
2.把y结点的值赋给z
3.我们要删除y结点 ,让y的父亲结点成为y的右子树的结点 (自己唯一不明白的就是这个地方了)
最后来看看删除代码:
最后在已经有上面知识的基础上,再来解决红黑树。至于B树家族,实在是太复杂,自己先了解下。等到自己实力增强的时候再去深入。
首先我们来看看二叉查找树:
下面是二叉查找树的定义:
二叉排序树或者是一棵空树;或者是具有如下特性的二叉树:
(1)若它的左子树不空,则左子树上
所有结点的值均小于根结点的值
(2)若它的右子树不空,则右子树上
所有结点的值均大于根结点的值
(3)它的左、右子树也都分别是二叉
排序树
给出一颗二叉查找树:
我们可以看到,根节点为8。左子树的所有节点的数据都比8小,右子树的所有节点的数据都比8大。
而且子树也满足下面的规律。
二叉查找树的概念我们了解起来应该不难。
我们用二叉链表的数据结构就可以来表示二叉查找树:
typedef struct BiTNode{ TElemType data; struct BiTNode *lchild, *rchild, *parent; }BiTNode, *BiTree;
下面是具体的基本算法实现。
1.查找,这里使用了递归来实现
Status SearchBST(BiTree T, KeyType key, BiTree f, BiTree &p) //查找成功, p指向该数据元素的结点 //查找不成功,p指向查找路径上访问的最后一个节点,f指向当前访问的结点的双亲,初始调用为NULL { if (T == NULL) { p = f; return false; } else { if (T->data == key) { p = T; return true; } else if (key < T->data) { f = T; SearchBST(T->lchild, key, f, p); } else { f = T; SearchBST(T->rchild, key, f, p); } } }
2.插入
插入只有在查找失败的情况下面才进行。因为根据定义,二叉查找树不允许节点有相同的数据。
下面是插入算法
//二叉排序树的插入算法,只有在查找不成功的时候才进行插入 Status InsertBST(BiTree &T, TElemType e) { BiTree p; BiTree s; if (!SearchBST(T, e, NULL, p)) //不存在就插入 { s = (BiTree) malloc (sizeof(BiTNode)); s->data = e; s->lchild = s->rchild = NULL; if (!p) T = s; else if (e < p->data) p->lchild = s; else p->rchild = s; return true; } else return false; }
3.中序遍历的前驱和后继
根据算法导论来好了。
为什么这里要强调中序遍历的前驱和后继?因为在下面的删除操作中我们会用到求前驱或者是求后继的操作。
那么我们在中序遍历的前驱和后继之前,我们先写两个查找最大节点和最小节点的算法。因为我们在 进行中序遍历的前驱和后继的时候要用到。
//最大关键字元素 BiTree BSTMaxmum(BiTree b) { BiTree p = b; while (p->rchild) p = p->rchild; return p; } //最小关键字元素 BiTree BSTMinmum(BiTree b) { BiTree p = b; while (p->lchild) p = p->lchild; return p; }
有了这两个作为基础。现在我们来介绍下中序遍历的前驱和后继
我们以求后继作为例子:
求后继分为两种情况
1.如果结点的右子树非空,那么我们右子树的最左结点就是该节点的后继
2.如果结点的右子树为空,那么从x向上查找,直到遇到某个是其父结点的左儿子的结点为止。
下面以后继为例子,具体代码的实现。
//查找后继 BiTree SuccessorBST(BiTree b) { BiTree p = b; //如果结点的右子树非空,那么右子树的最左结点就是该节点的后继 if (p->rchild) return BSTMinmum(p->rchild); //如果结点的右子树为空,那么从x向上查找,直到遇到某个是其父结点的左儿子的结点为止 BiTree y = p->parent; while (y != NULL & p == y->rchild) { p = y; y = y->parent; } return y; }
前驱的方法与查找后继类似。具体代码如下:
//查找前驱 BiTree PredecessorBST(BiTree b) { BiTree p = b; if (p->lchild) return BSTMaxmum(p->lchild); BiTree y = p->parent; while (y != NULL & p == y->lchild) { p = y; y = y->parent; } return y; }
4.结点的删除
结点的删除时我们要保证删除后的结点仍然符合 二叉查找树的性质。
大家可以参考下面这个博客:
http://blog.csdn.net/danielhf/article/details/81210 http://www.cnblogs.com/aiyelinglong/archive/2012/03/27/2419972.html
删除分为三种
1. 要删除的节点没有子节点, 即它是叶节点
2. 要删除的节点有一个子节点
3. 要删除的节点有两个子节点
这里有个比较巧妙地方法,我们把第1种情况和第2种情况合并起来处理
如果左子树为空,就重接右子树;如果右子树为空,就重接左子树
最难的就是第三种情况了。
通过看图,我们来理解一下。
我们要删除 z 这个节点
1.我们通过中序遍历找到z的后继为y,我们已经知道y肯定没有左子树(如果这里不明白,再回上去看看吧)
2.把y结点的值赋给z
3.我们要删除y结点 ,让y的父亲结点成为y的右子树的结点 (自己唯一不明白的就是这个地方了)
最后来看看删除代码:
Status DeleteBST(BiTree &T, KeyType key) { //寻找删除的结点的位置 if (!T) return false; if (T->data == key) { Delete(T); return true; } else if (key < T->data) DeleteBST(T->lchild, key); else DeleteBST(T->rchild, key); }使用查找前驱的方法删除结点:
void Delete (BiTree &p) { BiTree q, s; q = p; //左子树为空,则重接右子树 if(!p->lchild) { p = p->rchild; free(q); } //右子树为空,则重接左子树 else if(!p->rchild) { p = p->lchild; free(q); } //左右子树都不为空 //找到前驱 (后继) else { //s = PredecessorBST(p->lchild); s = p->lchild; while(!s->rchild) { q = s; s = s->rchild; } //s为p的前驱 p->data = s->data; if (q != p) q->rchild = s->lchild; else q->lchild = s->lchild; free(s); } }
相关文章推荐
- 数据结构(22)--动态查找之二叉排序树(二叉查找树)
- 数据结构之查找(五)——二叉查找树
- SDUTOJ(2039)数据结构上机实验之二分查找
- 3376-数据结构实验之查找四:二分查找
- 【数据结构与算法】二分查找
- 【除留余数法定义hash函数+线性探测法解决hash冲突】数据结构实验之查找七:线性之哈希表
- 数据结构实验之查找七:线性之哈希表
- 数据结构基础(2) --顺序查找 & 二分查找
- 【数据结构与算法】查找波峰或者波谷
- 数据结构实验之查找七:线性之哈希表
- 数据结构之折半查找
- 【数据结构与算法】二分查找
- 数据结构与算法-二分查找
- 数据结构实验之查找一:二叉排序树
- 数据结构与算法以及刷题leetocde 007 查找表 set和map相关
- 数据结构上机实验之二分查找
- 数据结构——查找、普通查找、折半查找
- 数据结构实验之查找七:线性之哈希表
- 数据结构——二叉查找树
- 数据结构上机实验之顺序查找