本文已参与[新人创作礼]活动,一起开启掘金创作之路
二叉搜索树: 二叉树的一种,并且树中每个节点(x)左子树的关键字不大于x节点的关键字,右子树的关键字不小于x节点的关键字。
节点: 每个二叉搜索树的节点包含{left,right,p,key……}分别对应{左节点,右节点,父节点,关键字……[卫星数据]},在本文代码中,value代表key。
本文概要: 实现了如下二叉搜索树的一个封装类,分别包括
1、二叉搜索树的构建
2、前中后序遍历(前:p,left,right;中:left,p,right;后:left,right,p)
3、对应节点搜索
4、找到树中key最小/最大的节点
5、找到二叉搜索树中某个节点对应的前驱/后继(比其小的最大值/比其大的最小值)
6、二叉搜索树的插入
7、二叉搜索树的删除(这个较为复杂,后面有详解)
首先熟悉并实战一下:
Q:{6,5,2,5,7,8}构造成二叉搜索树;排列出其前中后序遍历的数组;6的前驱后继
A:
构造的二叉搜索树如上;
前序遍历:6,5,2,5,7,8
中序遍历:2,5,5,6,7,8
后序遍历:2,5,5,7,8,6
前驱:5
后继:7
Q: 再来一题难的,下图的前中后序遍历
A:
前序遍历:A,B,D,G,H,E,C,K,F,I,J
中序遍历:G,D,H,B,E,A,K,C,I,J,F
后序遍历:G,H,D,E,B,K,J,I,F,C,A
上代码(详解放在后面)
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
template<class T>
class TreeNode
{
public:
TreeNode *left;//做孩子
TreeNode *right;//右孩子
TreeNode *p;//父亲
T mValue;//该节点的值
TreeNode(){}
TreeNode(T value){
mValue = value;
left = NULL;
right = NULL;
p = NULL;
}
TreeNode(T value,TreeNode * left,TreeNode *right,TreeNode *parent){
mValue = value;
left = left;
right = right;
p = parent;
}
~TreeNode(){
}
};
template<class T>
class SearchTree
{
public:
SearchTree();//创建空树
SearchTree(TreeNode<T> a[]);//传入节点组创建树
SearchTree(T a[],int length);//传入节点值组,创建树
~SearchTree();
MidWalk();//中序遍历
FrontWalk();//前序遍历
BackWalk();//后序遍历
TreeNode<T> * Search(T value);//找到值相等的节点
TreeNode<T> * Minimum();//树中最小节点
TreeNode<T> * Maximum();//树中最大节点
TreeNode<T> * TreePredecessor(TreeNode<T> *node);//某节点的前任 狗头.jpg 小于该节点的 值最大节点
TreeNode<T> * TreeSuccessor(TreeNode<T> *node);//某节点的后驱 大于该节点的 值最小节点
string Insert(T value);//插入
string Delete(T value);//删除
private:
TreeNode<T> *root;
InsertInner(TreeNode<T> *insertNode,TreeNode<T> *parentNode);
MidWalkInner(TreeNode<T> *node);//中序遍历
FrontWalkInner(TreeNode<T> *node);//前序遍历
BackWalkInner(TreeNode<T> *node);//后序遍历
TreeNode<T> * SearchInner(TreeNode<T> *node,T value);//搜索
TreeNode<T> * MinimumInner(TreeNode<T> *node);//树中最小节点
TreeNode<T> * MaximumInner(TreeNode<T> *node);//树中最大节点
Transplant(TreeNode<T> *pNode,TreeNode<T> *subNode);//继承,subNode继承pNode原有的位置
string strTrue;//用于返回true的字符串
string strFalse;//用于返回false的字符串
string strNull;//用于返回null的字符串
};
template<class T>
SearchTree<T>::SearchTree()
{
strTrue = "true";
strFalse = "false";
strNull = "null";
}
template<class T>
SearchTree<T>::SearchTree(TreeNode<T> a[])
{
strTrue = "true";
strFalse = "false";
strNull = "null";
}
template<class T>
SearchTree<T>::SearchTree(T a[],int length)
{
int i = 0;
TreeNode<T> *rootNd = new TreeNode<T>(a[i]);
root = rootNd;
i++;
//大体思路,循环遍历
//小于找左孩子
//大于找右孩子
//孩子为空直接放置
//如果i==0 将root指针指向该节点
for (int i=1;i<length;i++)
{
Insert(a[i]);
}
strTrue = "true";
strFalse = "false";
strNull = "null";
}
template<class T>
SearchTree<T>::MidWalk()
{
TreeNode<T> *node = root;
MidWalkInner(node);
cout<<endl;
}
template<class T>
SearchTree<T>::MidWalkInner(TreeNode<T> *node)
{
if (node!=NULL)
{
MidWalkInner(node->left);
cout<<node->mValue<<" ";
MidWalkInner(node->right);
}
}
template<class T>
SearchTree<T>::FrontWalk()
{
TreeNode<T> *node = root;
FrontWalkInner(node);
}
template<class T>
SearchTree<T>::FrontWalkInner(TreeNode<T> *node)
{
if (node!=NULL)
{
cout<<node->mValue<<endl;
FrontWalkInner(node->left);
FrontWalkInner(node->right);
}
}
template<class T>
SearchTree<T>::BackWalk()
{
TreeNode<T> *node = root;
BackWalkInner(node);
}
template<class T>
SearchTree<T>::BackWalkInner(TreeNode<T> *node)
{
if (node!=NULL)
{
BackWalkInner(node->left);
BackWalkInner(node->right);
cout<<node->mValue<<endl;
}
}
template<class T>
TreeNode<T> * SearchTree<T>::Search(T value)
{
TreeNode<T> *node = root;
TreeNode<T> *matchNode = SearchInner(node,value);
return matchNode;
}
template<class T>
TreeNode<T> * SearchTree<T>::SearchInner(TreeNode<T> *node,T value)
{
if (node==NULL || node->mValue == value)
{
if (node==NULL) //对于找不到的给一个-1以示空
return new TreeNode<T>(-1);
else
return node;
}
if (value < node->mValue)
SearchInner(node->left,value);
else
SearchInner(node->right,value);
}
template<class T>
string SearchTree<T>::Insert(T value)
{
TreeNode<T> *node = new TreeNode<T>(value);
InsertInner(node,root);
return strTrue;
}
template<class T>
TreeNode<T> * SearchTree<T>::Minimum()
{
TreeNode<T> *node = root;
while(node->left!=NULL)
node = node->left;
return node;
}
template<class T>
TreeNode<T> * SearchTree<T>::MinimumInner(TreeNode<T> *node)
{
while(node->left!=NULL)
node = node->left;
return node;
}
template<class T>
TreeNode<T> * SearchTree<T>::Maximum()
{
TreeNode<T> *node = root;
while(node->right!=NULL)
node = node->right;
return node;
}
template<class T>
TreeNode<T> * SearchTree<T>::MaximumInner(TreeNode<T> *node)
{
while(node->right!=NULL)
node = node->right;
return node;
}
template<class T>
TreeNode<T> * SearchTree<T>::TreePredecessor(TreeNode<T> *node)
{
if(node->left !=NULL)
{
TreeNode<T> * temp = MaximumInner(node->left);
return temp;
}
TreeNode<T> * temp = node->p;
while( temp!=NULL && node == temp->left)
{
node = temp;
temp = temp->p;
}
if (temp == NULL)
temp = new TreeNode<T>(-1); //表示没有前驱
return temp;
}
template<class T>
TreeNode<T> * SearchTree<T>::TreeSuccessor(TreeNode<T> *node)
{
if(node->right !=NULL)
{
TreeNode<T> * temp = MinimumInner(node->right);
return temp;
}
TreeNode<T> * temp = node->p;
while( temp!=NULL && node == temp->right)
{
node = temp;
temp = temp->p;
}
if (temp == NULL)
temp = new TreeNode<T>(-1); //表示没有后继
return temp;
}
template<class T>
SearchTree<T>::InsertInner(TreeNode<T> *insertNode,TreeNode<T> *parentNode)
{
if (parentNode->left==NULL && parentNode->right==NULL)
{
if (insertNode->mValue < parentNode->mValue)
{
parentNode->left = insertNode;
insertNode->p = parentNode;
}
else
{
parentNode->right = insertNode;
insertNode->p = parentNode;
}
}
else
{
if (insertNode->mValue < parentNode->mValue)
{
if (parentNode->left!=NULL)
InsertInner(insertNode,parentNode->left);
else
{
parentNode->left = insertNode;
insertNode->p = parentNode;
}
}
else
{
if (parentNode->right!=NULL)
InsertInner(insertNode,parentNode->right);
else
{
parentNode->right = insertNode;
insertNode->p = parentNode;
}
}
}
}
template<class T>
string SearchTree<T>::Delete(T value)
{
TreeNode<T> *node = SearchInner(root,value);//找到要删除的节点
if(node->left==NULL)
Transplant(node,node->right);
else if(node->right==NULL)
Transplant(node,node->left);
else
{
//找到后继节点
TreeNode<T> *temp = MinimumInner(node->right);
if (temp->p != node)
{
Transplant(temp,temp->right);
temp->right = node->right;
temp->right->p = temp;
}
Transplant(node,temp);
temp->left = node->left;
temp->left->p = temp;
}
return strTrue;
}
template<class T>
SearchTree<T>::Transplant(TreeNode<T> *pNode,TreeNode<T> *subNode)
{
if(pNode->p ==NULL) //pNode是根节点,则subNode继承到root
root = subNode;
else if (pNode == pNode->p->left)//下面两步,根据pNode是左还是右节点,则subNode继承到对应的节点
pNode->p->left = subNode;
else
pNode->p->right = subNode;
if (subNode !=NULL)//设置subNode的父节点
subNode->p = pNode->p;
}
int main()
{
int a[11] = {6,5,2,5,7,8,1,3,9,4,11};
SearchTree<int> *tr = new SearchTree<int>(a,11);
tr->MidWalk();
TreeNode<int> *node = tr->Search(10);
cout<<"node value is "<<node->mValue<<endl;
node = tr->Minimum();
cout<<"min value is "<<node->mValue<<endl;
node = tr->Maximum();
cout<<"max value is "<<node->mValue<<endl;
node = tr->Search(8);
node = tr->TreeSuccessor(node);
cout<<"successor value is "<<node->mValue<<endl;
node = tr->Search(2);
node = tr->TreePredecessor(node);
cout<<"predecessor value is "<<node->mValue<<endl;
node = tr->Search(2);
cout<<"2 node value is "<<node->mValue<<endl;
tr->Delete(2);
node = tr->Search(2);
cout<<"delete 2 node value is "<<node->mValue<<endl;
tr->MidWalk();
tr->Insert(2);
node = tr->Search(2);
cout<<"insert 2 node value is "<<node->mValue<<endl;
tr->MidWalk();
}
节点插入: 利用递归函数及二叉搜索树的性质(左节点≤父节点≤右节点),找到对应的位置插入即可; 二叉树的构造: 将传入的节点依次调用 节点插入 的方法 前中后序遍历: 利用递归函数,以中序遍历为例;1、优先输出父节点2、递归左节点3、递归右节点 节点搜索: 递归遍历每个节点,找到value相等的值 PS. 其实应该对比一下value值,大于等于value的搜索右节点,小于value的搜索左节点,就交给你们去完成了。 最大最小节点: 没什么好讲的,一直找右/左节点到底就是了 前驱后继: 前驱,在左子树的最大值中 或者 父节点中并且该节点必须在父节点的右子树中; 后继,在右子树的最小值中 或者 父节点中并且该节点必须在父节点的左子树中; 删除: 1、没有孩子,则直接删去就好 2、删除的节点x仅有一个孩子y(只存在左节点/只存在右节点),将y替代原来的x 3、删除的节点x存在两个孩子, ①就要找到x节点的后继节点y, ②将y节点的右节点替代y节点(ps,没有y左节点相关处理的原因在补充知识点内), ③y节点顶替x节点原有的位置 PS.记得要修改y及y右节点左右指针的指向
补充知识点: 在一棵二叉搜索树中,有双孩子节点x的后继节点没有左孩子;节点的前驱没有右孩子。 证明: 反证法—>后继节点如果有左孩子,则在节点的左子树中存在更靠近x.key的节点;前驱节点同理
删除的书内详解: