二叉查找树(二叉排序树)的详细实现,以及随机平衡二叉查找树Treap的分析与应用
这是一篇两年前写的东西,自我感觉还是相当不错的Treap教程。正好期末信息科学技术概论课要求交一个论文,就把这个东西修改了一下交了,顺便也发到这里吧。
1、序
详细实现了二叉查找树的各种操作:插入结点、构造二叉树、删除结点、查找、 查找最大值、查找最小值、查找指定结点的前驱和后继
2、二叉查找树简介
它或者是一棵空树;或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值; (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值; (3)左、右子树也分别为二叉排序树
3、二叉查找树的各种操作
此处给出代码,注释非常详细,具体操作请参考代码:
- /*************************************************************************
- 这是一个二叉查找树,实现了以下操作:插入结点、构造二叉树、删除结点、查找、
- 查找最大值、查找最小值、查找指定结点的前驱和后继。上述所有操作时间复杂度
- 均为o(h),其中h是树的高度
- 注释很详细,具体内容就看代码吧
- *************************************************************************/
- #include<stdio.h>
- #include<stdlib.h>
- //二叉查找树结点描述
- typedef int KeyType;
- typedef struct Node
- {
- KeyType key; //关键字
- struct Node * left; //左孩子指针
- struct Node * right; //右孩子指针
- struct Node * parent; //指向父节点指针
- }Node,*PNode;
- //往二叉查找树中插入结点
- //插入的话,可能要改变根结点的地址,所以传的是二级指针
- void inseart(PNode * root,KeyType key)
- {
- //初始化插入结点
- PNode p=(PNode)malloc(sizeof(Node));
- p->key=key;
- p->left=p->right=p->parent=NULL;
- //空树时,直接作为根结点
- if((*root)==NULL){
- *root=p;
- return;
- }
- //插入到当前结点(*root)的左孩子
- if((*root)->left == NULL && (*root)->key > key){
- p->parent=(*root);
- (*root)->left=p;
- return;
- }
- //插入到当前结点(*root)的右孩子
- if((*root)->right == NULL && (*root)->key < key){
- p->parent=(*root);
- (*root)->right=p;
- return;
- }
- if((*root)->key > key)
- inseart(&(*root)->left,key);
- else if((*root)->key < key)
- inseart(&(*root)->right,key);
- else
- return;
- }
- //查找元素,找到返回关键字的结点指针,没找到返回NULL
- PNode search(PNode root,KeyType key)
- {
- if(root == NULL)
- return NULL;
- if(key > root->key) //查找右子树
- return search(root->right,key);
- else if(key < root->key) //查找左子树
- return search(root->left,key);
- else
- return root;
- }
- //查找最小关键字,空树时返回NULL
- PNode searchMin(PNode root)
- {
- if(root == NULL)
- return NULL;
- if(root->left == NULL)
- return root;
- else //一直往左孩子找,直到没有左孩子的结点
- return searchMin(root->left);
- }
- //查找最大关键字,空树时返回NULL
- PNode searchMax(PNode root)
- {
- if(root == NULL)
- return NULL;
- if(root->right == NULL)
- return root;
- else //一直往右孩子找,直到没有右孩子的结点
- return searchMax(root->right);
- }
- //查找某个结点的前驱
- PNode searchPredecessor(PNode p)
- {
- //空树
- if(p==NULL)
- return p;
- //有左子树、左子树中最大的那个
- if(p->left)
- return searchMax(p->left);
- //无左子树,查找某个结点的右子树遍历完了
- else{
- if(p->parent == NULL)
- return NULL;
- //向上寻找前驱
- while(p){
- if(p->parent->right == p)
- break;
- p=p->parent;
- }
- return p->parent;
- }
- }
- //查找某个结点的后继
- PNode searchSuccessor(PNode p)
- {
- //空树
- if(p==NULL)
- return p;
- //有右子树、右子树中最小的那个
- if(p->right)
- return searchMin(p->right);
- //无右子树,查找某个结点的左子树遍历完了
- else{
- if(p->parent == NULL)
- return NULL;
- //向上寻找后继
- while(p){
- if(p->parent->left == p)
- break;
- p=p->parent;
- }
- return p->parent;
- }
- }
- //根据关键字删除某个结点,删除成功返回1,否则返回0
- //如果把根结点删掉,那么要改变根结点的地址,所以传二级指针
- int deleteNode(PNode* root,KeyType key)
- {
- PNode q;
- //查找到要删除的结点
- PNode p=search(*root,key);
- KeyType temp; //暂存后继结点的值
- //没查到此关键字
- if(!p)
- return 0;
- //1.被删结点是叶子结点,直接删除
- if(p->left == NULL && p->right == NULL){
- //只有一个元素,删完之后变成一颗空树
- if(p->parent == NULL){
- free(p);
- (*root)=NULL;
- }else{
- //删除的结点是父节点的左孩子
- if(p->parent->left == p)
- p->parent->left=NULL;
- else //删除的结点是父节点的右孩子
- p->parent->right=NULL;
- free(p);
- }
- }
- //2.被删结点只有左子树
- else if(p->left && !(p->right)){
- p->left->parent=p->parent;
- //如果删除是父结点,要改变父节点指针
- if(p->parent == NULL)
- *root=p->left;
- //删除的结点是父节点的左孩子
- else if(p->parent->left == p)
- p->parent->left=p->left;
- else //删除的结点是父节点的右孩子
- p->parent->right=p->left;
- free(p);
- }
- //3.被删结点只有右孩子
- else if(p->right && !(p->left)){
- p->right->parent=p->parent;
- //如果删除是父结点,要改变父节点指针
- if(p->parent == NULL)
- *root=p->right;
- //删除的结点是父节点的左孩子
- else if(p->parent->left == p)
- p->parent->left=p->right;
- else //删除的结点是父节点的右孩子
- p->parent->right=p->right;
- free(p);
- }
- //4.被删除的结点既有左孩子,又有右孩子
- //该结点的后继结点肯定无左子树(参考上面查找后继结点函数)
- //删掉后继结点,后继结点的值代替该结点
- else{
- //找到要删除结点的后继
- q=searchSuccessor(p);
- temp=q->key;
- //删除后继结点
- deleteNode(root,q->key);
- p->key=temp;
- }
- return 1;
- }
- //创建一棵二叉查找树
- void create(PNode* root,KeyType *keyArray,int length)
- {
- int i;
- //逐个结点插入二叉树中
- for(i=0;i<length;i++)
- inseart(root,keyArray[i]);
- }
- int main(void)
- {
- int i;
- PNode root=NULL;
- KeyType nodeArray[11]={15,6,18,3,7,17,20,2,4,13,9};
- create(&root,nodeArray,11);
- for(i=0;i<2;i++)
- deleteNode(&root,nodeArray[i]);
- printf("%d\n",searchPredecessor(root)->key);
- printf("%d\n",searchSuccessor(root)->key);
- printf("%d\n",searchMin(root)->key);
- printf("%d\n",searchMax(root)->key);
- printf("%d\n",search(root,13)->key);
- return 0;
- }
4、附录
参考书籍 《算法导论》
二叉查找树(二叉排序树)的详细实现,以及随机平衡二叉查找树Treap的分析与应用的更多相关文章
- 【查找结构3】平衡二叉查找树 [AVL]
在上一个专题中,我们在谈论二叉查找树的效率的时候.不同结构的二叉查找树,查找效率有很大的不同(单支树结构的查找效率退化成了顺序查找).如何解决这个问题呢?关键在于如何最大限度的减小树的深度.正是基于这 ...
- 平衡二叉查找树 AVL 的实现
不同结构的二叉查找树,查找效率有很大的不同(单支树结构的查找效率退化成了顺序查找).如何解决这个问题呢?关键在于如何最大限度的减小树的深度.正是基于这个想法,平衡二叉树出现了. 平衡二叉树的定义 (A ...
- 006-数据结构-树形结构-二叉树、二叉查找树、平衡二叉查找树-AVL树
一.概述 树其实就是不包含回路的连通无向图.树其实是范畴更广的图的特例. 树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合. 1.1.树的特性: 每个结点有零个或多个子 ...
- 平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】
平衡树初阶——AVL平衡二叉查找树 一.什么是二叉树 1. 什么是树. 计算机科学里面的树本质是一个树状图.树首先是一个有向无环图,由根节点指向子结点.但是不严格的说,我们也研究无向树.所谓无向树就是 ...
- 数据结构-自平衡二叉查找树(AVL)详解
介绍: 在计算机科学中,AVL树是最先发明的自平衡二叉查找树. 在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树. 查找.插入和删除在平均和最坏情况下都是O(log n).增 ...
- AVL树(平衡二叉查找树)
首先要说AVL树,我们就必须先说二叉查找树,先介绍二叉查找树的一些特性,然后我们再来说平衡树的一些特性,结合这些特性,然后来介绍AVL树. 一.二叉查找树 1.二叉树查找树的相关特征定义 二叉树查找树 ...
- 算法学习 - 平衡二叉查找树实现(AVL树)
平衡二叉查找树 平衡二叉查找树是非常早出现的平衡树,由于全部子树的高度差不超过1,所以操作平均为O(logN). 平衡二叉查找树和BS树非常像,插入和删除操作也基本一样.可是每一个节点多了一个高度的信 ...
- 二叉查找树、平衡二叉树(AVLTree)、平衡多路查找树(B-Tree),B+树
B+树索引是B+树在数据库中的一种实现,是最常见也是数据库中使用最为频繁的一种索引. B+树中的B代表平衡(balance),而不是二叉(binary),因为B+树是从最早的平衡二叉树演化而来的. 在 ...
- 深入浅出数据结构C语言版(12)——平衡二叉查找树之AVL树
在上一篇博文中我们提到了,如果对普通二叉查找树进行随机的插入.删除,很可能导致树的严重不平衡 所以这一次,我们就来介绍一种最老的.可以实现左右子树"平衡效果"的树(或者说算法),即 ...
随机推荐
- thinkphp自学笔记
什么是MVC? M:编写模型类-对数据进行操作 用作数据处理 V:编写HTML文件-将页面显示出来 网页视图 C:编写类文件 用作逻辑处理 ThinkPHP的MVC的特点是什么: 它比较灵活并不依赖 ...
- Spring Cloud(十四)Config 配置中心与客户端的使用与详细
前言 在上一篇 文章 中我们直接用了本应在本文中配置的Config Server,对Config也有了一个基本的认识,即 Spring Cloud Config 是一种用来动态获取Git.SVN.本地 ...
- 一些CSS3的乐趣 - 工作也能发现乐的源头
中秋节 translate 前些日子做一个中秋节的专题,主要就是写一个效果,月亮滚动,花瓣飘落.具体代码如下: .icons {z-index:10088; position:absolute; -w ...
- 【51Nod】1510 最小化序列 贪心+动态规划
[题目]1510 最小化序列 [题意]给定长度为n的数组A和数字k,要求重排列数组从而最小化: \[ans=\sum_{i=1}^{n-k}|A_i-A_{i+k}|\] 输出最小的ans,\(n \ ...
- 图文详解 解决 MVC4 Code First 数据迁移
在使用Code first生成数据库后 当数据库发生更改时 运行程序就会出现数据已更改的问题 这时可以删除数据库重新生成解决 但是之前的数据就无法保留 为了保留之前的数据库数据 我们需要使用到C ...
- org.hibernate.TransientObjectException异常
代码如下: /** * 测试4:新增一个秘书角色,并赋给张三该角色 */ @Test public void test4(){ Session session = HibernateUtils.ope ...
- 云计算--MPI
[root@localhost mpi]# mpicc -c base.c[root@localhost mpi]# mpicc -o base base.o[root@localhost mpi]# ...
- elasticsearch如何使用?
ES和关系型数据库的数据对比 1.创建索引库PUT/POST都可以,索引库名称必须全部小写,不能以下划线开头,也不能包含逗号curl -XPUT 'http://192.168.136.131:920 ...
- crontab挂定时任务
Linux shell基本知识 a)">" 与 ">>" 的作用是不一样的,前者使用本次输出内容替换原有文件的内容,后者则是把本次输出追加 ...
- PhpStorm,Pycharm,Goland破解
phpstorm是一个轻量级且便捷的PHP IDE,其旨在提供用户效率,可深刻理解用户的编码,提供智能代码补全,快速导航以及即时错误检查.不但是php开发的利器,前端开发也是毫不逊色的.下面记录Php ...