二叉查找树(二)之 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)
二叉查找树的C++测试程序(BSTreeTest.cpp)
关于二叉查找树的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++的实现相关推荐
- 【数据结构】二叉查找树/二叉搜索树BST(附相关C++代码)
文章目录 BST相关概念 BST如何添加节点 BST如何遍历 BST如何求最值 BST如何删除节点 BST如何查找节点 如何验证一棵树是BST 本文内容将主要介绍二叉查找树的相关概念,与关于二叉查找树 ...
- 二叉查找树,二叉平衡树
一.二叉查找树 看大佬: 二叉查找树_3Code_Love的博客-CSDN博客_二叉查找树 二.二叉平衡树 看大佬: 平衡二叉树_月雲之霄的博客-CSDN博客_平衡二叉树
- 二叉查找树(一)之 C语言的实现
二叉查找树(一)之 图文解析 和 C语言的实现 概要 本章先对二叉树的相关理论知识进行介绍,然后给出C语言的详细实现.关于二叉树的学习,需要说明的是:它并不难,不仅不难,而且它非常简单.初次接触树的时 ...
- 《算法导论》第十二章——二叉搜索树
虽然写这个博客主要目的是为了给我自己做一个思路记忆录,但是如果你恰好点了进来,那么先对你说一声欢迎.我并不是什么大触,只是一个菜菜的学生,如果您发现了什么错误或者您对于某些地方有更好的意见,非常欢 ...
- 二叉查找树的平衡(DSW)
二叉查找树的平衡(DSW) 一.有序数组创建二叉查找树 二.DSW算法(Day–Stout–Warren algorithm) 2.1 第一阶段:右旋转形成主链 2.2 第二阶段:左旋转转换为平衡树 ...
- 数据结构--伸展树(伸展树构建二叉搜索树)-学习笔记
2019/7/16更新:封装SplayTree进入class:例题:http://poj.org/problem?id=3622 一个伸展树的板子: #include<stdio.h> # ...
- 【algods】4.树和二叉树、完全二叉树、满二叉树、二叉查找树、平衡二叉树、堆、哈夫曼树、散列表...
本博客内容耗时4天整理,如果需要转载,请注明出处,谢谢. 1.树 1.1树的定义 在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结 ...
- 二叉查找树(一)之 图文解析 和 C语言的实现
本文转载至http://www.cnblogs.com/skywang12345/p/3576328.html 二叉查找树(一)之 图文解析 和 C语言的实现 概要 本章先对二叉树的相关理论知识进行介 ...
- 浙江大学数据结构(4.1二叉搜索树)
查找问题: 静态查找(只有查找操作)与动态查找(查找.插入.删除操作) 针对动态查找,数据如何组织? 什么是二叉搜索树? 二叉搜索树(Binary Search Tree),也称二叉排序树或二叉查找树 ...
最新文章
- 【转】ASP.NET AJAX入门系列
- 数据的中心化和标准化
- 2引擎帮助文档_Simcenter Amesim 16液压部分帮助文档中英文对照(2)
- 浅析MySQL二进制日志
- 是否需要配置环境变量,比如maven,jdk等
- spring的@primary和@qualifier注解解决一个接口多个实现的注入问题
- 海量小文件的开源存储方案选型建议
- windows server 2003 IIS6.0下session问题
- 李永乐复习全书线性代数 第三章 向量
- excel转置怎么操作_PDF转excel怎么操作?这个方法一定要熟知!
- 安装及使用RSSHub
- 看机器学习如何预测债券收益率
- Python-集合练习(协助学生做问卷调查)
- vant vant-list碰到的坑
- 科研绘图(Matplotlib.pyplot)
- 一番谈话,深自反思。
- POJ 1723 士兵排队 C语言实现
- Django学习笔记(下)
- 将一根木棍分成三段,求这三段构成三角形的概率 和 在一圆周上任意取三个点构成锐角三角形的概率是多少
- 【论文阅读】Geography-Aware Sequential Location Recommendation