重要的事情放前面,原文链接:
欢迎阅读更多优质文章:
数据结构与算法
各位小禹禹,你们好!感谢您的建议,让景禹更加完善,这份参考目录是献给提建议的您!祝你们不论考研、找工作还是应付考试,都一切顺利!
线性表
顺序存储结构:
链式存储结构:
栈
队列
递归+分治
字符串
树
图
查找
景禹更新文章主要集中在微信公众号 ,欢迎各位来拍砖。
今天我们谈一谈 二叉排序树 ,一种你会爱上的数据结构,当然人有优缺,二叉排序是也是如此,我们一起开动脑筋征服她吧。
二叉排序树
二叉排序树(Binary Sort Tree)或者是一颗空树;或者是具有如下性质的二叉树:
(1) 若它的左子树不空,则 左子树 上所有结点的值 均小于 它的根结点的值;
(2) 若它的右子树不空,则 右子树 上所有结点的值 均大于 它的根结点的值;
(3) 它的 左、右子树又分别为二叉排序树 。
显然二叉排序树的定义是一个递归形式的定义,所以后面景禹要讲的插入、查找和删除都是基于递归的形式。
下图中的这颗二叉树就是一颗典型的二叉排序树:
二叉排序树既然是名字当中带有 排序 二字,这就是它相对于普通二叉树的优势所在。此时可能还不清楚,没关系,我们一步一步的建立一颗上面的二叉树就会很清晰。
假设我们初始时有如下 无序序列:
第一步:插入 8 作为根结点。
第二步:插入 3 ,与根结点 8 进行比较,发现比8小,且根结点没有左孩子,则将 3 插入到 8 的左孩子。
第三步:插入10,首先与根结点比较,发现比 8 大,则要将 10 插入根结点的右子树;根结点 8 的右子树为空,则将 10 作为 8 的右孩子。
第四步:插入 1,首先与根结点比较,比根结点小,则应插入根结点的左子树。再与根结点的左孩子 3 比较,发现比 3 还小,则应插入 3 的左孩子。
第五步:插入 6,先与根结点8比较,小于 8,向左走;再与 3 比较,大于 3,向有走,没有结点,则将6 作为3的右孩子。
第六步:插入14,先与8比较,比 8 大,向右走;再与8的右孩子10比较,比10大,向右走,没有结点,则将14作为10的右孩子。
第七步:插入4,先与8比较,发现比8小,向左走,再与3比较,比3大向右走,再与6比较,向左走且没有左孩子,将4作为6的左孩子。
第八步:插入7,先与8比较,发现比8小,向左走,再与3比较,向右走,在与6比较,继续向右走,发现6没有右孩子,则将7作为 6的右孩子插入。
第九步:插入13,先与8比较(大于)向右,再与10比较(大于)向右,再与14比较(小于)向左,发现14的左孩子为空,则将13插入到14的左孩子位置。
上面构造出的二叉排序树的中序遍历结果(关于二叉树的遍历不熟悉的,可以参看 一文横扫二叉树的所有遍历方法 ):
二叉排序树的查找操作
二分查找是在一个有序数组上进行的,就像前面我们通过对二叉排序树进行中序遍历得到的结果一样,初始时,我们将整个有序数组当做二分查找的搜索空间,然后计算搜索空间的中间元素,并与查找元素进行比较;然后将整个搜索空间缩减一半;重复上面的步骤,直到找到待查找元素或者返回查找失败的信息。关于二分查找的详细介绍可以参看 二分查找就该这样学 这篇文章。
二叉排序树的查找操作与二分查找非常相似,我们一起试着查找值为13的结点。
第一步:访问根结点 8 .
第二步:根据二叉排序树的左子树均比根结点小,右子树均比根结点大的性质, 13 > 8 ,因此值为13的结点可能在根结点 8 的右子树当中,我们查看根结点的右子节点 10 :
第三步:与第二步相似, 13 > 10 ,因此查看结点 10 的右孩子 14 :
第四步:根据二叉排序树的左子树均比根结点小,右子树均比根结点大的性质, 13 < 14 ,因此查看 14 的左孩子 13 ,发现刚好和要查找的值相等:
二叉排序树查找操作的实现:
struct node* search(struct node* root, int key)
{
// 如果root为空或者root的值和待查找的key相同,则返回root
if (root &