二叉树中使用最广泛的就是搜索二叉树;
搜索二叉树还有其它名称:二叉排序树、二叉查找树等;
1.搜索二叉树的优点
1】有很好的查询性能
2】有很好的新增和删除的性能
3】若左子树不空,则左子树上所有结点的值均小于它的根结点的值
4】若右子树不空,则右子树上所有结点的值均大于它的根结点的值
5】左、右子树也分别为二叉排序树
如图:典型的搜索二叉树
.png)
对搜索二叉树进行中序遍历的结果就是元素从小到大排序后的结果;
如果二叉树中的元素是基本类型int、short等,可以直接操作;
如果元素是对象,那么该对象的类必须重载运算符><==,因为搜索二叉树就是通过这些运算符来排序的;
搜索二叉树里面不允许有重复元素;
2.搜索二叉树的操作
1)新增元素
例如:在上图的搜索二叉树中新增节点8
比较8和15,因为8<15,所以应该放左子树,如果左子树的节点没值就直接写到这里,有值就要继续比较;
比较8和5,8>5,放右子树;
8<12,放左边;
8<10,放左边;
8>6,放右边;
8>7,放右边,7的右子树是空的,因此8放这里;
因此8应该放在以7为父节点的右子树中;
例如:新增18
经过一系列查找,树中原本有一个18;
因为搜索二叉树中不允许重复元素,因此直接返回;
2)查找元素
例如:从上面图的二叉树中找6
6<15,从左找;
6>5,往右找;
6<12,往左找;
6<10,往左找,然后找到了;
例如:找21
21>15,从右找;
21>20,往右找;
21<23,往左找,然后左边没有了,因此找不到返回空;
3)删除元素
情况一:叶子节点
1】删除该节点
2】将父节点(左或者右)指针置NULL
例如:删除3,直接删除3,然后5的左指针指向NULL;
情况2:只有一个子树
1】删除该节点
2】将父节点(左或者右)指针指向子树
例如:删除6,直接删除6,然后将10的左指针指向7;
情况3:左右子树都有
方法1)
1】用右子树最小的节点取代源节点
2】再递归删除最小节点
例如:删除5
先从5的右边找到最小的6;
不删除5而是将节点处的值从5换为6;
再删除原来的6;
原理:
右边最小的数一定比根节点大,也比左边任何一个数大;
右边最小的数只可能是叶子节点,或只有右子树,删除操作简单;
方法2)
1】用左子树最大的节点取代源节点
2】删除最大节点
3.搜索二叉树的实现
头文件:
#ifndef SEARCHTREE_H
#define SEARCHTREE_H
#include "stdio.h"
#include "stdlib.h"
#include "windows.h"
#define SUCCESS 1 // 执行成功
#define FAIL -1 // 执行失败
template<class T>
class TreeNode{
public:
T element; //当前节点存储的数据
TreeNode<T>* pLeft; //指向左子节点的指针
TreeNode<T>* pRight; //指向右子节点的指针
TreeNode<T>* pParent; //指向父结点的指针
TreeNode(T& ele){
//初始化Node节点
memset(&element,0,sizeof(TreeNode));
//为元素赋值
memcpy(&element,&ele,sizeof(T));
pLeft = pRight = pParent = NULL;
}
//重载== 比较两结点是否相等
bool operator==(TreeNode<T>* node){
return node->element == element?true:false;
}
};
template<class T>
class BSortTree{
public:
BSortTree(); //构造函数
~BSortTree(); //析构函数
public: //判断树是否为空
bool IsEmpty(); //新增节点
DWORD Insert(T element); //删除节点
void Delete(T element);
TreeNode<T>* Search(T element); //查找节点
void InOrderTraverse(TreeNode<T>* pNode); //中序遍历
void PreOrderTraverse(TreeNode<T>* pNode); //前序遍历
void PostOrderTraverse(TreeNode<T>* pNode); //后序遍历
private:
TreeNode<T>* GetMaxNode(TreeNode<T>* pNode); //获取以pNode为根的最大节点
TreeNode<T>* GetMinNode(TreeNode<T>* pNode); //获取以pNode为根的最小节点
TreeNode<T>* SearchNode(TreeNode<T>* pNode,T element); //获取以pNode为根的最小节点
DWORD InsertNode(T element, TreeNode<T>* pNode); //新增节点
TreeNode<T>* DeleteNode(T element, TreeNode<T>* pNode); //删除节点
void Clear(TreeNode<T>* pNode); //清空所有节点
private:
TreeNode<T>* m_pRoot; //根结点指针
int size; //树中元素总个数
};
template<class T>
BSortTree<T>::BSortTree()
{
m_pRoot = NULL;
size = 0;
}
template<class T>
BSortTree<T>::~BSortTree(){
Clear(m_pRoot);
}
template<class T>
DWORD BSortTree<T>::Insert(T element)
{
//如果根节点为空
if ( !m_pRoot )
{
m_pRoot = new TreeNode<T>(element);
size++;
return SUCCESS;
}
//如果根节点不为空
return InsertNode(element, m_pRoot);
}
template<class T>
DWORD BSortTree<T>::InsertNode(T element, TreeNode<T>* pNode)
{
//将元素封装到节点中
TreeNode<T>* pNewNode = new TreeNode<T>(element);
//如果element == 当前节点 直接返回
if(element == pNode->element)
{
return SUCCESS;
}
//如果pNode的左子节点为NULL 并且element < 当前节点
if(pNode->pLeft == NULL && element < pNode->element)
{
pNode->pLeft = pNewNode;
pNewNode->pParent = pNode;
size++;
return SUCCESS;
}
//如果pNode的右子节点为NULL 并且element > 当前节点
if(pNode->pRight == NULL && element > pNode->element){
pNode->pRight = pNewNode;
pNewNode->pParent = pNode;
size++;
return SUCCESS;
}
//如果element<当前节点 且当前节点的左子树不为空
if(element < pNode->element)
{
InsertNode(element,pNode->pLeft);
}
else
{
InsertNode(element,pNode->pRight);
}
return SUCCESS;
}
template<class T>
void BSortTree<T>::Clear(TreeNode<T>* pNode)
{
if(pNode!=NULL)
{
Clear(pNode->pLeft);
Clear(pNode->pRight);
delete pNode;
pNode=NULL;
}
}
template<class T>
bool BSortTree<T>::IsEmpty()
{
return size==0?true:false;
}
template<class T>
TreeNode<T>* BSortTree<T>::Search(T element)
{
return SearchNode(m_pRoot, element);
}
template<class T>
TreeNode<T>* BSortTree<T>::SearchNode(TreeNode<T>* pNode,T element)
{
if(pNode == NULL) //如果节点为NULL
{
return NULL;
}
else if(element == pNode->element) //如果相等
{
return pNode;
} //如果比节点的元素小 向左找
else if(element < pNode->element)
{
return SearchNode(pNode->pLeft,element);
}
else //如果比节点的元素大 向右找
{
return SearchNode(pNode->pRight,element);
}
}
template<class T>
void BSortTree<T>::Delete(T element)
{
//先找到元素所在节点
TreeNode<T>* node = Search(element);
if(node == NULL){ //如果没有该元素则直接返回
return;
}
TreeNode<T>* parent = node->pParent;
if(!node->pLeft && !node->pRight){ //如果是叶子节点直接删除
if(parent->pLeft == node){ //判断是父节点的左子树还是右子树
parent->pLeft = NULL;
}else{
parent->pRight = NULL;
}
delete node;
}else if(!node->pLeft){ //如果只有一个子树,删除该节点并用子树代替该节点
if(parent->pLeft == node){ //判断是父节点的左子树还是右子树
parent->pLeft = node->pRight;
}else{
parent->pRight = node->pRight;
}
node->pRight->pParent = parent;
delete node;
}else if(!node->pRight){
if(parent->pLeft == node){ //判断是父节点的左子树还是右子树
parent->pLeft = node->pLeft;
}else{
parent->pRight = node->pLeft;
}
node->pLeft->pParent = parent;
delete node;
}else{ //如果目标节点左右子树都不为空
TreeNode<T>* min = node->pRight;
while(min->pLeft){
min = min->pLeft; //找到目标节点右子树中最小的元素
}
memcpy(node, min, sizeof(T)); //用右子树最小元素的值替换目标节点的值
TreeNode<T>* minParent = min->pParent; //删除最小元素
if(minParent->pLeft == min){
minParent->pLeft = min->pRight;
}else{
minParent->pRight = min->pRight;
}
if(min->pRight){
min->pRight->pParent = minParent;
}
delete min;
}
size--;
return;
}
//中序遍历
template<class T>
void BSortTree<T>::InOrderTraverse(TreeNode<T>* pNode){
if(pNode){
InOrderTraverse(pNode->pLeft);
printf("%d\t",pNode->element);
InOrderTraverse(pNode->pRight);
}
}
#endif
测试:
#include "SearchTree.h"
void fun()
{
//12 8 5 9 17 15 13
/*
12
8 17
5 9 15
13
*/
BSortTree<int> tree;
//插入
tree.Insert(12);
tree.Insert(8);
tree.Insert(5);
tree.Insert(9);
tree.Insert(17);
tree.Insert(15);
tree.Insert(13);
//查找特定元素
TreeNode<int>* p = tree.Search(9);
printf("%x %d\n",p,p->element);
//中序遍历
tree.InOrderTraverse(tree.Search(12));
printf("\n");
//删除元素8
tree.Delete(8);
tree.InOrderTraverse(tree.Search(12));
printf("\n");
}
void main(){
fun();
getchar();
}
结果:
.png)