二叉排序树
一、二叉排序树定义
- 定义:二叉查找树,又被称为二叉搜索树。其特点如下:设x为二叉查找树中的一个结点,x节点包含关键字key,一句话就是左孩子比父节点小,右孩子比父节点大,还有一个特性就是”中序遍历“可以让结点有序。
/*
(4)
/ \
(2) (6)
/ \ / \
(1) (3)(5) (8)
\
(9)
*/
- 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 任意节点的左、右子树也分别为二叉搜索树;
- 没有键值相等的节点。
二、二叉排序树插入操作
1、插入原理
- 第一步:插入头节点(4)
/*
(4)
*/
- 第二步:插入节点(5)
节点(5)的值比头节点(4)大,所以该节点插入到头节点(4)的右子树上
/*
(4)
\
(5)
*/
- 第三步:插入节点(3)
节点(3)的值比头节点(4)小,所以该节点插入到头节点(4)的左子树上
/*
(4)
/ \
(3) (5)
*/
- 第四步:插入节点(7)
节点(7)的值比头节点(4)大,由于头节点(4)的右子树上已有节点(5),所以该节点与节点(5)比较,该节点(7)比节点(5)大,所以该节点插入到头节点(5)的右子树上
/*
(4)
/ \
(3) (5)
\
(7)
*/
- 依次类推插入
2、插入方式实现
- 递归插入
/**
* @brief 插入
* @param m_proot:树节点
* @param m_pTdata:插入数据
*/
node* insert(node* m_pRoot, T m_pData)
{
if (m_pRoot == nullptr)
return new node(m_pData);
if (m_pData < m_pRoot->m_data)
{
m_pRoot->m_left = insert(m_pRoot->m_left, m_pData);
}
else if (m_pData > m_pRoot->m_data)
{
m_pRoot->m_right = insert(m_pRoot->m_right, m_pData);
}
return m_pRoot;
}
- 非递归插入
//插入 (非递归)
int BST_InsertLive(node*& m_pRoot, T m_pData)
{
node* temp = m_pRoot; // 保存跟节点
node* parent = nullptr;
bool bLeftandRight = false; // 记录循环找到空节点为左右子树那个
while (temp != nullptr && temp->m_Tdata != m_pData)
{
parent = temp;
if (m_pData < temp->m_Tdata) // 左子树
{
temp = temp->m_left;
bLeftandRight = false;
}
else if (m_pData > temp->m_Tdata) // 右子树
{
temp = temp->m_right;
bLeftandRight = true;
}
}
if (m_pRoot == nullptr)
{
m_pRoot = new node(m_pData);
return 1;
}
else if (temp == nullptr)
{
if (!bLeftandRight) // 左子树
{
parent->m_left = new node(m_pData);
}
else // 右子树
{
parent->m_right = new node(m_pData);
}
return 1;
}
else if (temp->m_Tdata == m_pData)
{
return 0;
}
}
三、二叉排序树删除操作
1、删除原理
- 删除的节点为头节点直接删除
删除头节点(4)
/*
(4) -->
*/
- 删除的节点左右子树都为空,直接删除节点
删除节点(2)
/*
(4) (4)
/ \ ---> \
(2) (5) (5)
*/
- 删除的节点左子树为空
删除节点(5),因为节点(5)的左子树为空,所有要删除节点(5),只需要将节点(5)的右子树(6)赋值给原来节点(5)的位置
/*
(4) (4)
/ \ ---> / \
(2) (5) (2) (6)
\
(6)
*/
- 删除的节点右子树为空
删除节点(6),因为节点(6)的右子树为空,所有要删除节点(6),只需要将节点(6)的左子树(5)赋值给原来节点(6)的位置
/*
(4) (4)
/ \ ---> / \
(2) (6) (2) (5)
/
(5)
*/
- 删除的节点左右子树都不为空
删除的节点(5),其左右节点都不为空,由于二叉搜索树的特性是左子树一定小于右子树,所有节点(5)的右子树的值必然大于左子树的值,找到节点(5)的右子树的最小值,由于二叉搜索树的特性节点(5)的右子树的最小值必然大于节点(5)左子树的值,将节点(5)左子树赋值给节点(5)的右子树的最小值的左子树,然后删除节点(5),这样删除完成
/*
(1) (1)
\ \
(5) ---> (6)
/ \ /
(3) (6) (3)
/ /
(2) (2)
*/
2、C++递归实现
/**
* @brief 删除(leedcode题450)
* @param m_proot:树节点
* @param m_pTdata:删除值
*/
node* remove(node* m_pRoot, T m_pTdata)
{
if (m_pRoot == nullptr) // 节点为空
return m_pRoot;
if (m_pRoot->m_Tdata == m_pTdata) // 找到该值的节点
{
if (m_pRoot->m_left == nullptr && m_pRoot->m_right == nullptr) // 左右子树都为空,直接删除节点
{
delete m_pRoot;
return nullptr;
}
else if (m_pRoot->m_left == nullptr) // 左子树为空,删除左子树,返回右子树
{
node* temp = m_pRoot->m_right;
delete m_pRoot;
return temp;
}
else if (m_pRoot->m_right == nullptr) // 右子树为空,删除右子树,返回左子树
{
node* temp = m_pRoot->m_left;
delete m_pRoot;
return temp;
}
else // 左右子树都不为空
{
node* curr = m_pRoot->m_right; // 右子树赋值给节点curr
while (curr->m_left != nullptr) // 循环找到m_pRoot右子树的最深左子树
curr = curr->m_left;
curr->m_left = m_pRoot->m_left; // 将m_pRoot的左子树赋值给m_pRoot右子树的最深左子树
node* temp = m_pRoot; // 找到的节点m_pRoot赋值给节点temp
m_pRoot = m_pRoot->m_right; // 节点m_pRoot的右子树赋值给节点m_pRoot
delete temp;
return m_pRoot;
}
}
if (m_pRoot->m_Tdata > m_pTdata)
m_pRoot->m_left = remove(m_pRoot->m_left, m_pTdata);
if (m_pRoot->m_Tdata < m_pTdata)
m_pRoot->m_right = remove(m_pRoot->m_right, m_pTdata);
return m_pRoot;
}
四、二叉排序树遍历操作
1、前序遍历
前序遍历:跟->左子树->右子树
/*
(1)
\
(5)
/ \
(3) (6)
/
(2)
第一步:先访问跟节点(1)
第二步:跟节点的左子树没有,访问右子树节点(5)
第三步:访问节点(5)的左子树(3),再访问节点(3)的左子树(2)
第四步:节点(2)没有左右子树,节点(3)没有右子树,访问节点(5)的右子树(6)
*/
- 递归实现
/**
* @brief 前序遍历
* @param m_proot:树节点
*/
void print_Pre(node* m_proot)
{
if (m_proot != nullptr)
{
std::cout << m_proot->m_Tdata << " ";
print_Pre(m_proot->m_left);
print_Pre(m_proot->m_right);
}
}
- 栈实现
/**
* @brief 前序遍历(栈实现)
*/
void print_Pre_Stack()
{
if (m_root == nullptr)
return;
std::stack<node*> stStack;
node* temp = m_root;
while (temp != nullptr || !stStack.empty())
{
while (temp != nullptr)
{
cout << temp->m_Tdata << " ";
stStack.push(temp);
temp = temp->m_left;
}
if (!stStack.empty())
{
temp = stStack.top()->m_right;
stStack.pop();
}
}
std::cout << std::endl;
}
2、中序遍历
中序遍历:左子树->跟->右子树
/*
(1)
\
(5)
/ \
(3) (6)
/
(2)
第一步:先访问跟节点(1)的左子树,再访问跟节点(1)
第二步:访问节点(5)的左子树(3),节点(3)下面还有左子树,继续往下访问节点(3)的左子树(2)
第三步:访问节点(3),然后访问节点(5),然后访问节点(5)的右子树(6)
*/
- 递归实现
/**
* @brief 中序遍历
* @param m_proot:树节点
*/
void print_In(node* m_proot)
{
if (m_proot != nullptr)
{
print_In(m_proot->m_left);
std::cout << m_proot->m_Tdata << " ";
print_In(m_proot->m_right);
}
}
- 栈实现
/**
* @brief 中序遍历(栈实现)
*/
void print_In_Stack()
{
if (m_root == nullptr)
return;
std::stack<node*> stStack;
node* temp = m_root;
while (temp != nullptr || !stStack.empty())
{
while (temp != nullptr)
{
stStack.push(temp);
temp = temp->m_left;
}
if (!stStack.empty())
{
temp = stStack.top();
stStack.pop();
cout << temp->m_Tdata << " ";
temp = temp->m_right;
}
}
std::cout << std::endl;
}
3、后序遍历
后序遍历:左子树->右子树->跟
/*
(1)
\
(5)
/ \
(3) (6)
/
(2)
第一步:先访问跟节点(1)的左子树,发现跟节点(1)没有左子树
第二步:然后访问节点(1)的右子树(5),节点(5)下面还有左子树(3),继续往下访问节点(3)的左子树(2)
第三步:访问节点(3),然后访问节点(5)的右子树(6),然后访问节点(5),
第四步:最后访问跟节点(1)
*/
- 递归实现
/**
* @brief 后序遍历
* @param m_proot:树节点
*/
void print_Post(node* m_proot)
{
if (m_proot != nullptr)
{
print_Post(m_proot->m_left);
print_Post(m_proot->m_right);
std::cout << m_proot->m_Tdata << " ";
}
}
- 栈实现
/**
* @brief 后序遍历(栈实现)
*/
void print_Post_Stack()
{
if (m_root == nullptr)
return;
std::stack<node*> stStack;
node* temp = m_root;
do
{
while (temp->m_left)
{
stStack.push(temp);
temp = temp->m_left;
}
if (temp->m_right)
{
stStack.push(temp);
temp = temp->m_right;
}
else
{
while (!stStack.empty())
{
while (temp == stStack.top()->m_left && !stStack.top()->m_right ||
temp == stStack.top()->m_right && !stStack.top()->m_left)
{
std::cout << temp->m_Tdata << " ";
temp = stStack.top();
stStack.pop();
if (stStack.empty())
break;
}
std::cout << temp->m_Tdata << " ";
if (stStack.empty())
break;
if (temp == stStack.top()->m_left)
{
temp = stStack.top()->m_right;
break;
}
else
{
temp = stStack.top();
stStack.pop();
if (stStack.empty())
std::cout << temp->m_Tdata << " ";
}
}
}
} while (!stStack.empty());
std::cout << std::endl;
}
4、层次遍历
- 队列实现
/**
* @brief 层次遍历(队列实现)
*/
void print_Level_Queue()
{
if (m_root == nullptr)
return;
std::queue<node*> queQueue;
node* temp = m_root;
queQueue.push(temp);
while (!queQueue.empty())
{
temp = queQueue.front();
queQueue.pop();
std::cout << temp->m_Tdata << " ";
if (temp->m_left != nullptr)
queQueue.push(temp->m_left);
if (temp->m_right != nullptr)
queQueue.push(temp->m_right);
}
std::cout << std::endl;
}
五、整体代码
#include <iostream>
#include <stack>
#include <queue>
/**
* @namespace 二叉排序树
*/
namespace tree_BST
{
template<class T>
class Tree
{
public:
struct node
{
node(T m_pTdata) :m_Tdata(m_pTdata), m_left(nullptr), m_right(nullptr) {}
T m_Tdata;
node* m_left; // 左子树
node* m_right; // 右子树
};
Tree() :m_root(nullptr) {}
/**
* @brief 插入
* @param m_pTdata:插入值
*/
void insert(T m_pTdata)
{
m_root = insert(m_root, m_pTdata);
}
/**
* @brief 删除
* @param m_pTdata:删除值
*/
void remove(T m_pTdata)
{
m_root = remove(m_root, m_pTdata);
}
/**
* @brief 前序遍历
*/
void print_Pre()
{
print_Pre(m_root);
std::cout << std::endl;
}
/**
* @brief 中序遍历
*/
void print_In()
{
print_In(m_root);
std::cout << std::endl;
}
/**
* @brief 后序遍历
*/
void print_Post()
{
print_Post(m_root);
std::cout << std::endl;
}
/**
* @brief 前序遍历(栈实现)
*/
void print_Pre_Stack()
{
if (m_root == nullptr)
return;
std::stack<node*> stStack;
node* temp = m_root;
while (temp != nullptr || !stStack.empty())
{
while (temp != nullptr)
{
cout << temp->m_Tdata << " ";
stStack.push(temp);
temp = temp->m_left;
}
if (!stStack.empty())
{
temp = stStack.top()->m_right;
stStack.pop();
}
}
std::cout << std::endl;
}
/**
* @brief 中序遍历(栈实现)
*/
void print_In_Stack()
{
if (m_root == nullptr)
return;
std::stack<node*> stStack;
node* temp = m_root;
while (temp != nullptr || !stStack.empty())
{
while (temp != nullptr)
{
stStack.push(temp);
temp = temp->m_left;
}
if (!stStack.empty())
{
temp = stStack.top();
stStack.pop();
cout << temp->m_Tdata << " ";
temp = temp->m_right;
}
}
std::cout << std::endl;
}
/**
* @brief 后序遍历(栈实现)
*/
void print_Post_Stack()
{
if (m_root == nullptr)
return;
std::stack<node*> stStack;
node* temp = m_root;
do
{
while (temp->m_left)
{
stStack.push(temp);
temp = temp->m_left;
}
if (temp->m_right)
{
stStack.push(temp);
temp = temp->m_right;
}
else
{
while (!stStack.empty())
{
while (temp == stStack.top()->m_left && !stStack.top()->m_right ||
temp == stStack.top()->m_right && !stStack.top()->m_left)
{
std::cout << temp->m_Tdata << " ";
temp = stStack.top();
stStack.pop();
if (stStack.empty())
break;
}
std::cout << temp->m_Tdata << " ";
if (stStack.empty())
break;
if (temp == stStack.top()->m_left)
{
temp = stStack.top()->m_right;
break;
}
else
{
temp = stStack.top();
stStack.pop();
if (stStack.empty())
std::cout << temp->m_Tdata << " ";
}
}
}
} while (!stStack.empty());
std::cout << std::endl;
}
/**
* @brief 层次遍历(队列实现)
*/
void print_Level_Queue()
{
if (m_root == nullptr)
return;
std::queue<node*> queQueue;
node* temp = m_root;
queQueue.push(temp);
while (!queQueue.empty())
{
temp = queQueue.front();
queQueue.pop();
std::cout << temp->m_Tdata << " ";
if (temp->m_left != nullptr)
queQueue.push(temp->m_left);
if (temp->m_right != nullptr)
queQueue.push(temp->m_right);
}
std::cout << std::endl;
}
private:
/**
* @brief 删除(leedcode题450)
* @param m_proot:树节点
* @param m_pTdata:删除值
*/
node* remove(node* m_pRoot, T m_pTdata)
{
if (m_pRoot == nullptr) // 节点为空
return m_pRoot;
if (m_pRoot->m_Tdata == m_pTdata) // 找到该值的节点
{
if (m_pRoot->m_left == nullptr && m_pRoot->m_right == nullptr) // 左右子树都为空,直接删除节点
{
delete m_pRoot;
return nullptr;
}
else if (m_pRoot->m_left == nullptr) // 左子树为空,删除左子树,返回右子树
{
node* temp = m_pRoot->m_right;
delete m_pRoot;
return temp;
}
else if (m_pRoot->m_right == nullptr) // 右子树为空,删除右子树,返回左子树
{
node* temp = m_pRoot->m_left;
delete m_pRoot;
return temp;
}
else // 左右子树都不为空
{
node* curr = m_pRoot->m_right; // 右子树赋值给节点curr
while (curr->m_left != nullptr) // 循环找到m_pRoot右子树的最深左子树
curr = curr->m_left;
curr->m_left = m_pRoot->m_left; // 将m_pRoot的左子树赋值给m_pRoot右子树的最深左子树
node* temp = m_pRoot; // 找到的节点m_pRoot赋值给节点temp
m_pRoot = m_pRoot->m_right; // 节点m_pRoot的右子树赋值给节点m_pRoot
delete temp;
return m_pRoot;
}
}
if (m_pRoot->m_Tdata > m_pTdata)
m_pRoot->m_left = remove(m_pRoot->m_left, m_pTdata);
if (m_pRoot->m_Tdata < m_pTdata)
m_pRoot->m_right = remove(m_pRoot->m_right, m_pTdata);
return m_pRoot;
}
/**
* @brief 插入
* @param m_proot:树节点
* @param m_pTdata:插入数据
*/
node* insert(node* m_pRoot, T m_pData)
{
if (m_pRoot == nullptr)
return new node(m_pData);
if (m_pData < m_pRoot->m_data)
{
m_pRoot->m_left = insert(m_pRoot->m_left, m_pData);
}
else if (m_pData > m_pRoot->m_data)
{
m_pRoot->m_right = insert(m_pRoot->m_right, m_pData);
}
return m_pRoot;
}
//插入 (非递归)
int BST_InsertLive(node*& m_pRoot, T m_pData)
{
node* temp = m_pRoot; // 保存跟节点
node* parent = nullptr;
bool bLeftandRight = false; // 记录循环找到空节点为左右子树那个
while (temp != nullptr && temp->m_Tdata != m_pData)
{
parent = temp;
if (m_pData < temp->m_Tdata) // 左子树
{
temp = temp->m_left;
bLeftandRight = false;
}
else if (m_pData > temp->m_Tdata) // 右子树
{
temp = temp->m_right;
bLeftandRight = true;
}
}
if (m_pRoot == nullptr)
{
m_pRoot = new node(m_pData);
return 1;
}
else if (temp == nullptr)
{
if (!bLeftandRight) // 左子树
{
parent->m_left = new node(m_pData);
}
else // 右子树
{
parent->m_right = new node(m_pData);
}
return 1;
}
else if (temp->m_Tdata == m_pData)
{
return 0;
}
}
/**
* @brief 前序遍历
* @param m_proot:树节点
*/
void print_Pre(node* m_proot)
{
if (m_proot != nullptr)
{
std::cout << m_proot->m_Tdata << " ";
print_Pre(m_proot->m_left);
print_Pre(m_proot->m_right);
}
}
/**
* @brief 中序遍历
* @param m_proot:树节点
*/
void print_In(node* m_proot)
{
if (m_proot != nullptr)
{
print_In(m_proot->m_left);
std::cout << m_proot->m_Tdata << " ";
print_In(m_proot->m_right);
}
}
/**
* @brief 后序遍历
* @param m_proot:树节点
*/
void print_Post(node* m_proot)
{
if (m_proot != nullptr)
{
print_Post(m_proot->m_left);
print_Post(m_proot->m_right);
std::cout << m_proot->m_Tdata << " ";
}
}
private:
node* m_root; // 根节点
};
void test_tree()
{
tree_BST::Tree<int> m_tree;
std::cout << "BST insert(1,5,6,3,2)" << std::endl;
m_tree.insert(1);
/*
(1)
*/
m_tree.insert(5);
/*
(1)
\
(5)
*/
m_tree.insert(6);
/*
(1)
\
(5)
\
(6)
*/
m_tree.insert(3);
/*
(1)
\
(5)
/ \
(3) (6)
*/
m_tree.insert(2);
/*
(1)
\
(5)
/ \
(3) (6)
/
(2)
*/
std::cout << "BST 前序遍历(跟->左子树->右子树):";
m_tree.print_Pre(); // 1 5 3 2 6
/*
(1)
\
(5)
/ \
(3) (6)
/
(2)
第一步:先访问跟节点(1)
第二步:跟节点的左子树没有,访问右子树节点(5)
第三步:访问节点(5)的左子树(3),再访问节点(3)的左子树(2)
第四步:节点(2)没有左右子树,节点(3)没有右子树,访问节点(5)的右子树(6)
*/
std::cout << "BST 中序遍历(左子树->跟->右子树):";
m_tree.print_In(); // 1 2 3 5 6
/*
(1)
\
(5)
/ \
(3) (6)
/
(2)
第一步:先访问跟节点(1)的左子树,再访问跟节点(1)
第二步:访问节点(5)的左子树(3),节点(3)下面还有左子树,继续往下访问节点(3)的左子树(2)
第三步:访问节点(3),然后访问节点(5),然后访问节点(5)的右子树(6)
*/
std::cout << "BST 后序遍历(左子树->右子树->跟):";
m_tree.print_Post(); // 2 3 6 5 1
/*
(1)
\
(5)
/ \
(3) (6)
/
(2)
第一步:先访问跟节点(1)的左子树,发现跟节点(1)没有左子树
第二步:然后访问节点(1)的右子树(5),节点(5)下面还有左子树(3),继续往下访问节点(3)的左子树(2)
第三步:访问节点(3),然后访问节点(5)的右子树(6),然后访问节点(5),
第四步:最后访问跟节点(1)
*/
std::cout << "BST 前序遍历(栈实现):";
m_tree.print_Pre_Stack(); // 1 5 3 2 6
std::cout << "BST 中序遍历(栈实现):";
m_tree.print_In_Stack(); // 1 2 3 5 6
std::cout << "BST 后序遍历(栈实现):";
m_tree.print_Post_Stack(); // 2 3 6 5 1
std::cout << "BST 层次遍历(队列实现):";
m_tree.print_Level_Queue(); // 1 5 3 6 2
std::cout << "BST 删除(3)(迭代实现):";
m_tree.remove(3);
m_tree.print_In(); // 1 2 5 6
/*
(1) (1)
\ \
(5) (5)
/ \ / \
(3) (6) (2) (6)
/
(2)
*/
std::cout << "BST 删除(2)(迭代实现):";
m_tree.remove(2);
m_tree.print_In(); // 1 5 6
std::cout << "BST 删除(1)(迭代实现):";
m_tree.remove(1);
m_tree.print_In(); // 5 6
std::cout << "BST 删除(6)(迭代实现):";
m_tree.remove(6);
m_tree.print_In(); // 5
std::cout << "BST 删除(5)(迭代实现):";
m_tree.remove(5);
m_tree.print_In(); //
}
}// namespace tree_BST
int main()
{
tree_BST::test_tree();
return 0;
}