二叉查找树(二)之 C++的实现

概要

上一章介绍了"二叉查找树的相关理论知识,并通过C语言实现了二叉查找树"。这一章给出二叉查找树的C++版本。这里不再对树的相关概念进行介绍,若遇到不明白的概念,可以在上一章查找。

目录
1.二叉树查找树
2. 二叉查找树的C++实现 3. 二叉查找树的C++实现(完整源码)
4. 二叉查找树的C++测试程序

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3576373.html


更多内容: 数据结构与算法系列 目录

(01) 二叉查找树(一)之 图文解析 和 C语言的实现
(02) 二叉查找树(二)之 C++的实现

二叉查找树简介

二叉查找树(Binary Search Tree),又被称为二叉搜索树。
它是特殊的二叉树:对于二叉树,假设x为二叉树中的任意一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y] >= key[x]。那么,这棵树就是二叉查找树。如下图所示:

在二叉查找树中:
(01) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(02) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(03) 任意节点的左、右子树也分别为二叉查找树。
(04) 没有键值相等的节点(no duplicate nodes)。

二叉查找树的C++实现

1. 节点和二叉查找树的定义

1.1 二叉查找树节点

template <class T>
class BSTNode{public:T key;            // 关键字(键值)BSTNode *left;    // 左孩子BSTNode *right;    // 右孩子BSTNode *parent;// 父结点
BSTNode(T value, BSTNode *p, BSTNode *l, BSTNode *r):key(value),parent(),left(l),right(r) {}
};

BSTNode是二叉查找树的节点,它包含二叉查找树的几个基本信息:
(01) key -- 它是关键字,是用来对二叉查找树的节点进行排序的。
(02) left -- 它指向当前节点的左孩子。
(03) right -- 它指向当前节点的右孩子。
(04) parent -- 它指向当前节点的父结点。

1.2 二叉树操作

template <class T>
class BSTree {private:BSTNode<T> *mRoot;    // 根结点public:BSTree();~BSTree();// 前序遍历"二叉树"void preOrder();// 中序遍历"二叉树"void inOrder();// 后序遍历"二叉树"void postOrder();// (递归实现)查找"二叉树"中键值为key的节点BSTNode<T>* search(T key);// (非递归实现)查找"二叉树"中键值为key的节点BSTNode<T>* iterativeSearch(T key);// 查找最小结点:返回最小结点的键值。
        T minimum();// 查找最大结点:返回最大结点的键值。
        T maximum();// 找结点(x)的后继结点。即,查找"二叉树中数据值大于该结点"的"最小结点"。BSTNode<T>* successor(BSTNode<T> *x);// 找结点(x)的前驱结点。即,查找"二叉树中数据值小于该结点"的"最大结点"。BSTNode<T>* predecessor(BSTNode<T> *x);// 将结点(key为节点键值)插入到二叉树中void insert(T key);// 删除结点(key为节点键值)void remove(T key);// 销毁二叉树void destroy();// 打印二叉树void print();private:// 前序遍历"二叉树"void preOrder(BSTNode<T>* tree) const;// 中序遍历"二叉树"void inOrder(BSTNode<T>* tree) const;// 后序遍历"二叉树"void postOrder(BSTNode<T>* tree) const;// (递归实现)查找"二叉树x"中键值为key的节点BSTNode<T>* search(BSTNode<T>* x, T key) const;// (非递归实现)查找"二叉树x"中键值为key的节点BSTNode<T>* iterativeSearch(BSTNode<T>* x, T key) const;// 查找最小结点:返回tree为根结点的二叉树的最小结点。BSTNode<T>* minimum(BSTNode<T>* tree);// 查找最大结点:返回tree为根结点的二叉树的最大结点。BSTNode<T>* maximum(BSTNode<T>* tree);// 将结点(z)插入到二叉树(tree)中void insert(BSTNode<T>* &tree, BSTNode<T>* z);// 删除二叉树(tree)中的结点(z),并返回被删除的结点BSTNode<T>* remove(BSTNode<T>* &tree, BSTNode<T> *z);// 销毁二叉树void destroy(BSTNode<T>* &tree);// 打印二叉树void print(BSTNode<T>* tree, T key, int direction);
};

BSTree是二叉树。它包含二叉查找树的根节点和二叉查找树的操作。二叉查找树的操作中有许多重载函数,例如insert()函数,其中一个是内部接口,另一个是提供给外部的接口。

2 遍历

这里讲解前序遍历、中序遍历、后序遍历3种方式。

2.1 前序遍历
若二叉树非空,则执行以下操作:
(01) 访问根结点;
(02) 先序遍历左子树;
(03) 先序遍历右子树。

前序遍历代码

template <class T>
void BSTree<T>::preOrder(BSTNode<T>* tree) const
{if(tree != NULL){cout<< tree->key << " " ;preOrder(tree->left);preOrder(tree->right);}
}template <class T>
void BSTree<T>::preOrder()
{preOrder(mRoot);
}

2.2 中序遍历

若二叉树非空,则执行以下操作:
(01) 中序遍历左子树;
(02) 访问根结点;
(03) 中序遍历右子树。

中序遍历代码

template <class T>
void BSTree<T>::inOrder(BSTNode<T>* tree) const
{if(tree != NULL){inOrder(tree->left);cout<< tree->key << " " ;inOrder(tree->right);}
}template <class T>
void BSTree<T>::inOrder()
{inOrder(mRoot);
}

2.3 后序遍历

若二叉树非空,则执行以下操作:
(01) 后序遍历左子树;
(02) 后序遍历右子树;
(03) 访问根结点。

后序遍历代码

template <class T>
void BSTree<T>::postOrder(BSTNode<T>* tree) const
{if(tree != NULL){postOrder(tree->left);postOrder(tree->right);cout<< tree->key << " " ;}
}template <class T>
void BSTree<T>::postOrder()
{postOrder(mRoot);
}

看看下面这颗树的各种遍历方式:

对于上面的二叉树而言,
(01) 前序遍历结果: 3 1 2 5 4 6
(02) 中序遍历结果: 1 2 3 4 5 6 
(03) 后序遍历结果: 2 1 4 6 5 3

3. 查找

递归版本的代码

template <class T>
BSTNode<T>* BSTree<T>::search(BSTNode<T>* x, T key) const
{if (x==NULL || x->key==key)return x;if (key < x->key)return search(x->left, key);elsereturn search(x->right, key);
}template <class T>
BSTNode<T>* BSTree<T>::search(T key)
{search(mRoot, key);
}

非递归版本的代码

template <class T>
BSTNode<T>* BSTree<T>::iterativeSearch(BSTNode<T>* x, T key) const
{while ((x!=NULL) && (x->key!=key)){if (key < x->key)x = x->left;elsex = x->right;}return x;
}template <class T>
BSTNode<T>* BSTree<T>::iterativeSearch(T key)
{iterativeSearch(mRoot, key);
}

4. 最大值和最小值

查找最大值的代码

template <class T>
BSTNode<T>* BSTree<T>::maximum(BSTNode<T>* tree)
{if (tree == NULL)return NULL;while(tree->right != NULL)tree = tree->right;return tree;
}template <class T>
T BSTree<T>::maximum()
{BSTNode<T> *p = maximum(mRoot);if (p != NULL)return p->key;return (T)NULL;
}

查找最小值的代码

template <class T>
BSTNode<T>* BSTree<T>::minimum(BSTNode<T>* tree)
{if (tree == NULL)return NULL;while(tree->left != NULL)tree = tree->left;return tree;
}template <class T>
T BSTree<T>::minimum()
{BSTNode<T> *p = minimum(mRoot);if (p != NULL)return p->key;return (T)NULL;
}

5. 前驱和后继

节点的前驱:是该节点的左子树中的最大节点。
节点的后继:是该节点的右子树中的最小节点。

查找前驱节点的代码

/* * 找结点(x)的前驱结点。即,查找"二叉树中数据值小于该结点"的"最大结点"。*/
template <class T>
BSTNode<T>* BSTree<T>::predecessor(BSTNode<T> *x)
{// 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。if (x->left != NULL)return maximum(x->left);// 如果x没有左孩子。则x有以下两种可能:// (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。// (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。BSTNode<T>* y = x->parent;while ((y!=NULL) && (x==y->left)){x = y;y = y->parent;}return y;
}

查找后继节点的代码

/* * 找结点(x)的后继结点。即,查找"二叉树中数据值大于该结点"的"最小结点"。*/
template <class T>
BSTNode<T>* BSTree<T>::successor(BSTNode<T> *x)
{// 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。if (x->right != NULL)return minimum(x->right);// 如果x没有右孩子。则x有以下两种可能:// (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。// (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。BSTNode<T>* y = x->parent;while ((y!=NULL) && (x==y->right)){x = y;y = y->parent;}return y;
}

6. 插入

插入节点的代码

/* * 将结点插入到二叉树中** 参数说明:*     tree 二叉树的根结点*     z 插入的结点*/
template <class T>
void BSTree<T>::insert(BSTNode<T>* &tree, BSTNode<T>* z)
{BSTNode<T> *y = NULL;BSTNode<T> *x = tree;// 查找z的插入位置while (x != NULL){y = x;if (z->key < x->key)x = x->left;elsex = x->right;}z->parent = y;if (y==NULL)tree = z;else if (z->key < y->key)y->left = z;elsey->right = z;
}/* * 将结点(key为节点键值)插入到二叉树中** 参数说明:*     tree 二叉树的根结点*     key 插入结点的键值*/
template <class T>
void BSTree<T>::insert(T key)
{BSTNode<T> *z=NULL;// 如果新建结点失败,则返回。if ((z=new BSTNode<T>(key,NULL,NULL,NULL)) == NULL)return ;insert(mRoot, z);
}

注:本文实现的二叉查找树是允许插入相同键值的节点的。若想禁止二叉查找树中插入相同键值的节点,可以参考"二叉查找树(一)之 图文解析 和 C语言的实现"中的插入函数进行修改。

7. 删除

删除节点的代码

/* * 删除结点(z),并返回被删除的结点** 参数说明:*     tree 二叉树的根结点*     z 删除的结点*/
template <class T>
BSTNode<T>* BSTree<T>::remove(BSTNode<T>* &tree, BSTNode<T> *z)
{BSTNode<T> *x=NULL;BSTNode<T> *y=NULL;if ((z->left == NULL) || (z->right == NULL) )y = z;elsey = successor(z);if (y->left != NULL)x = y->left;elsex = y->right;if (x != NULL)x->parent = y->parent;if (y->parent == NULL)tree = x;else if (y == y->parent->left)y->parent->left = x;elsey->parent->right = x;if (y != z) z->key = y->key;return y;
}/* * 删除结点(z),并返回被删除的结点** 参数说明:*     tree 二叉树的根结点*     z 删除的结点*/
template <class T>
void BSTree<T>::remove(T key)
{BSTNode<T> *z, *node; if ((z = search(mRoot, key)) != NULL)if ( (node = remove(mRoot, z)) != NULL)delete node;
}

8. 打印

打印二叉查找树的代码

/** 打印"二叉查找树"** key        -- 节点的键值 * direction  --  0,表示该节点是根节点;*               -1,表示该节点是它的父结点的左孩子;*                1,表示该节点是它的父结点的右孩子。*/
template <class T>
void BSTree<T>::print(BSTNode<T>* tree, T key, int direction)
{if(tree != NULL){if(direction==0)    // tree是根节点cout << setw(2) << tree->key << " is root" << endl;else                // tree是分支节点cout << setw(2) << tree->key << " is " << setw(2) << key << "'s "  << setw(12) << (direction==1?"right child" : "left child") << endl;print(tree->left, tree->key, -1);print(tree->right,tree->key,  1);}
}template <class T>
void BSTree<T>::print()
{if (mRoot != NULL)print(mRoot, mRoot->key, 0);
}

9. 销毁

销毁二叉查找树的代码

/** 销毁二叉树*/
template <class T>
void BSTree<T>::destroy(BSTNode<T>* &tree)
{if (tree==NULL)return ;if (tree->left != NULL)return destroy(tree->left);if (tree->right != NULL)return destroy(tree->right);delete tree;tree=NULL;
}template <class T>
void BSTree<T>::destroy()
{destroy(mRoot);
}

二叉查找树的C++实现(完整源码)

二叉查找树的C++实现文件(BSTree.h)

 View Code

二叉查找树的C++测试程序(BSTreeTest.cpp)

 View Code

关于二叉查找树的C++实现有两点需要补充说明的:
第1点:采用了STL模板。因此,二叉查找树支持任意数据类型。
第2点:将二叉查找树的"声明"和"实现"都位于BSTree.h中。这是因为,在二叉查找树的实现采用了模板;而C++编译器不支持对模板的分离式编译!

二叉查找树的C++测试程序

上面的BSTreeTest.c是二叉查找树树的测试程序,运行结果如下:

== 依次添加: 1 5 4 3 2 6
== 前序遍历: 1 5 4 3 2 6
== 中序遍历: 1 2 3 4 5 6
== 后序遍历: 2 3 4 6 5 1
== 最小值: 1
== 最大值: 6
== 树的详细信息: 1 is root5 is  1's  right child4 is  5's   left child3 is  4's   left child2 is  3's   left child6 is  5's  right child== 删除根节点: 3
== 中序遍历: 1 2 4 5 6 

下面对测试程序的流程进行分析!

(01) 新建"二叉查找树"root。

(02) 向二叉查找树中依次插入1,5,4,3,2,6 。如下图所示:

(03) 遍历和查找
插入1,5,4,3,2,6之后,得到的二叉查找树如下:

前序遍历结果: 1 5 4 3 2 6 
中序遍历结果: 1 2 3 4 5 6 
后序遍历结果: 2 3 4 6 5 1 
最小值是1,而最大值是6。

(04) 删除节点4。如下图所示:

(05) 重新遍历该二叉查找树。
中序遍历结果: 1 2 4 5 6

二叉查找树(二)之 C++的实现相关推荐

  1. 【数据结构】二叉查找树/二叉搜索树BST(附相关C++代码)

    文章目录 BST相关概念 BST如何添加节点 BST如何遍历 BST如何求最值 BST如何删除节点 BST如何查找节点 如何验证一棵树是BST 本文内容将主要介绍二叉查找树的相关概念,与关于二叉查找树 ...

  2. 二叉查找树,二叉平衡树

    一.二叉查找树 看大佬: 二叉查找树_3Code_Love的博客-CSDN博客_二叉查找树 二.二叉平衡树 看大佬: 平衡二叉树_月雲之霄的博客-CSDN博客_平衡二叉树

  3. 二叉查找树(一)之 C语言的实现

    二叉查找树(一)之 图文解析 和 C语言的实现 概要 本章先对二叉树的相关理论知识进行介绍,然后给出C语言的详细实现.关于二叉树的学习,需要说明的是:它并不难,不仅不难,而且它非常简单.初次接触树的时 ...

  4. 《算法导论》第十二章——二叉搜索树

      虽然写这个博客主要目的是为了给我自己做一个思路记忆录,但是如果你恰好点了进来,那么先对你说一声欢迎.我并不是什么大触,只是一个菜菜的学生,如果您发现了什么错误或者您对于某些地方有更好的意见,非常欢 ...

  5. 二叉查找树的平衡(DSW)

    二叉查找树的平衡(DSW) 一.有序数组创建二叉查找树 二.DSW算法(Day–Stout–Warren algorithm) 2.1 第一阶段:右旋转形成主链 2.2 第二阶段:左旋转转换为平衡树 ...

  6. 数据结构--伸展树(伸展树构建二叉搜索树)-学习笔记

    2019/7/16更新:封装SplayTree进入class:例题:http://poj.org/problem?id=3622 一个伸展树的板子: #include<stdio.h> # ...

  7. 【algods】4.树和二叉树、完全二叉树、满二叉树、二叉查找树、平衡二叉树、堆、哈夫曼树、散列表...

    本博客内容耗时4天整理,如果需要转载,请注明出处,谢谢. 1.树 1.1树的定义 在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结 ...

  8. 二叉查找树(一)之 图文解析 和 C语言的实现

    本文转载至http://www.cnblogs.com/skywang12345/p/3576328.html 二叉查找树(一)之 图文解析 和 C语言的实现 概要 本章先对二叉树的相关理论知识进行介 ...

  9. 浙江大学数据结构(4.1二叉搜索树)

    查找问题: 静态查找(只有查找操作)与动态查找(查找.插入.删除操作) 针对动态查找,数据如何组织? 什么是二叉搜索树? 二叉搜索树(Binary Search Tree),也称二叉排序树或二叉查找树 ...

最新文章

  1. 【转】ASP.NET AJAX入门系列
  2. 数据的中心化和标准化
  3. 2引擎帮助文档_Simcenter Amesim 16液压部分帮助文档中英文对照(2)
  4. 浅析MySQL二进制日志
  5. 是否需要配置环境变量,比如maven,jdk等
  6. spring的@primary和@qualifier注解解决一个接口多个实现的注入问题
  7. 海量小文件的开源存储方案选型建议
  8. windows server 2003 IIS6.0下session问题
  9. 李永乐复习全书线性代数 第三章 向量
  10. excel转置怎么操作_PDF转excel怎么操作?这个方法一定要熟知!
  11. 安装及使用RSSHub
  12. 看机器学习如何预测债券收益率
  13. Python-集合练习(协助学生做问卷调查)
  14. vant vant-list碰到的坑
  15. 科研绘图(Matplotlib.pyplot)
  16. 一番谈话,深自反思。
  17. POJ 1723 士兵排队 C语言实现
  18. Django学习笔记(下)
  19. 将一根木棍分成三段,求这三段构成三角形的概率 和  在一圆周上任意取三个点构成锐角三角形的概率是多少
  20. 【论文阅读】Geography-Aware Sequential Location Recommendation

热门文章

  1. 探秘JVM(二)——编译进行时
  2. Shell编程进阶 1.7 case选择
  3. xpool, cpool,epoo
  4. 本科生怎样发表论文?
  5. ios:CGContextRef 渲染中文问题
  6. 对象化下的编程——字段
  7. [ZZ88]送给即将毕业奔三的男人们的16条忠告
  8. windows XP安装配置Perl Apache
  9. stm32之 GPIO_Remap_SWJ_Disable之后无法使用swd下载 程序解决方法
  10. 中断处理函数中自旋锁的应用