文章中部分内容和思路来自《数据结构、算法与应用 c++语言描述》
二叉搜索树定义
是一颗二叉树,可能为空;一颗非空的二叉搜索树应满足以下条件:
1) 每个元素有一个关键字,并且任意两个元素关键字不同;因此,所有元素的关键字唯一
2) 在根节点的左子树中,元素的关键字(若有)都小于根节点的关键字
3) 在根节点的右子树中,元素的关键字(若有)都大于根节点的关键字
4) 根节点的左右子树也都是二叉搜索树
图14-1中除a)图外都是二叉搜索树
[ps:条件1可以去掉,然后用小于等于替代2中小于,大于等于替代3中大于,可以构成有重复值的二叉搜索树]
二叉搜索树插入
示意:
代码:
template<class T>
void BinarySearchTree<T>::insert(const T &value, BSTNODE<T> *&node)
{
if (NULL == node)
{
node = new BSTNODE<T>;
node->element = value;
node->leftchild = NULL;
node->rightchild = NULL;
}
else if (node->element > value)
{
insert(value, node->leftchild);
}
else if (node->element < value)
{
insert(value, node->rightchild);
}
else
{
// 无重复值节点
}
}
二叉搜索树删除
原理及示意:
分三种情况,1)删除的节点是叶子节点 2)删除的节点只有一个孩子节点 3)删除的节点有两个孩子节点
第一种情况比较简单,这里不作解释[删除节点释放内存即可]
第二种情况也比较简单,以图b为例,若删除节点5,则使其父节点指向其子节点,删除节点释放内存即可
第三种情况复杂一些,以图a为例,若删除节点40,则取节点左子树中最大节点35或右子树最小节点60,替换该节点值,并删除35/60节点释放内存即可
代码:
template<class T>
void BinarySearchTree<T>::remove(const T &value, BSTNODE<T> *&node)
{
// 空节点直接返回
if (NULL == node)
return;
if (value < node->element)
remove(value, node->leftchild);
else if (value > node->element)
remove(value, node->rightchild);
else
{
// 重点:
// 若节点有两个孩子,则先将左树的最大节点/右树的最小节点替换当前节点,然后删除左树最大节点/右树最小节点
// 若节点只有一个孩子,则用孩子节点替换当前节点,并使当前节点指向孩子节点的孩子节点,删除孩子节点
if (node->leftchild != NULL && node->rightchild != NULL) // 待删除的节点有两个孩子
{
node->element = findMax(node->leftchild)->element;
remove(node->element, node->leftchild);
}
else
{
// 先将当前节点指向
BSTNODE<T> *tmpNode = node;
node = (node->leftchild != NULL) ? node->leftchild : node->rightchild;
delete tmpNode;
tmpNode = NULL;
}
}
}
索引二叉搜索树
源于普通二叉搜索树,只是在每个节点上添加一个leftSize域。域的值是该节点左子树元素个数
二叉搜索树操作完整例子代码
---------
strdef.h
---------
#ifndef STRDEF_H
#define STRDEF_H
template <class T>
struct BSTNode
{
T element; // 值域
BSTNode* leftchild; // 左孩子
BSTNode* rightchild; // 右孩子
};
template <class T>
using BSTNODE = BSTNode<T>;
#endif // STRDEF_H
------------------
BinarySearchTree.h
------------------
#ifndef BINARYSEARCHTREE_H
#define BINARYSEARCHTREE_H
#include "strdef.h"
template <class T>
class BinarySearchTree
{
public:
BinarySearchTree();
~BinarySearchTree();
public:
bool contains(const T& value); // 搜索
void insert(const T& value); // 插入
void remove(const T& value); // 删除
void printNodes(); // 打印全部节点,前序
BSTNODE<T> *findMax(BSTNODE<T> *node); // 查找最大
private:
bool contains(const T &value, BSTNODE<T> *node);
void insert(const T& value, BSTNODE<T> *&node);
void remove(const T& value, BSTNODE<T> *&node);
void releaseNode(BSTNODE<T> *node);
void printNodes(BSTNODE<T> *node);
private:
BSTNODE<T> *_root;
};
#endif // BINARYSEARCHTREE_H
--------------------
BinarySearchTree.cpp
--------------------
#include "BinarySearchTree.h"
#include <QDebug>
template<class T>
BinarySearchTree<T>::BinarySearchTree()
{
_root = NULL;
}
template<class T>
BinarySearchTree<T>::~BinarySearchTree()
{
releaseNode(_root);
}
template<class T>
bool BinarySearchTree<T>::contains(const T &value)
{
return contains(value, _root);
}
template<class T>
void BinarySearchTree<T>::insert(const T &value)
{
insert(value, _root);
}
template<class T>
void BinarySearchTree<T>::remove(const T &value)
{
remove(value, _root);
}
template<class T>
void BinarySearchTree<T>::printNodes()
{
printNodes(_root);
}
template<class T>
BSTNODE<T> *BinarySearchTree<T>::findMax(BSTNODE<T> *node)
{
if (NULL == node->rightchild)
return node;
else
return findMax(node->rightchild);
}
template<class T>
bool BinarySearchTree<T>::contains(const T &value, BSTNODE<T> *node)
{
if (node)
{
if (node->element == value)
{
return true;
}
else if (value < node->element)
{
return contains(value, node->leftchild);
}
else
{
return contains(value, node->rightchild);
}
}
return false;
}
template<class T>
void BinarySearchTree<T>::insert(const T &value, BSTNODE<T> *&node)
{
if (NULL == node)
{
node = new BSTNODE<T>;
node->element = value;
node->leftchild = NULL;
node->rightchild = NULL;
}
else if (node->element > value)
{
insert(value, node->leftchild);
}
else if (node->element < value)
{
insert(value, node->rightchild);
}
else
{
// 无重复值节点
}
}
template<class T>
void BinarySearchTree<T>::remove(const T &value, BSTNODE<T> *&node)
{
// 空节点直接返回
if (NULL == node)
return;
if (value < node->element)
remove(value, node->leftchild);
else if (value > node->element)
remove(value, node->rightchild);
else
{
// 重点:
// 若节点有两个孩子,则先将左树的最大节点/右树的最小节点替换当前节点,然后删除左树最大节点/右树最小节点
// 若节点只有一个孩子,则用孩子节点替换当前节点,并使当前节点指向孩子节点的孩子节点,删除孩子节点
if (node->leftchild != NULL && node->rightchild != NULL) // 待删除的节点有两个孩子
{
node->element = findMax(node->leftchild)->element;
remove(node->element, node->leftchild);
}
else
{
// 先将当前节点指向
BSTNODE<T> *tmpNode = node;
node = (node->leftchild != NULL) ? node->leftchild : node->rightchild;
delete tmpNode;
tmpNode = NULL;
}
}
}
template<class T>
void BinarySearchTree<T>::releaseNode(BSTNODE<T> *node)
{
if (node)
{
releaseNode(node->leftchild);
releaseNode(node->rightchild);
delete node;
}
node = NULL;
}
template<class T>
void BinarySearchTree<T>::printNodes(BSTNODE<T> *node)
{
if (node)
{
qDebug() << node->element;
printNodes(node->leftchild);
printNodes(node->rightchild);
}
}
--------
main.cpp
--------
#include <QCoreApplication>
#include "BinarySearchTree.cpp"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
BinarySearchTree<int> bst;
// 测试数据
bst.insert(30);
bst.insert(5);
bst.insert(40);
bst.insert(2);
bst.insert(35);
bst.insert(80);
bst.insert(32);
bst.insert(60);
bst.insert(85);
bst.insert(31);
bst.insert(33);
// 测试插入
bst.printNodes();
// 测试搜索
qDebug() << bst.contains(20);
qDebug() << bst.contains(32);
// // 测试删除叶子节点
// qDebug() << "测试删除叶子节点";
// bst.remove(2);
// bst.printNodes();
// // 测试删除单孩子节点
// qDebug() << "测试删除单孩子节点";
// bst.remove(5);
// bst.printNodes();
// 测试删除双孩子节点
qDebug() << "测试删除双孩子节点";
bst.remove(40);
bst.printNodes();
return a.exec();
}