数据结构——第四讲、树(二叉搜索树与平衡二叉树)

4.1 二叉搜索树

操作集:

Position Find(ElementType x, BinTree T);
Position FindMin(BinTree T);
Position FindMax(BinTree T);

BinTree Insert(ElementType x, BinTree T);
BinTree Delete(ElementType x, BinTree T);
  • 查找
Position Find(ElementType x, BinTree T){
	if(!T)return NULL;
	while(T){
		if(x > T->Data)
			T = T->Right;
		else if(x < T->Data)
			T = T->Left;
		else
			return T;
	}
	return NULL;
}
  • 查找最大最小节点
Position FindMin(BinTree T){
	if(!T)return NULL;
	while(T->Left){
		T = T->Left;
	}
	return T;
}
Position FindMax(BinTree T){
	if(!T)return NULL;
	while(T->Right){
		T = T->Right;
	}
	return T;
}
  • 插入
BinTree Insert(ElementType x, BinTree T){
	if(!T){
		Position a = (Position)malloc(sizeof(struct TNode));
		a->Data = x;
		a->Left = NULL;
		a->Right = NULL;
		return a;
	}
	if(x > T->Data)
		T->Right = Insert(x,T->Right);
	else if(x < T->Data)
		T->Left = Insert(x,T->Left);
	return T;
}
  • 删除
BinTree Delete(ElementType x, BinTree T){
	Position temp = NULL;
	if(!T)return NULL;
	if(x > T->Data)
		T->Right = Delete(x,T->Right);
	else if(x < T->Data)
		T->Left = Delete(x,T->Left);
	else{//找到要删除的元素,分“有两个儿子”、“一个或没有儿子”两种情况。
		if(T->Left && T->Right){
			//找左子树的最大值替换当前要删除的节点,然后再去左子树把最大的节点删除
			//删除最大的节点肯定不是“有两个儿子的情况”。
			temp = FindMax(T->Left);
			T->Data = temp->Data;
			T->Left = Delete(T->Data, T->Left);
		}
		else{
			//只有一个儿子时,释放当前节点空间并返回自己的儿子
			temp = T;
			if(T->Left)
				T = T->Left;
			else if(T->Right)
				T = T->Right;
			else//没有儿子时直接释放当前节点空间
				T = NULL;
			free(temp);
		}
	}
	return T;
}

4.2 平衡二叉树

  二叉搜索树插入节点的顺序不同,得到的二叉树的搜索效率也会发生变化,自然而然的我们就会产生一个疑问,什么样的树比较好?答案就是平衡二叉树。完全二叉树或满二叉树都是平衡二叉树。
  平衡二叉树是树上所有的节点的平衡因子都为1(这个平衡因子就是这个节点左右子树的高度差)。
  平衡二叉树的高度和节点数的关系是 log n(节点数为n个时,平衡二叉树的高度大约为log n级别) 。

一个已经平衡的二叉树,如果插入节点就会使它不平衡,为此需要做一些调整,分为四种不同情况:RR、RL、LL、LR。

  • RR:插在某节点右儿子的右边;
  • LL:插在某节点左儿子的左边;
  • RL:插在某节点右儿子的左边;
  • LR:插在某节点左儿子的右边;

卧槽,平衡二叉树点击量格外高,本来打算以后再写的,所有的代码在中国大学mooc网浙江大学的数据结构课里面都有,有的在视频里有的在课后的文本里面,有需要的可以直接去看原版。

//先定义AVL树的节点
typedef struct AVLNode *AVLTree;
struct AVLNode{
	ElementType Data;
	AVLTree Left;
	AVLTree Right;
	int Height;
}
//需要一个返回最大值的函数用来更新树高
Max(int a, int b){return a>b?a:b;}
//用四个函数做调整,传入一个不平衡的二叉树的根节点,返回一个平衡的二叉树的根节点;

//插在左儿子的左边,就把它的左儿子提上来,把左儿子的右边接到它的左边(因为左儿子的右边比左儿子大比它小)
AVLTree LLRotation(AVLTree A){
	AVLTree B = A->Left;
	A->Left = B->Right;
	B->Right = A;
	/*只有某个节点的左右子树发生变化了,它自己的高度才会发生变化,否则它自己的高度不变,而且这里必须先更新A的高度,因为更新B的高度的时候要用到A的高度。*/
	A->Height = Max(A->Left->Height,A->Right->Height)+1;
	B->Height = Max(B->Left->Height,A->Height)+1;   //B的Right就是A;
	return B;
}

//插在右儿子的右边,与LL类似,把右儿子提上来,右儿子的左边接在它的右边
AVLTree RRRotation(AVLTree A){
	AVLTree B = A->Right;
	A->Right = B->Left;
	B->Left = A;
	A->Height = Max(A->Left->Height,A->Right->Height)+1;
	B->Height = Max(B->Left->Height,A->Height)+1;
	return B;
}

//插在右儿子的左边,需要先将右儿子LL旋,然后再将它自己RR旋转回来,画图可以更清楚的看到实际上做了哪些调整。
AVLTree RLRotation(AVLTree A){
	A->Right = LLRotation(A->Right);
	return RRRotation(A);
}

//同理可得LR
AVLTree LRRotation(AVLTree A){
	A->Left = RRRotation(A->Left);
	return LLRotation(A);
}

//插入函数本体,输入要插入的数据和平衡树,返回已经插入好的平衡树。
AVLTree Insert(ElementType x, AVLTree T){
	if(!T){
		T = (AVLTree)malloc(sizeof(struct AVLNode));
		T->Data = x;
		T->Left = T->Right = NULL;
		T->Height = 0;
	}
	else{
		if(x > T->Data){
			T->Right = Insert(x,T->Right);
			if(T->Right->Height - T->Left->Height == 2){
				if(x > T->Right->Data)
					T = RRRotation(T);
				else
					T = RLRotation(T);
			}
		}
		else if(x < T->Data){
			T->Left = Insert(x,T->Left);
			if(T->Left->Height - T->Right->Height == 2){
				if(x < T->Left->Data)
					T = LLRotation(T);
				else
					T = LRRotation(T);
		}
	}
	T->Height = Max(T->Right->Height,T->Left->Height)+1;
	return T;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值