数据结构与算法-BST(二叉搜索树)、AVL树(平衡二叉树)

本文详细介绍了二叉搜索树(BST)的特点、结构和操作,包括创建、插入、查找和删除。特别强调了删除操作的三种情况。接着深入探讨了AVL树(平衡二叉树)的概念、平衡因子、旋转操作及其在解决BST不平衡问题上的作用。插入和删除在AVL树中的处理保证了树的平衡,从而提高了查找效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1二叉查找树

1.1特点

  1. 任意节点的左子树不空, 则左子树上所有节点的key均小于它的根节点的key
  2. 任意节点的右子树不空, 则右子树上所有节点的key均大于它的根节点的key
  3. 任意节点的左,右子树也分别为二叉查找树
  4. 没有key相等的节点
  5. 二叉查找树进行中序遍历,可以得到一个递增的有序序列

在这里插入图片描述

1.2结构

struct Node {
    int key;
    struct Node* left;
    struct Node* right;
}

1.3操作

1.3.1创建

1.3.2插入

Node* Insert(Node*& node, int key){
if(!search(node,key)){
    if(NULL == node) {
    	node = new Node(key);
    }
    if (key < node->key){
    	 node->left = Insert(node->left, key);
    }else if (key > node->key){
     node->right = Insert(node->right,key);
     }    
    return node;
}else{
		return NULL:
}
}

1.3.3查找

Node* Search(Node* node, int key){
    if(NULL == node) {
    	return NULL;
    }
    if (key < node->key){
     	return Search(node->left, key);
     }else if (key > node->key) {
     	return Search(node->right, key);
     }
    return node;
}

1.3.4删除

二叉查找树的删除操作是相对复杂一点,它要按 3 种情况来处理
1:被删除结点是叶子结点,直接删除
2:结点只有左子树或只有右子树,则让子树替代
3:结点既有左子树,又有右子树,有两种处理方式

1: 替代删除,后继代替删除节点,然后删除后继;或者前驱代替删除节点,然后删除前驱。

2:合并删除,右子树合并到左子树的最大值的右子树上;或者左子树合并到右子树最小值的左子树上。

在这里插入图片描述 在这里插入图片描述

Node* DeleteBST(Node** T, int key){
	if(!*T){
		return false;
	}else{
		if(key==(*T)->key)){
			return Delete(T);
		}
		else if(key<(*T)->key){
			return DeleteBST(&(*T)->left, key);
		}
		else{
			return DeleteBST(&(*T)->right, key);
		}
	}
}
Node* DeleteBST(Node** p){
	Node * q,s;
	//	
	if((*p)->rchild==NULL){
		q=*p;
		*p=(*p)->lchild;
		free(q);
	}
	else if((*p)->lchild==NULL){
		q=*p;
		*p=(*p)->rchild;
		free(q);
	}
	else{
		q=*p;
		s=(*p)->lchlid;
		while(s->rchild){
			q=s;
			s=s->lchlid;
		}
		//只是把前驱的值放在了删除结点上
		(*p)->data=s->data;
		//有右子树 
		if(q!=*p){
			q->rchild=s->lchild;
		}else{//没有
			q->lchild=s->lchlid;
		}
		free(s);		
	}
return true;
}

BST树的缺点不平衡所有有下面的AVL树

2.AVL树(平衡二叉树)

2.1概念

平衡二叉树/自平衡二叉查找树(Balanced Binary Tree): 也称为AVL树(名称来自发明人G.M. Adelson-Velsky 和 E.M. Landis的首字母),它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树树快速查找的关键是高度要低,高度低的关键是平衡

非平衡二叉树
在这里插入图片描述
平衡二叉树
在这里插入图片描述

2.2平衡因子

平衡因子BF(Balance Factor):左树深度减去右树深度的值。平衡因子BF = 左子树深度-右子树深度。
平衡二叉树每个结点的平衡因子只能是1,0,-1。若其绝对值超过1,则该二叉排序树就是不平衡的。当BF为-1、0、1时,二叉树平衡;反之,不平衡。

两种旋转(左旋/右旋)、三个节点(新插入节点/不平衡节点/旋转节点)、四种不平衡(LL/RR/RL/LR)。

2.3两种旋转

旋转条件
当最小不平衡子树根节点 BF>1,右旋BF<-1,左旋
在这里插入图片描述

旋转步骤:

  1. 获取旋转节点
  2. 旋转节点的子节点替换父节点的旋转节点
  3. 旋转节点父节点做旋转节点子节点
  4. 返回旋转节点

2.3.1左旋

void R_Rotate(Tree *p){
	Tree L;
	L=(*p)->Rchild;
	(*p)->rchild=L->lchild;
	L->lchild=(*p);
	(*p)=L
}

2.3.1右旋

void R_Rotate(Tree *p){
	Tree L;
	L=(*p)->lchild;
	(*p)->lchild=L->rchild;
	L->rchild=(*p);
	(*p)=L
}

2.4四种不平衡

类别说明
LL 左左情况插入一个新节点到不平衡节点的左子树(Left)的左子树(Left),导致不平衡节点的平衡因子由1变为
RR 右右情况插入一个新节点到不平衡节点的右子树(Right)的右子树(Right),导致不平衡节点的平衡因子由-1变为-2
LR 左右情况插入一个新节点到不平衡节点的左子树(Left)的右子树(Right),导致不平衡节点的平衡因子由1变为2
RL 右左情况插入一个新节点到不平衡节点的右子树(Right)的左子树(Left),导致不平衡节点的平衡因子由-1变为-2

在这里插入图片描述

2.4.1左平衡

void LeftBalance(Tree *T){
	Tree L,Lr;
	L=(*T)->lchild;
	switch(L->bf){
		case LH:
			(*T)->bf=L->bf=EH;
			R_Rotate(T);
			break;
		case RH;
			Lr=L->rchild;
			switch(Lr->bf){
				case LH://1
						(*T)->bf=RH;
						L->bf=EH;
						break;
				case EH://0
						(*T)->bf=L->bf=EH;
						break;
				case RH://-1
						(*T)->bf=EH;
						L->bf=LH;
						break;
			}
			Lr->bf=EH;
			L_Rotate(&(*T)->lchild);
			R_Rotate(T);
	}
}

2.4.1右平衡

void LeftBalance(Tree *T){
	Tree L,Ll;
	L=(*T)->rchild;
	switch(L->bf){
		case RH:
			(*T)->bf=L->bf=EH;
			L_Rotate(T);
			break;
		case LH;
			Ll=L->lchild;
			switch(Ll->bf){
				case LH://1/??????
						(*T)->bf=LH;
						L->bf=EH;
						break;
				case EH://0
						(*T)->bf=L->bf=EH;
						break;
				case RH://-1//?????
						(*T)->bf=EH;
						L->bf=RH;
						break;
			}
			Ll->bf=EH;
			R_Rotate(&(*T)->lchild);
			L_Rotate(T);
	}
}

2.5插入

typedef struct BiTNode{
	int data;
	int bf;
	struct BitNode *lchild; *rchild;
}Node,*Tree;

int Insert_AVL(Tree *T,int e,int *taller){
	if(!*T){
		*T=(Tree)malloc(sizof(Node));
		(*T)->lchild=NULL;
		(*T)->Nchild=NULL;
		(*T)->bf=EH;
		*taller=TRUE;
	}else{
		if(e==(*T)0>data){
			*taller=FALSE;
			return FALSE;
		}
		if(e<(*T)->data){
			if(!Insert_AVL(&(*T)->lchild, e,taller)){
				return FALSE;
			}
			if(*taller){
				switch((*T)->bf){
					case LH://1
						LeftBalance(T);//左平衡操作
						*taller=FALSE;
						break;
					case EH://本身是平衡的所以插入左变 就将不平衡
						(*T)->bf=LH;
						*taller=TRUE;
						break;
					case RH://-1
						(*T)->bf=EH;
						*taller=FALSE;
						break;
				}
			}
		}else{
		if(!Insert_AVL(&(*T)->rchild, e,taller)){
				return FALSE;
			}
			if(*taller){
				switch((*T)->bf){
					case LH://1
						(*T)->bf=EH;
						*taller=FALSE;
						break;
					case EH://本身是平衡的所以插入左变 就将不平衡
						(*T)->bf=RH;
						*taller=TRUE;
						break;
					case RH://-1
						RightBalance(T);//右平衡操作
						*taller=FALSE;
						break;
				}
			}
		}
	}
}

2.6删除

做一门精致,全面详细的 java数据结构算法!!!让天下没有难学的数据结构,让天下没有难学的算法,不吹不黑,我们的讲师及其敬业,可以看到课程视频,课件,代码的录制撰写,都是在深夜,如此用心,其心可鉴,他不掉头发,谁掉头发???总之你知道的,不知道的,我们都讲,并且持续更新,走过路过,不要错过,不敢说是史上最全的课程,怕违反广告法,总而言之,言而总之,这门课你值得拥有,好吃不贵,对于你知识的渴求,我们管够管饱话不多说,牛不多吹,我们要讲的本门课程内容:稀疏数组、单向队列、环形队列、单向链表、双向链表、环形链表、约瑟夫问题、栈、前缀、中缀、后缀表达式、中缀表达式转换为后缀表达式、递归回溯、迷宫问题、八皇后问题、算法的时间复杂度、冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、基数排序(桶排序)、堆排序、排序速度分析、二分查找、插值查找、斐波那契查找、散列、哈希表、二叉、二叉数组转换、二叉排序(BST)AVL、线索二叉、赫夫曼、赫夫曼编码、多路查找(BB+和B*)、图、图的DFS算法和BFS、程序员常用10大算法、二分查找算法(非递归)、分治算法、动态规划算法、KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法马踏棋盘算法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值