第六章第二节(左式堆)

左式堆是一种特殊的二叉堆,用于提高合并效率。它不是完全二叉树,而是左倾的不平衡二叉树。左式堆的每个节点具有堆序性质,且左儿子的零路径长不少于右儿子。插入和删除操作通过合并实现,合并过程中始终保持左倾特性。代码示例展示了左式堆的节点结构、初始化、查找最小值、判断空堆、插入和删除等操作,以及合并函数的递归实现,确保合并效率为O(logN)。
摘要由CSDN通过智能技术生成

左式堆是在二叉堆的基础上出现的,主要是为了解决二叉堆合并的效率。
二叉堆合并H1与H2的合并,依此将H2中的根节点删除并插入H1节点中,从而完成合并。

左式堆的结构
1.左式堆具有堆序性质,左式堆不是完全二叉树,是趋于左倾的不平衡二叉树。

左式堆的性质
1.把任一节点X的零路径长Npl(X)定义为X到一个没有两个儿子的节点的最短路径长,即有一个子节点或零个子节点的节点X的Npl值为0。
2.对于堆中的每一个节点X,左儿子的零路径长,至少与右儿子的零路径长一样。(这个性质确保了树不平衡的要求,更偏重于使树向左增加深度。)

左式堆的操作
1.合并
2.插入,插入是合并的一种特殊情况,把插入的节点看作一个单结点的左式堆与一个大的左式堆合并
3.删除,将左式堆的根节点删除,得到两个子树,将两个子树合并即可

合并的递归实现思路
1.如果两个堆由一个堆是空的,就返回另外一个堆。
2.如果两个堆都不为空,则比较两个堆根值的大小,将根值大的堆与根值小的堆的右子树进行合并,直到合并完成

左式堆的数据结构
每个节点除了包括属性值,左指针,右指针,还包括一个指示零路径长的项。

左式堆总是在右边做堆合并,保持左边不变,左式的合并的效率取决于右路径的节点长度。左式堆的合并效率为 O(log N)

代码

头文件即数据结构

#include<stdio.h>
#include<stdlib.h>
struct TreeNode;
typedef struct TreeNode *PriorityQueue;
//节点的数据结构
struct TreeNode {
	int Element;			//属性值
	PriorityQueue Left;		//左指针
	PriorityQueue Right;	//右指针
	int Npl;				//零路径长
};
//函数的声明
PriorityQueue Initialize();
int FindMin(PriorityQueue H);
int IsEmpty(PriorityQueue H);
PriorityQueue Merge(PriorityQueue H1,PriorityQueue H2);
#define Insert(X,H) (H = Insert1((X),H))
#define DeleteMin(H) (H = DeleteMin1(H))
PriorityQueue Insert1(int X, PriorityQueue H);
PriorityQueue DeleteMin1(PriorityQueue H);
static PriorityQueue Merge1(PriorityQueue H1,PriorityQueue H2);

函数的实现

PriorityQueue Initialize(void) {	//左式堆初始化
	return NULL;
}
int IsEmpty(PriorityQueue H) {		//判断堆是否为空
	if (H == NULL) {
		return 1;
	}
	return 0;
}
int FindMin(PriorityQueue H) {		//找到最小的值,即树根位置
	if (!IsEmpty(H)) {
		return H->Element;
	}
	return NULL;
}

插入及删除函数

PriorityQueue Insert1(int X, PriorityQueue H) {			//插入堆
	//创建一个单节点的堆,与大的堆进行合并操作
	PriorityQueue NewHeap = (PriorityQueue)malloc(sizeof(struct TreeNode));
	NewHeap->Element = X;
	NewHeap->Left = NULL;
	NewHeap->Right = NULL;
	NewHeap->Npl = 0;
	H = Merge(H, NewHeap);
	return H;
}
PriorityQueue DeleteMin1(PriorityQueue H) {				//删除根节点,调整堆
	//将堆的根节点删除,将左右子树合并为一个左式堆。
	if (IsEmpty(H)) {
		printf("堆为空!\n");
		return H;
	}
	PriorityQueue LeftHeap, RightHeap;
	LeftHeap = H->Left;
	RightHeap = H->Right;
	free(H);		//释放根节点
	return Merge(LeftHeap, RightHeap);		//合并左右子树
}

合并函数

PriorityQueue Merge(PriorityQueue H1, PriorityQueue H2) {
	//合并操作,判断两个堆是否为空,并比较两个堆根节点的大小,将根节点大的与根节点小的合并
	if (H1 == NULL) {
		return H2;
	}
	if (H2 == NULL) {
		return H1;
	}
	if (H1->Element<H2->Element) {
		return Merge1(H1, H2);
	}
	return Merge1(H2, H1);
}
static PriorityQueue Merge1(PriorityQueue H1,PriorityQueue H2) {
	//将H2与H1的右子树合并
	if (H1->Left == NULL) {		
		H1->Left = H2;	//H1是一个单节点,H1的右子树已为空,H1的零路径长为0
	}
	else {
		H1->Right = Merge(H1->Right, H2);		//将H2与H1的右子树合并
		if (H1->Left->Npl < H1->Right->Npl) {
			//如果右子树的Npl 大于 左子树的 Npl,两个子树进行交换即可保持左式堆的性质
			PriorityQueue T;
			T = H1->Left;
			H1->Left = H1->Right;
			H1->Right = T;
		}
		H1->Npl = H1->Right->Npl + 1;		//更新零路径长度,为右子树零路径长+1
	}
	return H1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值