二叉查找树

Posted 凄夜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉查找树相关的知识,希望对你有一定的参考价值。

  二叉树的定义是一棵树的每个节点最多只有两个儿子,使二叉树成为二叉查找树的性质是,对于树中的每个节点X,它的左子树中的关键字比X中的小,而它的右子树则比X中的关键字大。

  二叉树节点可以定义成如下形式:

1 struct BSTreeNode {
2     BSTreeNode* pLeft;
3     BSTreeNode* pRight;
4     int nData;
5 };

  二叉树非常简单,下面再介绍几个基本的操作。

  一、插入

    插入一个关键字Key从根节点开始,如果Key比此节点关键字大,则往右边继续往下,直到节点为空,以下代码为非递归写法,要写成递归写法也是非常容易的

 1 //返回树的根节点
 2 BSTreeNode* BSTreeInsert(BSTreeNode* pRoot, int nData) {
 3     if (pRoot == nullptr) {
 4         pRoot = new BSTreeNode;
 5         pRoot->pLeft = pRoot->pRight = nullptr;
 6         pRoot->nData = nData;
 7     }
 8     else {
 9         BSTreeNode* pParent = pRoot;
10         BSTreeNode* pCursor = pParent;
11         while (pCursor) {
12             pParent = pCursor;
13             if (nData > pCursor->nData)
14                 pCursor = pCursor->pRight;
15             else if (nData < pCursor->nData)
16                 pCursor = pCursor->pLeft;
17             else
18                 return pRoot;
19         }
20         pCursor = new BSTreeNode;
21         pCursor->nData = nData;
22         pCursor->pLeft = pCursor->pRight = nullptr;
23         if (nData > pParent->nData)
24             pParent->pRight = pCursor;
25         else if (nData < pParent->nData)
26             pParent->pLeft = pCursor;
27     }
28     return pRoot;
29 }

  二、获取最小值

    一直往左边遍历,直到节点为空。

 1 BSTreeNode* BSTreeMinimumNode(BSTreeNode* pRoot) {
 2     if (pRoot == nullptr)
 3         return nullptr;
 4 
 5     BSTreeNode* pCursor = pRoot;
 6     while (pCursor->pLeft) {
 7         pCursor = pCursor->pLeft;
 8     }
 9     return pCursor;
10 }

  三、获取最大值

    一直往右边遍历,直到节点为空。

 1 BSTreeNode* BSTreeMaximumNode(BSTreeNode* pRoot) {
 2     if (pRoot == nullptr)
 3         return nullptr;
 4 
 5     BSTreeNode* pCursor = pRoot;
 6     while (pCursor->pRight) {
 7         pCursor = pCursor->pRight;
 8     }
 9     return pCursor;
10 }

  四、删除

    二叉查找树的删除稍复杂一些,先查找此树待删除节点,当找到此节点(设为X)时,先判断左子节点和右子节点是否为空,如果有任一子节点为空,则删除非常容易,只需要将空节点的兄弟节点代替要删除的节点     即可。而如果左子节点和右子节点都不为空,则在待删除节点的右子树中找一个值最小的节点(设为Y),然后将此最小节点的值赋值给待删除结点X,然后在右子树中删除此最小节点Y,而且Y必定左子节点为空的,删除会非常简单。代码如下:

 1 BSTreeNode* BSTreeDelete(BSTreeNode* pRoot, int nData) {
 2     if (pRoot == nullptr)
 3         return nullptr;
 4     else if (nData > pRoot->nData) {
 5         pRoot->pRight = BSTreeDelete(pRoot->pRight, nData);
 6         return pRoot;
 7     }
 8     else if (nData < pRoot->nData) {
 9         pRoot->pLeft = BSTreeDelete(pRoot->pLeft, nData);
10         return pRoot;
11     }
12     else {
13         if (pRoot->pLeft == nullptr || pRoot->pRight == nullptr) {
14             BSTreeNode* pNode = (pRoot->pRight == nullptr) ? pRoot->pLeft : pRoot->pRight;
15             delete pRoot;
16             return pNode;
17         }
18         else {
19             BSTreeNode* pNode = BSTreeMinimumNode(pRoot->pRight);
20             pRoot->nData = pNode->nData;
21             pRoot->pRight = BSTreeDelete(pRoot->pRight, pNode->nData);
22             return pRoot;
23         }
24     }
25 }

  返回值是传入的树被删除nData后树的根节点。删除后,通过递归回溯,将返回值赋值给原节点对应的左子树或右子树。

  在《算法导论》里面,采用的是非递归删除,所以在那里讨论如果X的左右子节点不为空,则查找右子树中的后继节点Y(也就是最小节点)时,还讨论了如果后继Y是X的右子节点的情况,如果是右子节点则直接拿Y替换X,否则拿Y的右子节点先替换X中的值,再拿Y的右子节点替换Y。个人感觉不如递归删除的代码简洁明了。而且非递归删除里面,节点必须保持对父节点的引用,也就是说节点的定义里面要加一个父节点指针。

  五、二叉树的遍历

    二叉树的遍历有三种遍历方式,先序遍历,中序遍历,后序遍历

    先序遍历:本身,左子节点,右子节点。

    中序遍历:左子节点,本身,右子节点。

    后序遍历:左子节点,右子节点,本身。

  以以下二叉树为例:

      

  先序遍历输出:ABDECFG

  中序遍历输出:DBEAFCG

  后序遍历输出:DEBFGCA

  由以上可知,中序遍历输出的是排序好的结果。

  六、查找

    查找就不用说了,二叉查找树,在平均情况下,时间为O(logN),也就是树的高度

以上是关于二叉查找树的主要内容,如果未能解决你的问题,请参考以下文章

数据结构 动态查找与二叉排序树

二叉查找树

PHP 二叉查找树(二叉搜索树)的查找

C++-二叉搜索树的查找&插入&删除-二叉搜索树代码实现-二叉搜索树性能分析及解决方案

二叉查找树 - 删除查找

数据结构中,怎么写二叉树查找双亲的伪代码?急!