这篇博客面向已了解什么是二叉排序树、二叉树的应用场景是什么、二叉树基本操作的实现原理。
该博客不适合系统的去学习二叉排序树!!!主要是帮助急需代码实现的读者~
博客的内容主要分析了删除操作的一些细节问题,亲测有效无Bug!因为没有语言描述,可能有些晦涩,但是只要顺着把代码敲一遍,一定能够保证掌握二叉排序树的这些基本操作!!!
如果这篇博客有帮助你,点个赞呗~,话不多说,上代码。
二叉排序树的基本操作
// 头文件
#include <iostream>
#include <vector> // 容器,相当于数组
using namespace std;
1 二叉排序树结构体、创建新的节点
// 1.1 定义二叉排序树的存储结构
typedef int DataType;
typedef struct TreeNode {
DataType data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode, * ASLTree;
// 1.2 创建新的节点
ASLTree CreateNode(DataType x) {
ASLTree node = (ASLTree)malloc(sizeof(TreeNode));
if (!node) exit(-1);
node->data = x;
node->left = NULL;
node->right = NULL;
return node;
}
2 二叉排序树的创建
// 2.1.1 插入节点(解决方案1)
void InsertNode(ASLTree& root, DataType val) {
if (root == NULL) {
root = CreateNode(val); // 这把钥匙配这扇门
}
else {
if (val < root->data) {
InsertNode(root->left, val); // root->left为NULL
}
else {
InsertNode(root->right, val); // root->right为NULL
}
}
}
// (1) ASLTree root = NULL; 这个是一把钥匙,而不是门!!!
// (2) CreateNode(DatatType x) 创建了一个门
// (3) 如果直接是 ASLTree root,表示克隆了一把钥匙,去打开门,而不是使用原配的钥匙去打开的门
// (4) 加上 & ,则是将原配的钥匙携带到门旁,打开它
// 2.1.2 插入节点(解决方案2)
ASLTree InsertNode2(ASLTree root, DataType val) {
if (root == NULL) {
root = CreateNode(val);
}
else {
if (val < root->data) {
root->left = InsertNode2(root->left, val); // root->left为NULL
}
else {
root->right = InsertNode2(root->right, val); // root->right为NULL
}
}
return root;
}
// 2.2 通过数组构造二次排序树
ASLTree CreateSearchTree(vector<int>& vec) {
ASLTree root = NULL; // (1)这个是一把钥匙,而不是门!!!
for (int i = 0; i < vec.size(); i++) {
//InsertNode(root, vec[i]);
root = InsertNode2(root, vec[i]);
}
return root;
}
3 查找指定的节点
// 3.1 查找节点是否存在
bool SearchNode(ASLTree root, DataType val) {
if (root == NULL) return false; // 最后指向空,没找到该节点
if (val < root->data) {
SearchNode(root->left, val);
}
else if (val > root->data) {
SearchNode(root->right, val);
}
else { // 值相等,找到了
return true;
}
}
4 删除指定的节点
// 4.1 删除的指定的节点
ASLTree DeleteNode(ASLTree root, DataType val) {
ASLTree p = NULL; // 遍历指针
ASLTree fp = NULL; // 遍历指针的父指针
p = root;
while (p != NULL) {
fp = p; // 首次都是从根节点出发(根节点没有父节点)
if (val < p->data) { // 三个分别为if 、else if、if!!!
p = p->left;
}
else if (val > p->data) {
p = p->right;
}
if (val == p->data) { // 特殊情况下,删除的节点是根节点
break;
}
}
if (p == NULL) {
cout << "未找到你要删除的节点,删除失败!" << endl;
return NULL;
}
// 接下来分四种情况
// (1)左孩子右孩子都有(根节点和其他节点一样)
if (p->left && p->right) {
ASLTree q = p;
fp = p; // 因为p下一步要更新到p->right,则需要更新fp=p
p = p->right; // 我们寻找右子树最小值
while (p->left) {
fp = p;
p = p->left;
}
q->data = p->data; // 交换数据
// 右子树的最小值所在节点可能是叶子结点,可能是只有右子树的节点
if (fp->left == p) {
fp->left = p->right; // 可能为空,不影响
}
else if (fp->right == p) {
fp->right = p->right;
}
free(p); // 释放空间
return root;
}
// (2)左孩子右孩子都没有(根节点和其他叶子节点不一样!)
if (p->left == NULL && p->right == NULL) {
if (p == root) {
free(root);
return NULL;
}
if (fp->left == p) {
fp->left = NULL;
}
else if (fp->right == p) {
fp->right = NULL;
}
free(p);
return root;
}
// (3) 只有左孩子没有右孩子(根节点不同于其他节点)
if (p->left != NULL && p->right == NULL) {
if (p == root) {
root = p->left;
p->left = NULL; // 孤立要删除的根节点
free(p);
return root;
}
if (fp->left == p) {
fp->left = p->left;
p->left = NULL;
}
else if (fp->right == p) {
fp->right = p->left;
p->left = NULL;
}
free(p);
return root;
}
// (4) 只有右孩子没有左孩子(根节点不同于其他节点)
if (p->left == NULL && p->right != NULL) {
if (p == root) {
root = p->right;
p->right = NULL; // 孤立要删除的根节点
free(p);
return root;
}
if (fp->left == p) {
fp->left = p->right;
p->right = NULL;
}
else if (fp->right == p) {
fp->right = p->right;
p->right = NULL;
}
free(p);
return root;
}
}
5 中序遍历二叉排序树
// 5.1 中序遍历二叉树
void InOrder(ASLTree root) {
if (root == NULL) return;
InOrder(root->left);
cout << root->data << " ";
InOrder(root->right);
}
6 主函数
int main(void) {
DataType node;
vector<int> vec{ 4,2,3,6,8,7,5,1,9,10 };
cout << "通过容器生成二叉排序树:" << endl;
ASLTree tree = CreateSearchTree(vec);
cout << "该二叉排序树中序遍历如下:" << endl;
InOrder(tree);
cout << endl;
cout << "请输入要查找的节点:" << endl;
cin >> node;
if (SearchNode(tree, node)) {
cout << "找到了!" << endl;
}
else {
cout << "该排序树中没有这个结点!" << endl;
}
cout << "请输入要删除的节点:" << endl;
cin >> node;
tree = DeleteNode(tree, node);
cout << "删除后的二叉排序树中序遍历如下:" << endl;
InOrder(tree);
return 0;
}