使用 c 语言的方式实现,一棵二叉排序树
// 一棵典型的二叉排序数,每个节点存在 左子节点 < 节点本身 < 右子节点
5
2 7
1 3 6 8
// 二叉排序树的插入操作
// 插入一个节点4, 先和5比较发现比5小,就在5的左子树中继续查找要插入的位置,
// 将要插入的4 与 节点2比较发现比2大,就在2的右子树中继续查找要插入的位置,
// 将要插入的4 与 节点3比较发现比3大,且3的右子树为空,所以要插入的位置就为3的右子树,
5<<
2<< 7
1 3<< 6 8
4
// 二叉排序树的删除操作
// 当删除的元素为3时,3这个节点只有右子树而没有左子树,我们只需要将 3的右子树直接连接到父节点2即可
5
2 7
1 4<< 6 8
// 当删除的元素为5时,我们只需要将右子树最小的元素复制给5这个要删除的节点,
6<<
2 7
1 4 6 8
// 然后再删除右子树的最小节点即可
6
2 7
1 4 << 8
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node * parent;
struct Node * left;
struct Node * right;
};
struct BinaryTree {
struct Node * root;
};
//-------------------------------init--------------------------------------
void InitBinaryTree(struct BinaryTree * tree) {
tree->root = NULL;
}
//-------------------------------destroy------------------------------------
void DestroyNode(struct Node * node) {
if(node == NULL) return;
DestroyNode(node->left);
DestroyNode(node->right);
free(node);
}
void DestroyBinaryTree(struct BinaryTree * tree) {
DestroyNode(tree->root);
}
//-------------------------------searchTree------------------------------------
struct Node * SearchTree(struct BinaryTree * tree, int data) {
struct Node * p = tree->root;
while(p != NULL) {
if(p->data == data) {
break;
} else if(data < p->data) {
if(p->left == NULL) break;
p = p->left;
} else {
if(p->right == NULL) break;
p = p->right;
}
}
// 如果未找到节点就返回,节点应该插入位置的父节点
return p;
}
//-------------------------------insert------------------------------------
void Insert(struct BinaryTree * tree, int data) {
struct Node * p = SearchTree(tree, data);
struct Node * pNode = (struct Node *)malloc(sizeof(struct Node));
pNode->data = data;
pNode->left = NULL;
pNode->right = NULL;
if(tree->root == NULL) { // 当根节点为空时插入节点作为根节点
pNode->parent = NULL;
tree->root = pNode;
return;
}else {
// p 为插入节点 pNode 的父节点,根据数据大小判断是父节点的左子节点还是右子节点
pNode->parent = p;
if(data < p->data) {
p->left = pNode;
} else {
p->right = pNode;
}
}
}
//-------------------------------erase------------------------------------
void Erase(struct BinaryTree * tree, int data) {
if(tree->root == NULL) return;
struct Node * p = SearchTree(tree, data);
if( p->data != data) return; // 树中不存在要删除的节点
if(p->right == NULL) { // 当插入节点的右子树为空时,直接将左子树与父节点链接
if(p == p->parent->left){
p->parent->left = p->left;
} else {
p->parent->right = p->left;
}
free(p);
} else if(p->left == NULL){ // 当插入节点的左子树为空时,直接将右子树与父节点链接
if(p == p->parent->left){
p->parent->left = p->right;
} else {
p->parent->right = p->right;
}
free(p);
} else {
// 当左右子树都存在时,将删除的元素值替换为右子树的最小元素,从而转化为删除右子树的最小元素
struct Node * pos = p->right;
while(pos->left != NULL) pos = pos->left; // 找出右子树的最小元素
p->data = pos->data;
// 用pos节点覆盖了要删除的节点,现在只需删除 pos 节点即可(pos没有左子树)
if(pos == pos->parent->left){
pos->parent->left = pos->right;
} else {
pos->parent->right = pos->right;
}
free(pos);
}
}
//-------------------------------find------------------------------------
struct Node * find(struct BinaryTree * tree, int data) {
struct Node * p = tree->root;
while(p != NULL) {
if(p->data == data) {
return p;
} else if(data < p->data) {
p = p->left;
} else {
p = p->right;
}
}
// 如果没找到就返回 NULL
return p;
}
//-------------------------------print------------------------------------
void PrintBinaryTree(struct Node * node) {
if(node == NULL) return;
// 使用先序方式输出(先根再左再右)
printf("node: %d\n",node->data); // <<1>>
PrintBinaryTree(node->left); // <<2>>
PrintBinaryTree(node->right); // <<3>>
// 将上面调整为 2,1,3 循序就为中序遍历(先左再根再右),
// 调整为 2,3,1 就为后序遍历(先左再右再根)
}
void Print(struct BinaryTree * tree) {
PrintBinaryTree(tree->root);
printf("xxxxxxxxx\n");
}
int main(void)
{
struct BinaryTree tree;
InitBinaryTree(&tree);
Insert(&tree, 4);
Insert(&tree, 2);
Insert(&tree, 3);
Insert(&tree, 5);
Insert(&tree, 1);
Insert(&tree, 6);
Erase(&tree, 2);
Erase(&tree, 4);
Print(&tree);
struct Node * locate = find(&tree, 1);
if(locate != NULL) printf("find node: %d\n", locate->data);
DestroyBinaryTree(&tree);
return 0;
}