一、结构定义
1.性质:左子树 < 根节点的值,右子树 > 根节点的值。
2.用途:解决与排名相关的检索问题
3.进行中序遍历时,能升序输出结果。
二、结构操作
1.插入:待插入值和根节点比较,如果小于就向左子树去找,反之向右子树。然后在子树中重复这个过程,直到满足左子树 < 根 < 右子树 这个要求。
2.删除:
1.出度为0的节点(叶子结点):直接删除即可
2.出度为1的节点(只有一个子孩子):把他的孩子放到他的位置。
3.出度为2的节点(两个子孩子):找到该节点的前驱或后继交换后,转化为删除出度为1或0的节点问题。(因为我们交换后,一定是删除前驱或后继位置节点,而这里的节点出度最大为1)
思考:对于一个出度为2的节点,他的前驱一定是他左子树中最右侧的值,他的后继一定为右子树中最左侧的值。所以可以得出:前驱一定没有右子树,后继一定没有左子树(用反证法去想)。
三、代码演示
1.结构定义:
//二叉树
typedef struct Node {
int key;
struct Node* lchild, * rchild;
}Node;
2.初始化:
//初始化节点
Node* getNewNode(int key) {
Node* p = (Node*)malloc(sizeof(Node));
p->key = key;
p->lchild = p->rchild = NULL;
return p;
}
3.销毁:
//销毁
void clear(Node* root) {
if (root == NULL) return;
clear(root->lchild);
clear(root->rchild);
free(root);
return;
}
4.插入:
//插入,返回插入后根节点的地址
//重复的值不重复插入
Node* insert(Node* root, int key) {
if (root == NULL) return getNewNode(key);
if (root->key == key) return root;
if (key < root->key) root->lchild = insert(root->lchild, key);
else root->rchild = insert(root->rchild, key);
return root;
}
5.删除:(这里采用找前驱的方法,找后继也行,一个思路)
//寻找前驱节点
Node* preNode(Node* root) {
Node* temp = root->lchild;
while (temp->rchild) temp = temp->rchild;
return temp;
}
//删除
Node* eraser(Node* root, int key) {
if (root == NULL) return root;//可能不存在
if (key < root->key) root->lchild = eraser(root->lchild, key);
else if(key > root->key) root->rchild = eraser(root->rchild, key);
else {
//到这里,说明要删除的是root
//像之前讨论的,分三种情况
if (root->lchild == NULL && root->rchild == NULL) {
free(root);
return NULL;
//出度为0
}
else if (root->lchild == NULL || root->rchild == NULL) {
Node* temp = root->lchild ? root->lchild : root->rchild;//找哪个子树不为空
free(root);
return temp;
//出度为1
}
else {
Node* temp = preNode(root);//前驱节点
root->key = temp->key;
root->lchild = eraser(root->lchild, temp->key);//去左子树删除那个节点
}
}
return root;
}
6.测试:
//获取键值的宏
#define KEY(n) (n ? n->key : -1)
//先序遍历,输出二叉树的结构
void output(Node* root) {
if (root == NULL) return;
cout << KEY(root) << " "
<< KEY(root->lchild) << " "
<< KEY(root->rchild) << endl;
output(root->lchild);
output(root->rchild);
}
//中序遍历
void in_order(Node* root) {
if (root == NULL) return;
in_order(root->lchild);
cout << root->key << " ";
in_order(root->rchild);
return;
}
int main()
{
//测试插入
srand(time(0));
#define MAXN 20
Node* root = NULL;
for (int i = 0; i < MAXN; i++) {
int val = rand() % 100;
cout << "插入" << val << endl;
root = insert(root, val);
}
output(root);//输出结构和中序遍历的结果
cout <<"in_order in:"<< endl;
in_order(root);
cout << endl;
//测试删除
int x;
while (cin >> x && x != -1) {
cout << "eraser:" << x << endl;
root = eraser(root, x);
in_order(root);
cout << endl;
}
return 0;
}