C++数据结构之二叉查找树(BST)

二分查找法在算法家族大类中属于“分治法”,二分查找的过程比较简单,代码见我的另一篇日志,戳这里!因二分查找所涉及的有序表是一个向量,若有插入和删除结点的操作,则维护表的有序性所花的代价是O(n)。

就查找性能而言,二叉查找树和二分查找不分伯仲,但是,就维护表的有序性而言,二叉排序树无须移动结点,只需修改指针即可完成插入和删除操作,且其平均的执行时间均为O(lgn),因此更有效。二叉查找树,顾名思义,是一种可以用来二分查找的树数据结构,其左孩子比父节点小,右孩子比父节点大,还有一个特性就是”中序遍历“可以让结点有序。在对关键字进行查找的时候,根据关键字与根节点的关键字比较的结果,分别选择继续与其左子树或者右子树进行比较,直到找到所查找的关键字或者访问节点的左右子树不存在(没找到关键字)则退出!

二叉查找树的主要操作有:插入关键字查找关键字删除关键字。下面分别对这三个步骤做详细描述和算法实现。

为了方便,我将二叉查找树实现为一个类,结构如下:

  1. typedef struct Node_
  2. {
  3. struct Node_ *parent;
  4. struct Node_ *left;
  5. struct Node_ *right;
  6. T data;
  7. }Node;
  8.  
  9. class BinaryTree
  10. {
  11. public:
  12. BinaryTree():root(NULL){};
  13. ~BinaryTree();
  14. bool insertNode(T data);
  15. bool deleteNode(T data);
  16. Node* findNode(T data);
  17. private:
  18. Node *root;
  19. };

1. 插入关键字的过程如下所示:

插入过程的代码如下:

  1. bool BinaryTree::insertNode(T data)
  2. {
  3. Node *x = NULL, *current, *parent;
  4.  
  5. /***********************************************
  6. * allocate node for data and insert in tree *
  7. ***********************************************/
  8.  
  9. /* find x's parent */
  10. current = root;
  11. parent = NULL;
  12. while (current) {
  13. if (compEQ(data, current->data)) return true;
  14. parent = current;
  15. current = compLT(data, current->data) ?
  16. current->left : current->right;
  17. }
  18.  
  19. /* setup new node */
  20. if ((x = (Node*)malloc(sizeof(*x))) == 0)
  21. {
  22. cout << "Insufficient memory (insertNode)!" << endl;
  23. return false;
  24. }
  25. x->data = data;
  26. x->parent = parent;
  27. x->left = NULL;
  28. x->right = NULL;
  29.  
  30. /* insert x in tree*/
  31. if(parent)
  32. if(compLT(x->data, parent->data))
  33. parent->left = x;
  34. else
  35. parent->right = x;
  36. else
  37. root = x;
  38.  
  39. return true;
  40. }

其中的compEQ和compLT为2个宏定义,用来比较两个关键字的大小。

2. 查找关键字的过程比较简单,和二分查找方法类似,代码如下:

  1. Node* BinaryTree::findNode(T data)
  2. {
  3. /*******************************
  4. * find node containing data *
  5. *******************************/
  6.  
  7. Node *current = root;
  8. while(current != NULL)
  9. if(compEQ(data, current->data))
  10. return current;
  11. else
  12. current = compLT(data, current->data) ?
  13. current->left : current->right;
  14. return NULL;
  15. }

3. 删除关键字的过程分为2种情况讨论:单孩子的情况和左右孩子的情况。

1> 单孩子情况分析:

如果删除的节点有左孩子那就把左孩子顶上去,如果有右孩子就把右孩子顶上去,so easy!如图所示:

2> 左右孩子情况分析:

首先可以这么想象,如果我们要删除一个数组的元素,那么我们在删除后会将其后面的一个元素顶到被删除的位置,如下图所示:

那么二叉树操作同样也是一样,我们根据“中序遍历(inorder tree walk)”找到要删除结点的后一个结点,然后顶上去就行了,原理跟“数组”一样一样的。

好了,贴代码:

  1. bool BinaryTree::deleteNode(T data)
  2. {
  3. Node* pNode = findNode(data);
  4. if (pNode == NULL)
  5. {
  6. cout << "Cannot find this data in BST!" << endl;
  7. return false;
  8. }
  9.  
  10. Node *x, *y;
  11. /* find tree successor */
  12. if (pNode->left == NULL || pNode->right == NULL)
  13. y = pNode;
  14. else {
  15. y = pNode->right;
  16. while (y->left != NULL) y = y->left;
  17. }
  18.  
  19. /* x is y's only child */
  20. if (y->left != NULL)
  21. x = y->left;
  22. else
  23. x = y->right;
  24.  
  25. /* remove y from the parent chain */
  26. if (x) x->parent = y->parent;
  27. if (y->parent)
  28. if (y == y->parent->left)
  29. y->parent->left = x;
  30. else
  31. y->parent->right = x;
  32. else
  33. root = x;
  34.  
  35. /* y is the node we're removing */
  36. /* z is the data we're removing */
  37. /* if z and y are not the same, replace z with y. */
  38. if (y != pNode) {
  39. y->left = pNode->left;
  40. if (y->left) y->left->parent = y;
  41. y->right = pNode->right;
  42. if (y->right) y->right->parent = y;
  43. y->parent = pNode->parent;
  44. if (pNode->parent)
  45. if (pNode == pNode->parent->left)
  46. pNode->parent->left = y;
  47. else
  48. pNode->parent->right = y;
  49. else
  50. root = y;
  51. free (pNode);
  52. }
  53. else {
  54. free (y);
  55. }
  56. return true;
  57. }

好了,二叉查找树的代码告一段落,我们在来分析一下二叉查找树的插入过程,假如有以下序列:<4, 17, 16, 20, 37, 38, 43>,则会生成如下所示二叉树:

这已经完全退化成了一个单链表,势必影响到关键字的查找过程。不过总会有解决办法的,下一篇博客我将继续这个话题,对普通二叉树经过旋转,即使用平衡二叉树,使其保持最坏复杂度在O(logN)。

谢谢大家的阅读,希望能够帮到大家!PS:文章中部分图片利用了博客园另外一篇文章的插图(戳这里)!

Published by Windows Live Write!

作者: 薛定谔の喵 
出处: http://www.cnblogs.com/berlin-sun/ 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。

 

C++数据结构之二叉查找树(BST)的更多相关文章

  1. 查找系列合集-二叉查找树BST

    一. 二叉树 1. 什么是二叉树? 在计算机科学中,二叉树是每个结点最多有两个子树的树结构. 通常子树被称作“左子树”(left subtree)和“右子树”(right subtree). 二叉树常 ...

  2. [学习笔记] 二叉查找树/BST

    平衡树前传之BST 二叉查找树(\(BST\)),是一个类似于堆的数据结构, 并且,它也是平衡树的基础. 因此,让我们来了解一下二叉查找树吧. (其实本篇是作为放在平衡树前的前置知识的,但为了避免重复 ...

  3. 数据结构:二叉查找树(C语言实现)

    数据结构:二叉查找树(C语言实现) ►写在前面 关于二叉树的基础知识,请看我的一篇博客:二叉树的链式存储 说明: 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: 1.若其左子树不空,则左子树上 ...

  4. 二叉查找树(BST)

    二叉查找树(BST):使用中序遍历可以得到一个有序的序列

  5. 二叉查找树BST 模板

    二叉查找树BST 就是二叉搜索树 二叉排序树. 就是满足 左儿子<父节点<右儿子 的一颗树,插入和查询复杂度最好情况都是logN的,写起来很简单.   根据BST的性质可以很好的解决这些东 ...

  6. 算法与数据结构基础 - 二叉查找树(Binary Search Tree)

    二叉查找树基础 二叉查找树(BST)满足这样的性质,或是一颗空树:或左子树节点值小于根节点值.右子树节点值大于根节点值,左右子树也分别满足这个性质. 利用这个性质,可以迭代(iterative)或递归 ...

  7. 浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

    http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的 ...

  8. 【查找结构 2】二叉查找树 [BST]

    当所有的静态查找结构添加和删除一个数据的时候,整个结构都需要重建.这对于常常需要在查找过程中动态改变数据而言,是灾难性的.因此人们就必须去寻找高效的动态查找结构,我们在这讨论一个非常常用的动态查找树— ...

  9. JS中数据结构之二叉查找树

    树是一种非线性的数据结构,以分层的方式存储数据.在二叉树上进行查找非常快,为二叉树添加或删除元素也非常快. 一棵树最上面的节点称为根节点,如果一个节点下面连接多个节点,那么该节点称为父节点,它下面的节 ...

随机推荐

  1. UVA 11426 - GCD - Extreme (II) (数论)

    UVA 11426 - GCD - Extreme (II) 题目链接 题意:给定N.求∑i<=ni=1∑j<nj=1gcd(i,j)的值. 思路:lrj白书上的例题,设f(n) = gc ...

  2. [ 单例、代理 & 通知 ]

    PS:手写单例.代理方法实现 & 通知的简单使用! [ 单例模式,代理设计模式,观察者模式! ] 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设 ...

  3. wget一个小技巧

    今天在装一个东西的时候,在网上看到了这样的命令 wget  http://xxxx.sh -o -  | sh  的用法 不太明白-o -的用法于是乎man wget,看到了下面的一段话 -O fil ...

  4. 採用Hexo 搭建Team Blog

    採用Hexo 搭建Team Blog 首先你要会使用Git 已经GitHub,然后让我们了解下什么是静态Blog 静态博客是指 不须要数据库驱动,拥有丰富模板,通过模板标记语言生成简单html css ...

  5. SHDocVw, AxSHDocVw的引用

    原文:SHDocVw, AxSHDocVw的引用 SHDocVw的引用SHDocVw一定要在下面这个路径找: 类似 C:\Program Files\Microsoft Visual Studio 9 ...

  6. Web API-属性路由

    路由(Routing)就是Web API如何将一个URI匹配到一个action的过程.Web API 2 支持一个新的路由方式-属性路由(attribute routing).顾名思义,属性路由使用标 ...

  7. Asp.Net MVC5入门学习系列④

    原文:Asp.Net MVC5入门学习系列④ 添加Model且简单的使用EF 对于EF(EntityFramework)不了解的朋友可以去百度文科或者在园子里搜一些简资源看下,假如和我一样知道EF的概 ...

  8. php soap调用asp.net webservice

    原文:php soap调用asp.net webservice 首先做一下准备工作,找到安装环境里的php.ini把;extension=php_soap.dll去掉前面的;.我这里使用的是wamp, ...

  9. 用批处理编译*.sln工程

    原文:用批处理编译*.sln工程 批处理是直接调用Microsoft Visual Studio 8\Common7\IDE\ 目录内的 devenv.exe ,它启动后就是IDE,提供的参数如下: ...

  10. xheditor 进阶

    xhEditor提供两种方式初始化编辑器: 方法1:利用class属性来初始化和传递各种初始化参数,例:  class="xheditor {skin:'default'}" 方法 ...