平衡二叉树

4种旋转操作:

1. 左左旋(LL)

 2. 左右旋(LR)

3. 右右旋(RR)

4. 右左旋(RL)

 创建二叉树实现下图操作:

 实现代码:

#include <stdio.h>
#include <stdlib.h>

// 平衡二叉树,首先是有序二叉树,任意子树的高度差都小于等于1。

// 定义二叉树节点结构体 
typedef struct TreeNode
{
	int data;	// 数据域
	int height;	// 记录树的高度
	struct TreeNode* LChild;	// 指向左孩子节点指针
	struct TreeNode* RChild;	// 指向右孩子节点指针
}TreeNode;

// 1.创建节点 并 插入进行链接 注意要传递二级指针,因为要进行改变节点
void CreateAndInsert(TreeNode** T, int data);

// 遍历输出
// 2.前序遍历 递归
void PreOrder(TreeNode* T);
// 2.1、前序遍历 栈实现
void PreOrderStack(TreeNode* T);
// 3.中序遍历 递归
void MidOrder(TreeNode* T);
// 3.1、中序遍历 栈实现
void MidOrderByStack(TreeNode* T);
// 4.后序遍历 递归
void LastOrder(TreeNode* T);
// 4.1、后序遍历 栈实现
void LastOrderByStack(TreeNode* T);

// 获取树高度
// 5.获取树节点的高度
int getHeight(TreeNode* tree);
// 5.1、获取树节点的最大高度 左右子树的最大高度
// 参数1:左子树高度  参数2:右子树高度
int maxHeight(int leftHeight, int rightHeight);

// 进行旋转操作
//6.1、 进行LL 调整 参数1:父节点 参数2:父节点地址
void LL_Rotation(TreeNode* fatherNode, TreeNode** root);
//6.2、 进行RR 调整 参数1:父节点 参数2:父节点的地址
void RR_Rotation(TreeNode* fatherNode, TreeNode** root);


int main()
{
	// 定义节点
	TreeNode* T = NULL;

	// 创建或插入节点
	for (int i = 1; i < 7; i++)
	{
		CreateAndInsert(&T, i);
	}

	// 前序遍历 递归 打印数据
	printf("前序遍历(利用递归):");
	PreOrder(T);
	// 前序遍历 栈实现 打印数据
	printf("\n前序遍历(利用栈实现):");
	PreOrderStack(T);
	
	// 中序遍历 递归 
	printf("中序遍历(利用递归):");
	MidOrder(T);
	// 中序遍历 栈实现 打印数据
	printf("\n中序遍历(利用栈实现):");
	MidOrderByStack(T);

	// 后序遍历 递归 
	printf("\n后序遍历(利用递归):");
	LastOrder(T);
	// 后序遍历 栈实现 打印数据
	printf("\n后序遍历(利用栈实现):");
	LastOrderByStack(T);

	system("pause>0");
  	return 0;
}
// 1.创建节点 并 插入进行链接 注意要传递二级指针,因为要进行改变节点
void CreateAndInsert(TreeNode** T, int data)
{
	// 检验参数合法性
	if (NULL == T)
	{
		return;
	}
	// 判断树是否有节点 (空树)父节点 则进行创建节点操作
	if (NULL == *T)
	{
		// 动态申请内存空间 创建节点
		*T = (TreeNode*)malloc(sizeof(TreeNode));
		// 判空
		if (NULL == *T)
			return;
		// 给节点成员赋值
		(*T)->data = data;
		(*T)->height = 0;
		(*T)->LChild = NULL;
		(*T)->RChild = NULL;
	}
	else if (data < (*T)->data)
	{// 将节点插入到父节点的左孩子上
		// 利用递归 将节点插入到父节点的左孩子上
		CreateAndInsert(&(*T)->LChild, data);
		// 获取左右子树的高度 用于计算树的高度差
		int Lheight = getHeight((*T)->LChild);
		int Rheight = getHeight((*T)->RChild);
		// 判断高度差
		if (Lheight - Rheight == 2)
		{
			// 通过要插入的节点数据与父节点的数据比较大小进行调整
			if (data < (*T)->LChild->data)
			{
				// 进行LL 调整 参数1:父节点 参数2:父节点地址
				LL_Rotation(*T, T);
			}
			else
			{
				// 进行LR 调整
				// 先进行RR 调整
				RR_Rotation((*T)->LChild, &(*T)->LChild);
				// 再进行LL 调整
				LL_Rotation(*T, T);
			}
		}
	}
	else if (data > (*T)->data)
	{// 将节点插入到父节点的右孩子上
		// 利用递归 将节点插入到父节点的右孩子上
		CreateAndInsert(&(*T)->RChild, data);
		// 获取左右子树的高度 用于计算树的高度差
		int Lheight = getHeight((*T)->LChild);
		int Rheight = getHeight((*T)->RChild);
		// 判断高度差
		if (Rheight - Lheight == 2)
		{
			// 通过要插入的节点数据与父节点的数据比较大小进行调整
			if (data > (*T)->RChild->data)
			{
				// 进行RR 调整 参数1:父节点 参数2:父节点的地址
				RR_Rotation(*T, T);
			}
			else
			{
				// 进行RL 调整
				// 先进行LL 调整
				LL_Rotation((*T)->RChild, &(*T)->RChild);
				// 再进行RR 调整
				RR_Rotation(*T, T);
			}
		}
	}
	// 调整树的高度
	(*T)->height = maxHeight(getHeight((*T)->LChild), getHeight((*T)->RChild)) + 1;
}
// 2.前序遍历 根左右
void PreOrder(TreeNode* T)
{
	// 当节点不为空时 进行遍历输出
	if (NULL != T)
	{
		// 直接先打印节点数据
		printf("%d  ", T->data);
		// 递归 打印左孩子节点
		PreOrder(T->LChild);
		// 递归 打印右孩子节点
		PreOrder(T->RChild);
	}
}
// 2.1、前序遍历 栈实现 根左右
void PreOrderStack(TreeNode* T)
{
	// 当节点为空时,退出函数
	if (NULL == T)
		return;
	// 声明数组(栈)
	TreeNode* stack[100];
	// 定义用于下标的变量
	int stackTop = -1;
	// 定义移动指针
	TreeNode* pMove = T;
	// 进行循环输出数据 前序遍历
	while (-1 != stackTop || NULL != pMove)
	{
		// 入栈操作 移动指针左移
		while (NULL != pMove)
		{
			// 前序遍历先打印数据
			printf("%d  ", pMove->data);
			// 入栈操作 将移动指针装进数组中
			stack[++stackTop] = pMove;		
			// 移动指针左移
			pMove = pMove->LChild;
		}
		// 出栈操作 移动指针右移
		if (-1 != stackTop)
		{
			// 将数组元素赋给移动指针
			pMove = stack[stackTop--];
			// 移动指针右移
			pMove = pMove->RChild;
		}
	}
	printf("\n");
}
// 3.中序遍历 递归 左根右
void MidOrder(TreeNode* T)
{
	// 当节点不为空时 进行打印数据
 	if (NULL != T)
	{
		// 打印左孩子节点 递归调用
		MidOrder(T->LChild);
		// 打印数据
		printf("%d  ", T->data);
		// 打印右孩子节点 递归调用
		MidOrder(T->RChild);
	}
}
// 3.1、中序遍历 栈实现 左根右
void MidOrderByStack(TreeNode* T)
{
	// 当节点为空时,退出函数
	if (NULL == T)
		return;
	// 声明数组(栈)
	TreeNode* stack[100];
	// 定义用于下标的变量
	int stackTop = -1;
	// 定义移动指针
	TreeNode* pMove = T;
	// 进行遍历 中序遍历 入栈、出栈操作
	while (-1 != stackTop || NULL != pMove)
	{
		// 入栈
		while (NULL != pMove)
		{
			// 入栈 将移动指针装进数组中
			stack[++stackTop] = pMove;
			// 移动指针左移
			pMove = pMove->LChild;
		}
		// 出栈
		if (-1 != stackTop)
		{
			// 出栈操作 将数组元素赋给移动指针
			pMove = stack[stackTop--];
			// 打印数据
			printf("%d  ", pMove->data);
			// 移动指针右移
			pMove = pMove->RChild;
		}
	}
}
// 4.后序遍历 递归
void LastOrder(TreeNode* T)
{
	// 当节点不为空时 进行打印数据操作
	if (NULL != T)
	{
		// 左右根
		LastOrder(T->LChild);
		LastOrder(T->RChild);
		// 打印数据 根
		printf("%d  ", T->data);
	}
}
// 4.1、后序遍历 栈实现
void LastOrderByStack(TreeNode* T)
{
	// 当节点为空时 退出函数
	if (NULL == T)
		return;
	// 声明数组 栈
	TreeNode* stack[100];
	// 定义用于下标的变量
	int stackTop = -1;
	// 定义移动指针
	TreeNode* pMove = T;
	// 声明一个记录已打印数据的指针
	TreeNode* pPreMove = NULL;

	// 循环入栈操作
	while (NULL != pMove)
	{
		// 入栈 将移动指针装进数组中
		stack[++stackTop] = pMove;
		// 移动指针左移
		pMove = pMove->LChild;
	}
	// 出栈操作
	while (-1 != stackTop)
	{
		// 出栈 将数组元素赋给移动指针
		pMove = stack[stackTop--];
		// 判断是否进行打印数据 当右节点为空,或是右节点已被访问,则进行打印数据操作
		if (NULL == pMove->RChild || pPreMove == pMove->RChild)
		{
			// 打印数据
			printf("%d  ", pMove->data);
			// 记录已打印的数据节点
			pPreMove = pMove;
		}
		else 
		{
			if (NULL != pMove)
			{
				// 入栈 将移动指针装进数组中
				stack[++stackTop] = pMove;
				// 移动指针右移
				pMove = pMove->RChild;
			}
			// 移动指针左移
			while (NULL != pMove)
			{
				// 入栈 将移动指针装进数组中
				stack[++stackTop] = pMove;
				// 移动指针左移
				pMove = pMove->LChild;
			}
		}
	}
}
// 5.获取树节点的高度
int getHeight(TreeNode* tree)
{
	// 当树不为空时,返回节点的高度
	if (NULL != tree)
	{
		return tree->height;
	}
	return 0;
}
// 5.1、获取树节点的最大高度 左右子树的最大高度
// 参数1:左子树高度  参数2:右子树高度
int maxHeight(int leftHeight, int rightHeight)
{
	// 比较返回最大值
	if (leftHeight > rightHeight)
	{
		return leftHeight;
	}
	else
	{
		return rightHeight;
	}
}
//6.1、 进行LL 调整 参数1:父节点 参数2:父节点地址
void LL_Rotation(TreeNode* fatherNode, TreeNode** root)
{
	// 检验参数
	if (NULL == fatherNode)
		return;
	// 注意要判断父节点的左孩子是否为空
	if (NULL == fatherNode->LChild)
		return;

	// 获取中间节点
	TreeNode* midNode = fatherNode->LChild;
	// 如果中间节点有右孩子节点,将右孩子连接到父节点的左孩子上
	fatherNode->LChild = midNode->RChild;
	// 将父节点连接到中间节点的右孩子上
	midNode->RChild = fatherNode;
	
	// 获取父节点树的高度 最大高度 注意要+1操作 加上本身节点
	fatherNode->height = maxHeight(getHeight(fatherNode->LChild), getHeight(fatherNode->RChild)) + 1;
	// 获取中间节点树的高度 注意要+1操作 加上本身节点
	midNode->height = maxHeight(getHeight(midNode->LChild), getHeight(midNode->RChild)) + 1;

	// 将中间节点设置成根节点(父节点)
	*root = midNode;
}
//6.2、 进行RR 调整 参数1:父节点 参数2:父节点的地址
void RR_Rotation(TreeNode* fatherNode, TreeNode** root)
{
	// 检验参数
	if (NULL == fatherNode)
		return;
	// 
	// 获取中间节点
	TreeNode* midNode = fatherNode->RChild;
	// 将中间节点的左孩子插入到父节点的右孩子上
	fatherNode->RChild = midNode->LChild;
	// 将父节点连接到中间节点左孩子上
	midNode->LChild = fatherNode;
	
	// 获取父节点树的高度 注意要加上自身节点 +1
	fatherNode->height = maxHeight(getHeight(fatherNode->LChild), getHeight(fatherNode->RChild)) + 1;
	// 获取中间节点 树的高度 注意要加上自身节点 +1
	midNode->height = maxHeight(getHeight(midNode->LChild), getHeight(midNode->RChild)) + 1;
	
	// 重置根节点(父节点) 将中间节点置成根
	*root = midNode;
}

 程序运行结果:

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值