二叉查找树 _ 二叉排序树 _ 二叉搜索树_C++

一、数据结构背景+代码变量介绍

  二叉查找树,又名二叉排序树,亦名二叉搜索树

  它满足以下定义:

    1、任意节点的子树又是一颗二叉查找树,且左子树的每个节点均小于该节点,右子树的每个节点均大于该节点。

    2、由1可推出,任意节点的左孩子小于该节点,右孩子大于该节点

      以上讨论的是左(右)孩子(子树)存在的情况

  它的中序遍历是一个升序的排序

  在参考代码中,我们定义有:

    主程序中,k代表插入或删除或查找的节点的值

    root,根节点位置;a[i],第 i 号节点的值;cl[i],第 i 号节点左孩子的位置;cr[i],第 i 号节点右孩子的位置;fa[i],父亲节点位置;



二、中序遍历

   中序遍历的求法采用递归,先递归它的左孩子,然后打印当前节点,最后递归它的右孩子(当左或右孩子存在时才进行递归)

  

  如上图的中序遍历为 DBEAFC

  时间复杂度O(n)

1 void mid(int x)
2 {
3     if (time[cl[x]]!=0) mid(cl[x]);
4     cout<<a[x]<<" ";
5     if (time[cr[x]]!=0) mid(cr[x]);
6 }
7
8 主程序中:mid(root);


三、插入节点

  我们采用遇到相同的节点,使该节点计数器+1的办法

  先从根节点出发:

    1、若当前节点小于插入的数,则递归进入其左儿子

                   若左儿子计数器为0,即不存在左儿子,则直接将数插入到左儿子

    2、若当前节点大于插入的数,则递归进入其右儿子

                   若右儿子计数器为0,即不存在右儿子,则直接将数插入到右儿子

    3、若当前节点等于插入的数,则直接将该节点计数器+1

样例一

  如上图,将6插入该二叉树

    1、与根节点比较,小于根节点,进入左儿子

    2、与2比较,大于2,进入右儿子

    3、与5比较,大于5,进入右儿子,但因右儿子不存在,所以将6作为其右儿子

样例二

  如上图,将1插入该二叉树:

    1、与根节点比较,小于8,进入左儿子

    2、与2比较,小于2,进入左儿子,但因其左儿子不存在,所以将1作为其左儿子

  时间复杂度O(log2n)

 1 void ins(int i,int x)
 2 {
 3     if (root==0)
 4     {
 5         a[1]=x;
 6         time[1]=root=1;
 7         return;
 8     }
 9     if (x<a[i])
10     {
11         if (time[cl[i]]==0)
12         {
13             cl[i]=top>0?s[top--]:++tail;14             a[cl[i]]=x;
15             fa[cl[i]]=i;
16             time[cl[i]]++;
17             cr[cl[i]]=cl[cl[i]]=0;
18         }
19         else ins(cl[i],x);
20     }
21     else if (x>a[i])
22     {
23         if (time[cr[i]]==0)
24         {
25             cr[i]=top>0?s[top--]:++tail;26             a[cr[i]]=x;
27             fa[cr[i]]=i;
28             time[cr[i]]++;
29             cr[cr[i]]=cl[cr[i]]=0;
30         }
31         else ins(cr[i],x);
32     }
33     else
34     {
35         time[i]++;
36     }
37 }
38
39 主程序中:ser(root,k); root代表起始位置,k代表插入的值


四、查找节点

  查找类似于插入

  同样从根节点出发,如果遇到了空节点,即计数器等于0的节点,直接返回0,表示未查找到

  若该节点等于查找的值,则返回该节点的位置

  若该节点大于查找的值,则向左儿子递归查找

  若该节点小于查找的值,则向右儿子递归查找

  此处说明,若当前节点为空节点,则说明小于(大于)该节点父亲的值不存在,即未查找到

  查找类似于线段树思想,是一步步向下把范围缩小,直到找到期望的值或无结果

样例一

  如上图,需查找的值为5

    1、查找根节点,5<8,进入左儿子

    2、5>2,进入右儿子

    3、5=5,查找到该节点,返回该节点的位置

  若需查找的值为4时,在第3步会进入其左儿子,又因左儿子为空节点,则返回0,说明未查找到

  时间复杂度O(log2n)

1 int sea(int i,int x)
2 {
3     if (time[i]==0) return 0;
4     if (a[i]==x) return i;
5     else if (a[i]>x) return ser(cl[i],x);
6     else return ser(cr[i],x);
7 }
8
9 主程序中:sea(root,k); root代表查找的起始位置,k代表查找的值


五、删除节点

  当需要删除节点时,先查找改值所在的位置,然后再进行删除

  如果该节点计数器大于1,则只用把计数器-1

  如果计数器等于1,即删除后该节点不再存在,则根据儿子的数目分为三种情况:

    1、没有儿子:直接将该节点删除

    2、一个儿子:将该节点父亲的左(右)儿子直接指向该节点的唯一的那个儿子

    3、两个儿子:在该节点的右子树中寻找一个最小的值,然后用最小的那个节点替代该节点,最后删除最小的节点

            寻找最小节点具体方法:先将目前节点指向右儿子,然后寻找不断指向目前节点的左儿子,直到没有左儿子为止

            因为需要删除的最小节点肯定没有左儿子,所以只需递归执行第1或第2种情况,即 del(最小节点位置,最小节点的值)具体请参考代码

样例一

  删除9节点:调用查找,查找到9的位置,因为它没有儿子,可直接删除

样例二

  删除5节点:同样查找5节点的位置,发现其有1个孩子,则将 5节点 的 父亲2节点 的 右孩子 指向 5节点 的 孩子6节点,这样就自动删除了5节点

样例三

  删除2节点:

    1、查找到2节点的位置

    2、把最小节点指向其右孩子

    3、不断寻找目前最小节点的左孩子,直到尽头,找到最小节点

    4、将最小节点的信息赋给2节点

    5、按照删除节点的方法删除最小节点4节点

  时间复杂度O(log2n)

 1 void del(int k,int x)
 2 {
 3     int ct=0;
 4     if (cl[k]!=0) ct++;
 5     if (cr[k]!=0) ct++;
 6     time[k]--;
 7     if (time[k]==0)
 8     {
 9         if (ct==1)
10         {
11             s[++top]=k;12             if (k==root)
13             {
14                 root=time[cr[k]]==0?cl[k]:cr[k];
15                 return;
16             }
17             if (x<a[fa[k]]) cl[fa[k]]=time[cr[k]]==0?cl[k]:cr[k];
18             else cr[fa[k]]=time[cr[k]]==0?cl[k]:cr[k];
19         }
20         else if (ct==2)
21         {
22             int s=cr[k];
23             if (time[cl[s]]!=0) s=cl[s];
24             time[k]=time[s];
25             a[k]=a[s];
26             del(s,a[s]);
27         }
28         else s[++top]=k;29     }
30 }
31
32 主程序中:del(sea(root,k),k); 先查找到需删除的节点的位置,然后删除k


六、空节点位置栈

  在删除节点的时候,会产生许多空节点

  为了节省空间,我们会开一个栈来保存空节点的位置,当删除某个节点后,把它空出来的位置压入栈中

  当插入节点时,先询问栈顶top是否大于0,若栈中有元素,则把栈中的位置弹出,用该位置存放节点

                      若栈中没有元素,表示前面没有空的位置,则新开一个空间来存放节点,通过保存最大位置数的变量tail来控制最大位置



七、特殊情况

  对于二叉查找树会产生如下图的情况

  则所有操作的时间往往会被卡成线性O(n),而利用平衡二叉树、伸展树、红黑树等等数据结构便会帮我们解决这个问题

版权所有,转载请联系作者,违者必究

QQ:740929894

时间: 2024-10-08 08:16:06

二叉查找树 _ 二叉排序树 _ 二叉搜索树_C++的相关文章

PAT树_层序遍历叶节点、中序建树后序输出、AVL树的根、二叉树路径存在性判定、奇妙的完全二叉搜索树、最小堆路径、文件路由

<pre class="code"><span style="font-family: %value; font-size: 14px;">03-树1. List Leaves (25) Given a tree, you are supposed to list all the leaves in the order of top down, and left to right. Input Specification: Each inpu

【模板】二叉搜索树(二叉排序树,二叉查找树,BST)

二叉搜索树其实就是满足左结点小于根,右结点大于根这类规则的树形结构. 1 int n; 2 int a[MAX_N]; 3 int lt[MAX_N], rt[MAX_N]; 4 // 没有则为-1 5 // 默认a[0]为根结点 6 7 void Insert(int x, int obj) // 插入结点a[obj] 8 { 9 if(a[obj] < a[x]) 10 { 11 if(lt[x] ^ -1) Insert(lt[x], obj); 12 else lt[x] = obj;

二叉排序树BinarySortTree(二叉搜索树Binary Search Tree)

二叉排序树(Binary Sort Tree)又称二叉查找树(Binary Search Tree),亦称二叉搜索树. 定义: 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值: (3)左.右子树也分别为二叉排序树: (4)没有键值相等的节点 步骤: 二叉树 若根结点的关键字值等于查找的关键字则成功. 否则,若小于根结点的关键字值,递归查左子树. 若大于根

[数据结构]二叉搜索树(BST) VS 平衡二叉排序树(AVL) VS B树(平衡多路搜索树) VS B+树 VS 红黑树(平衡二叉B树)

1 二叉排序树/二叉查找树/Binary Sort Tree 1种对排序和查找都很有用的特殊二叉树 叉排序树的弊端的解决方案:平衡二叉树 二叉排序树必须满足的3条性质(或是具有如下特征的二叉树) 若它的左子树不为空,则:左子树上所有结点的值< 它根结点的值 若它的右子树不为空,则:右子树上所有结点的值 > 它根结点的值 它的左子树.右子树也分别为二叉排序树(递归性) (按照如上定义,即: 1 无键值相等的结点 2 中序遍历一颗二叉树时,可得一个结点值递增的有序序列) 2 平衡二叉排序树/Bal

判断一棵树是否为二叉搜索树(二叉排序树) python

输入一棵树,判断这棵树是否为二叉搜索树.首先要知道什么是排序二叉树,二叉排序树是这样定义的,二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值: (3)左.右子树也分别为二叉排序树: (4)没有键值相等的节点 #方法1,直接判断 直接判断的关键在于不能只是单纯地判断根.左.右三个节点的大小关系,左子树的右节点不仅要大于父节点,还要小于父节点的父节点,右子树的左节点

数据结构——二叉搜索树、B树、B-树

数据结构——二叉搜索树.B树.B-树 1. 综述 二叉排序树(Binary Sort Tree),又叫二叉查找树(Binary Search Tree),也叫二叉排序树. 二叉搜索树满足以下性质: 1. 若根节点左子树不为空,则左子树上的所有节点均小于根节点: 2. 若根节点右子树不为空,则右子树上的所有节点均大于根节点: 3. 其左右子树也是二叉搜索树(递归定义): 4. 没有键值相等的点. B树就是B-树.B树/B-树英文叫B-Tree,可能被不小心翻译成了B-树.

算法导论第十二章 二叉搜索树

一.二叉搜索树概览 二叉搜索树(又名二叉查找树.二叉排序树)是一种可提供良好搜寻效率的树形结构,支持动态集合操作,所谓动态集合操作,就是Search.Maximum.Minimum.Insert.Delete等操作,二叉搜索树可以保证这些操作在对数时间内完成.当然,在最坏情况下,即所有节点形成一种链式树结构,则需要O(n)时间.这就说明,针对这些动态集合操作,二叉搜索树还有改进的空间,即确保最坏情况下所有操作在对数时间内完成.这样的改进结构有AVL(Adelson-Velskii-Landis)

八:二叉搜索树的后序遍历

二叉搜索树:(又称:二叉查找树,二叉排序树) 满足性质: (1) 它或者是一棵空树: (2) 或者是具有下列性质的二叉树: <1> 若左子树不空,则左子树上所有结点的值均小于它的根结点的值: <2> 若右子树不空,则右子树上所有结点的值均大于它的根结点的值: <3> 左.右子树也分别为二查找序树: 问题描述: 输入一个整数数组,判断该数组是不是某二叉查找树的后序遍历的结果.如果是返回true,否则返回false. 解析: 根据后序遍历的定义,如果一个序列是二叉树的后续遍

数据结构第三部分:树与树的表示、二叉树及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树、集合及其运算

参考:浙大数据结构(陈越.何钦铭)课件 1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找——方法一:顺序查找(时间复杂度O(n)) int