AVL添加平衡二叉树,是一种二叉排序树,其中每个结点的左子树和右子树的高度差至多等于1。-icoding-数据结构-C-typedef struct node{ int val;

AVL添加


平衡二叉树,是一种二叉排序树,其中每个结点的左子树和右子树的高度差至多等于1。
它是一种高度平衡的二叉排序树。现二叉平衡树结点定义如下:

typedef struct node
{
    int val;
    struct node *left;
    struct node *right;
    struct node *parent;
    int height;
} node_t;

请实现平衡二叉树的插入算法:

向根为 root 的平衡二叉树插入新元素 val,成功后返回新平衡二叉树根结点

node_t *avl_insert(node_t *root, int val);

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

int get_height(node_t *p){
	if(!p)
		return 0;
	else
		return p->height;
}

示例代码如下:

一定要超级仔细, 不然绝对后悔!


node_t* avl_insert(node_t *root, int val){
//首先清晰字母定义;
//val新插入结点元素值,height高度!!! 
//定义查找过程中出现的距离插入结点最近的平衡因子不为零的结点A
//定义A的孩子结点为B,需要旋转的结点
//定义插入节点为s,s的值为val
//平衡因子:左子树减去右子树深度 

	node_t *s, *A, *B, *C, *p, *fp;
	//依次:插入点, 失衡点(也可能是旋转点),旋转点,旋转点(也可能是插入点=s),动点,跟踪点
	int i, k;//平衡因子 
	
	s = (node_t *)malloc(sizeof(node_t));
	if(!s) return NULL;
	
	s->val = val;
	s->left = s->parent = s->right = NULL;
	s->height = 1;
	
	//类似于指针跟踪技术,p为动指针,A为跟踪指针 
	A = root; A->parent = NULL;
	p = root; p->parent = NULL;
	
	//找出A 
	if(!p)
		root = s;
	else{
		while(p){
			//先找出最近的A->height!=0的结点, 就是最后的失衡点
			i = get_height(p->left) - get_height(p->right); 
			if(i){
				A = p;
				A->parent = p->parent;
			}
			//fp跟踪p,因为下一步p会往下移动,p最终指向s的那一层 
			fp = p;
			if(val < p->val)
				p = p->left;
			else
				p = p->right;
			}//p最终指向NULL就推出循环	 
	} 
	
	//插入, 此时fp是p的前一个结点,p指向空 
	if(val < fp->val)
		fp->left = s;
	else
		fp->right = s;
		
	//确定旋转结点B,修改A的平衡因子
	if(val < A->val)
		B = A->left;
	else
		B = A->right;

	A->height++;
	
	//修改路径B到s的高度, B在A的下一层 
	p = B; // p最终指向s, 之前指向的是s这一层,但是是空

	while(p != s){
		p->height++;
		if(val < p->val)
			p = p->left; 
		else
			p = p->right;	
	}
	//最终s的高度没有++的 
		
	
	//调整完高度就修改结点和指针, 首先需要判断失衡类型
	//分为LL,LR,RR,RL
	//结点A,B平衡因子在修改指针的过程中会变化,但是路径上的结点不会
	//指针修改包括s结点指针和原来双亲结点指针 
	i = get_height(A->left) - get_height(A->right);
	k = get_height(B->left) - get_height(B->right); 
	
	if(i == 2 && k == 1){//LL
		//B作为旋转结点
		//先改结点指针, 此时s插入在B的左子树下, 原来可以认为B左右子树,A右子树均为空
		A->left = B->right;
		B->right = A;
		
		//考虑原来A结点的指针,改成B后相应的指针也要改变,下面同理
		if(A->parent == NULL)
			root = B;
		else if(A->parent->left == A)
			A->parent->left = B;
		else
			A->parent->right = B;		
	}
	else if(i == -2 && k == -1){//RR
		A->right = B->left;
		B->left = A;
		
		if(A->parent == NULL)
			root = B;
		else if(A->parent->left == A)
			A->parent->left = B;
		else
			A->parent->right = B;	
	}
	else if(i == 2 && k == -1){//LR
		//此时认为C的左右子树空,B逆时针旋转,A顺时针旋转, s插入C的左子树或者右子树 
		//如果C结点也是空,也就是说B右子树空,那么直接插入C=s为B右子树,此时A右子树也是空的 
		C = B->right;
		B->right = C->left;
		A->left = C->right;
		C->left = B;
		C->right = A;
		
		if(A->parent == NULL)
			root = C;
		else if(A->parent->left == A)
			A->parent->left = C;
		else
			A->parent->right = C;
	}
	else if(i == -2 && k == 1){//RL 
		//和LR一样,画图来看就好
		C = B->left;
		A->right = C->left;
		B->left = C->right;
		C->left = A;
		C->right = B;
		
		if(A->parent == NULL)
			root = C;
		else if(A->parent->left == A)
			A->parent->left = C;
		else
			A->parent->right = C;
	}
	return root;
}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风起风里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值