二叉排序树

这里采用将数据先全部存储数组vec中,再构造树
删除结点操作: 为了保证删除之后仍然是一颗二叉排序树,有两个方法。一个是找到比当前结点小的最大结点来覆盖当前结点,再删除原来位置上的结点;另一种是找到比当前结点大的最小结点覆盖当前结点,再删除原来位置上的结点。
其中比当前结点小的最大结点叫做该结点的前驱;比当前结点大的最小结点叫做该结点的后继。结点的前驱是该结点左子树中的最右结点,而结点的后继则是该结点右子树中的最左结点。
所以这里用两个函数分别寻找前驱和后继:

node* findMAX(node* root) //找前驱
{
	while (root -> right != NULL) //不停往右直到没有右孩子
		root = root -> right;
	return root;
}
node* findMIN(node* root) //找后继
{
	while (root -> left != NULL) //不停往左直到没有左孩子
		root = root -> left;
	return root;
}

接着写删除函数,如果打算用前驱P来替换当前结点N,于是问题就转换为了在N的左子树中删除P。

void delete_Node(node* &root, int x)
{
	if (!root) //结点不存在
		return;
	if (root -> val == x) //找到结点,进入删除环节
	{
		if (root -> left == NULL && root -> right == NULL) //不存在左右子孩子,说明是叶子结点,直接删除
			root = NULL;
		else if (root -> left != NULL) //有左孩子,则找前驱结点
		{
			node* pre = findMAX(root -> left);
			root -> val = pre -> val; //让前驱覆盖当前结点
			delete_Node(root -> left, pre -> val); //然后删除前驱结点
		}else{
			node* next = findMIN(root -> right); //有右孩子,则找后继结点
			root -> val = next -> val; //后继结点覆盖当前结点
			delete_Node(root -> left, next -> val); //接着删除后继结点
		}
	}
	else if (root -> val > x)
		delete_Node(root -> left, x);
	else
		delete_Node(root -> right, x);
}

完整代码:

#include <iostream>
#include <cstdlib>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
struct node
{
	int val;
	node* left;
	node* right;
	node(int v) : val(v), left(NULL), right(NULL) {}
};
vector<int> vec; //数组
void search(node*, int);
void insert(node* &, int);
node* creat_tree();
node* findMAX(node*);
node* findMIN(node*);
void delete_Node(node* &, int);
void preorder(node*);
void inorder(node*);
void postorder(node*);
void levelorder(node*);
int main()
{
	int value;
	while (cin >> value)
		vec.push_back(value);
	node* root = creat_tree();
	cout << "先序序列:";
	preorder(root);
	cout << endl;
	cout << "中序序列:";
	inorder(root);
	cout << endl;
	cout << "后序序列:";
	postorder(root);
	cout << endl;
	system("pause");
	return 0;
}
node* creat_tree() //建立树
{
	node* root = NULL;
	for (int i = 0;i < vec.size(); i++)
		insert(root, vec[i]);
	return root;
}
void search(node* root, int x) //寻找结点
{
	if (!root)
		return;
	if (root -> val == x)
		cout << "find it!";
	else if (x < root -> val)
		search(root -> left, x);
	else
		search(root -> right, x);
}
void insert(node* &root, int x) //插入结点
{
	if (!root)
	{
		root = new node(x); //因为传入的参数采用了引用,所以这里直接赋值就能实现插入
		return;
	}
	if (root -> val == x)
		return;
	else if (x < root -> val) //二叉排序树,小于则在左边
		insert(root -> left, x);
	else
		insert(root -> right, x);
}
node* findMAX(node* root)
{
	while (root -> right != NULL)
		root = root -> right;
	return root;
}
node* findMIN(node* root)
{
	while (root -> left != NULL)
		root = root -> left;
	return root;
}
void delete_Node(node* &root, int x)
{
	if (!root)
		return;
	if (root -> val == x)
	{
		if (root -> left == NULL && root -> right == NULL)
			root = NULL;
		else if (root -> left != NULL)
		{
			node* pre = findMAX(root -> left);
			root -> val = pre -> val;
			delete_Node(root -> left, pre -> val);
		}else{
			node* next = findMIN(root -> right);
			root -> val = next -> val;
			delete_Node(root -> left, next -> val);
		}
	}
	else if (root -> val > x)
		delete_Node(root -> left, x);
	else
		delete_Node(root -> right, x);
}
void preorder(node* root) //前序遍历
{
	if (root == NULL)
		return;
	cout << root -> val;
	preorder(root -> left);
	preorder(root -> right);
}
void inorder(node* root) //中序
{
	if (root == NULL)
		return;
	inorder(root -> left);
	cout << root -> val;
	inorder(root -> right);
}
void postorder(node* root) //后序
{
	if (root == NULL)
		return;
	postorder(root -> left);
	postorder(root -> right);
	cout << root -> val;
}
void levelorder(node* root) //层序遍历
{
	queue<node*> que;
	que.push(root);
	while (!que.empty())
	{
		node* p = que.front();
		cout << p -> val;
		que.pop();
		if (p -> left != NULL)
			que.push(p -> left);
		if (p -> right != NULL)
			que.push(p -> right);
	}
}
输出:
5 3 7 4 2 8 6
^Z
先序序列:5324768
中序序列:2345678
后序序列:2436875
删除结点5432768

平衡二叉树

构造平衡二叉树的核心就是每个结点的平衡因子,即任意结点的左子树和右子树的高度之差为该结点的平衡因子。
现在在结构体中用height表示当前结点的高度:

struct node
{
	int val;
	int height;
	node* left;
	node* right;
	node(int v) : val(v), height(1), left(NULL), right(NULL) {}
};

用某个结点左孩子结点的高度减去右孩子结点的高度即可得到平衡因子。
在二叉树代码的基础上多出这几个函数:

int get_height(node* root) //得到当前结点的高度
{
	if (!root)
		return 0;
	return root -> height;
}
int get_balance_factor(node* root) //得到当前结点的平衡因子
{
	return get_height(root -> left) - get_height(root -> right);
}
void update_height(node* root) //更新高度,一般在插入结点后使用
{
	root -> height = max(get_height(root -> left), get_height(root -> right)) + 1;
}

旋转操作

然后是调整二叉树变成平衡二叉树的关键,左旋和右旋:

左旋


左旋的操作可以细分
在这里插入图片描述

//左旋
void LR(node* &root)
{
	node* temp = root -> right;
	root -> right = temp -> left; //temp的左子树赋给root的右边
	temp -> left = root; //root赋给temp的左
	update_height(root); //更新高度
	update_height(temp);
	root = temp;
}
右旋

在这里插入图片描述
在这里插入图片描述
右旋其实就是左旋的对称过程:

void RR(node* &root)
{
	node* temp = root -> left;
	root -> left = temp -> right;
	temp -> right = root;
	update_height(root);
	update_height(temp);
	root = temp;
}

插入操作

插入过程中难免会造成树的失衡,此时有多种情况:若A的平衡因子是2,说明左子树的高度比右子树大2,于是以A为根结点的子树一定是下面两种情况:

注意:LL和LR表示的是树型,不是左右旋

LL情况

把以C为根结点的子树看作是一个整体,然后以根节点A作为root进行右旋:

LR情况

LR型只不过比LL型多一个步骤罢了:

然后是A的平衡因子为-2,此时右子树的高度比左子树大2,于是以结点A为根节点的子树只有下图RR和LR两种:
在这里插入图片描述

RR型情况

和LL型一样,把以C为根节点的子树看作一个整体,然后以结点A作为root进行左旋:
在这里插入图片描述

RL型情况

把情况转换为RR型,然后按上面RR型的做法进行左旋:
在这里插入图片描述
将上面的内容应用于insert函数,每次插入一个结点之后更新当前子树的高度,然后根据树型进行平衡操作:

void insert(node* &root, int v) //插入结点
{
	if (root == NULL)
	{
		root = new node(v);
		return;
	}
	if (v < root -> val)
	{
		insert(root -> left, v); //往左子树插
		update_height(root); //更新树高
		if (get_balance_factor(root) == 2) //等于2说明是LL或者LR
		{
			if (get_balance_factor(root -> left) == 1) //1说明是LL
				RR(root); //执行右旋
			else if (get_balance_factor(root -> left) == -1) //LR
			{
				LR(root -> left); //先左旋,变成LL型
				RR(root); //再右旋
			}
		}
	}
	else
	{
		insert(root -> right, v); //往右子树插
		update_height(root);
		if (get_balance_factor(root) == -2) //RR或者RL型
		{
			if (get_balance_factor(root -> right) == -1) //RR
				LR(root); //左旋
			else if (get_balance_factor(root -> left) == 1) //LR
			{
				RR(root -> right);
				LR(root);
			}
		}
	}
}

完整代码:

#include <iostream>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
struct node
{
	int val;
	int height;
	node* left;
	node* right;
	node(int v) : val(v), height(1), left(NULL), right(NULL) {}
};
vector<int> vec; //数组
int get_height(node*);
int get_balance_factor(node*);
void update_height(node*);
void LR(node* &);
void RR(node* &);
void insert(node* &, int);
void preorder(node* root);
void inorder(node* root);
void postorder(node* root);
void levelorder(node* root);
node* creat_tree();
int main()
{
	int value;
	while (cin >> value)
		vec.push_back(value);
	node* root = creat_tree();
	cout << "先序序列:";
	preorder(root);
	cout << endl;
	cout << "中序序列:";
	inorder(root);
	cout << endl;
	cout << "后序序列:";
	postorder(root);
	cout << endl;
	cout << "层序序列:";
	levelorder(root);
	cout << endl;
	system("pause");
	return 0;
}
int get_height(node* root)
{
	if (!root)
		return 0;
	return root -> height;
}
int get_balance_factor(node* root)
{
	return get_height(root -> left) - get_height(root -> right);
}
void update_height(node* root)
{
	root -> height = max(get_height(root -> left), get_height(root -> right)) + 1;
}
void LR(node* &root)
{
	node* temp = root -> right;
	root -> right = temp -> left;
	temp -> left = root;
	update_height(root);
	update_height(temp);
	root = temp;
}
void RR(node* &root)
{
	node* temp = root -> left;
	root -> left = temp -> right;
	temp -> right = root;
	update_height(root);
	update_height(temp);
	root = temp;
}
node* creat_tree() //建立树
{
	node* root = NULL;
	for (int i = 0;i < vec.size(); i++)
		insert(root, vec[i]);
	return root;
}
void insert(node* &root, int v) //插入结点
{
	if (root == NULL)
	{
		root = new node(v);
		return;
	}
	if (v < root -> val)
	{
		insert(root -> left, v);
		update_height(root);
		if (get_balance_factor(root) == 2)
		{
			if (get_balance_factor(root -> left) == 1)
				RR(root);
			else if (get_balance_factor(root -> left) == -1)
			{
				LR(root -> left);
				RR(root);
			}
		}
	}
	else
	{
		insert(root -> right, v);
		update_height(root);
		if (get_balance_factor(root) == -2)
		{
			if (get_balance_factor(root -> right) == -1)
				LR(root);
			else if (get_balance_factor(root -> left) == 1)
			{
				RR(root -> right);
				LR(root);
			}
		}
	}
}
void preorder(node* root) //前序遍历
{
	if (root == NULL)
		return;
	cout << root -> val;
	preorder(root -> left);
	preorder(root -> right);
}
void inorder(node* root) //中序
{
	if (root == NULL)
		return;
	inorder(root -> left);
	cout << root -> val;
	inorder(root -> right);
}
void postorder(node* root) //后序
{
	if (root == NULL)
		return;
	postorder(root -> left);
	postorder(root -> right);
	cout << root -> val;
}
void levelorder(node* root) //层序遍历
{
	queue<node*> que;
	que.push(root);
	while (!que.empty())
	{
		node* p = que.front();
		cout << p -> val;
		que.pop();
		if (p -> left != NULL)
			que.push(p -> left);
		if (p -> right != NULL)
			que.push(p -> right);
	}
}
输出:
1 2 3 4 5 6
^Z
先序序列:421356
中序序列:123456
后序序列:132654
层序序列:425136

例题PAT甲级1066 Root of AVL Tree

这个树指的是一般意义上的树,即子结点个数不限且子结点没有先后次序的树,这里的结点结构体中使用一个数组来存储所有的子结点
举例:

      0
    / | \
   1  2  3
 /  \    |
4    5   6
#include <iostream>
#include <cstdlib>
#include <vector>
#include <queue>
using namespace std;
struct node
{
	int layer; //用来记录结点的层次
	int value; //结点的数值
	vector<int> child; //结点的子结点
};
vector<node> Node(10);
void pre_order(int);
void layer_order(int);
int newNode(int);
int main()
{
	for (int i = 0; i < Node.size(); i++)
		Node[i].value = i;
	for (int i = 1; i <= 3; i++)
		Node[0].child.push_back(i);
	Node[1].child.push_back(4);
	Node[1].child.push_back(5);
	Node[3].child.push_back(6);
	cout << "先根遍历:";
	pre_order(0);
	cout << endl;
	cout << "层序遍历:";
	layer_order(0);
	cout << endl;
	cout << Node[0].layer << ' ' << Node[5].layer;
	system("pause");
	return 0;
}
void pre_order(int root) //先根遍历
{
	cout << Node[root].value;
	for (int i = 0; i < Node[root].child.size(); i++)
		pre_order(Node[root].child[i]);
}
void layer_order(int root) //层序遍历
{
	queue<int> que;
	que.push(root);
	Node[root].layer = 0;
	while (!que.empty())
	{
		int front = que.front();
		cout << Node[front].value;
		que.pop();
		for (int i = 0; i < Node[front].child.size(); i++)
		{
			int child = Node[front].child[i];
			Node[child].layer = Node[front].layer + 1;
			que.push(child);
		}
	}
}
输出:
先根遍历:0145236
层序遍历:0123456
0 2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值