平衡树基础1——二叉排序树(二叉搜索树)

一、结构定义

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值