手写堆模板(指针数组)

使用说明

本文的堆以小根堆为例,给出模板
使用时将ElementType 修改为对应的数据类型就好

1.插入式建堆

建一个空堆,将元素一个一个插入,调整

#include <cstdio>
#include <cstdlib>

using namespace std;

typedef struct HeapStruct {
	ElementType *Element;
	int Size;
	int MaxSize;
} Heap, *MinHeap;

// 方法一: 创建一个大小为 MaxSize 的堆 
MinHeap Create_Heap(int MaxSize) {
	MinHeap heap = (MinHeap *) malloc (sizeof(Heap)); //  申请一个堆 
	heap->Element = (ElementType *) malloc (MaxSize+1)*sizeof(ElementType); // 为堆申请存储元素的空间大小,即堆的能够存储的结点数 
	heap->Size = 0;	// 堆的当前元素数 
	heap->MaxSize = MaxSize; // 堆的最大存储空间 
	heap->Element[0] = INT_MIN; // 将指针数组的 0 号位置置为无穷小,堆顶从 1 号开始 
}

// 使用后释放堆申请的空间 
void Destroy(MinHeap heap) {
	free(heap->Element); // 先释放堆结点的数组空间 
	free(heap);	// 再释放堆结点的空间 
} 

// 判断堆是否为空
bool IsEmpty(MinHeap heap) {
	return (heap->Size == 0);
}

// 判断堆是否满了 
bool IsFull(MinHeap heap, ElementType Size) {
	return (heap->Size == heap->MaxSize);
} 

// 向堆中插入元素 
void Insert(MinHeap heap, ElementType item) {
	int i = 0;
	
	// 检查是否有空间可以插入元素
	if(IsFull(heap)) {
		printf("Heap is full!\n");
		return ;
	} 
	
	/*
	将item加入为堆的一个叶子结点,然后向上调整至合适的位置插入,到堆顶结束
	*/
	
	heap->Size ++; // 堆中的元素数量增加1
	
	for(i = heap->Size; heap->Element[i / 2] > item; i = i / 2) { // 向上与父节点做比较 
		heap->Element[i] = heap->Element[i / 2]; // 父节点下移 
	} 
	
	heap->Element[i] = item;
}

// pop并返回堆顶 
ElementType Pop(MinHeap heap) { 
	ElementType item, temp; // 取出堆顶
	int parent = 0, child = 0;
	
	if(IsEmpty(heap)) {
		printf("Heap is Empty!\n");
		return heap->Element[0]; // 相当于一种安全保护 
	}
	
	/*
	如果堆不空,则将堆顶取出作为返回值,
	将最后一个结点也就是二叉堆的一个叶子结点放在堆顶。
	将堆顶向下调整至合适位置后停止 
	*/ 
	item = heap->Element[1];
	temp = heap->Element[heap->Size];
	heap->Size --; // 堆中元素减少一个
	
	for(int parent = 1; parent * 2 <= heao->Size; parent = child) {
		child = parent * 2;
		// 找出左右子节点中较小的那个
		if(child != heap->Size && (heap->Element[child] > heap->Element[child + 1])) {
			child++;
		} 
		
		// 比较父节点与子节点的大小,如果父节点大就,则二者互换位置继续寻找合适的插入位置,否则?
		if(temp > heap->Element[child]) {
			heap->Element[parent] = heap->Element[child];
		}
		else break;
	}
	heap->Element[child] = temp;
	return item;
} 

int main() {
	int x, n;
	scanf("%d", &n);
	MinHeap H = Create(n);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &x);
		Insert(H, x);
	}
	return 0;
}

2.直接在数组基础上调整排序建堆

直接将存数据的数组建堆,从每颗小的子树开始调整,

// 方法二: 已知一个数组,创建一个由数组组成的最小堆
MinHeap BuildMinHeap(ElementType *Element, int Size, int MaxSize) {
	MinHeap H = Create(MaxSize); // 创建一个空的
	ElementType temp;
	int parent = 0, child = 0;
	// 判断存储空间够不够用
	if (Size > H->MaxSize) {
		printf("最小堆的存储空间不够用\n");
		return NULL; 
	} 
	
	// 将数组中的元素先全部复制到堆里
	for(int i = 0; i < Size; i++) {
		H->Element[i+1] = Element[i];
	} 
	H->Size = Size;
	
	// 给最小堆元素排序
	/*
	从最后一个节点的父节点开始,自右向左,自下向上将每个父节点与其两个子节点做比较后上调
	直到堆顶与其左右子节点做比较 ,然后将堆顶下沉
	该建堆方法比一个一个插入更优,因为不需要将叶子结点从堆顶移动到叶子位置(当然最坏情况是一样的) 
	*/
	for(parent = H->Size / 2; parent >= 1; parent--) {
		temp = H->Element[parent];
		for(; parent * 2 <= H->Size; parent = child) {
			child = parent * 2;
			
			// 如果左右子树都存在,将父节点与其中较小的比较后选择是否下沉
			if(child != H->Size && (H->Element[child] > H->Element[child + 1])) {
				child ++;
			}
			
			// 选择父节点是否下沉
			if(temp > H->Element[child]) {
				H->Element[parent] = H->Element[child];
			} 
			else break;
		}
		H->Element[parent] = temp;
	}
	return H;
} 

完整代码

#include <cstdio>
#include <cstdlib>

using namespace std;

typedef struct HeapStruct {
	ElementType *Element;
	int Size;
	int MaxSize;
} Heap, *MinHeap;

// 方法一: 创建一个大小为 MaxSize 的堆 
MinHeap Create_Heap(int MaxSize) {
	MinHeap heap = (MinHeap *) malloc (sizeof(Heap)); //  申请一个堆 
	heap->Element = (ElementType *) malloc (MaxSize+1)*sizeof(ElementType); // 为堆申请存储元素的空间大小,即堆的能够存储的结点数 
	heap->Size = 0;	// 堆的当前元素数 
	heap->MaxSize = MaxSize; // 堆的最大存储空间 
	heap->Element[0] = INT_MIN; // 将指针数组的 0 号位置置为无穷小,堆顶从 1 号开始 
}

// 方法二: 已知一个数组,创建一个由数组组成的最小堆
MinHeap BuildMinHeap(ElementType *Element, int Size, int MaxSize) {
	MinHeap H = Create(MaxSize); // 创建一个空的
	ElementType temp;
	int parent = 0, child = 0;
	// 判断存储空间够不够用
	if (Size > H->MaxSize) {
		printf("最小堆的存储空间不够用\n");
		return NULL; 
	} 
	
	// 将数组中的元素先全部复制到堆里
	for(int i = 0; i < Size; i++) {
		H->Element[i+1] = Element[i];
	} 
	H->Size = Size;
	
	// 给最小堆元素排序
	/*
	从最后一个节点的父节点开始,自右向左,自下向上将每个父节点与其两个子节点做比较后上调
	直到堆顶与其左右子节点做比较 ,然后将堆顶下沉
	该建堆方法比一个一个插入更优,因为不需要将叶子结点从堆顶移动到叶子位置(当然最坏情况是一样的) 
	*/
	for(parent = H->Size / 2; parent >= 1; parent--) {
		temp = H->Element[parent];
		for(; parent * 2 <= H->Size; parent = child) {
			child = parent * 2;
			
			// 如果左右子树都存在,将父节点与其中较小的比较后选择是否下沉
			if(child != H->Size && (H->Element[child] > H->Element[child + 1])) {
				child ++;
			}
			
			// 选择父节点是否下沉
			if(temp > H->Element[child]) {
				H->Element[parent] = H->Element[child];
			} 
			else break;
		}
		H->Element[parent] = temp;
	}
	return H;
} 

// 使用后释放堆申请的空间 
void Destroy(MinHeap heap) {
	free(heap->Element); // 先释放堆结点的数组空间 
	free(heap);	// 再释放堆结点的空间 
} 

// 判断堆是否为空
bool IsEmpty(MinHeap heap) {
	return (heap->Size == 0);
}

// 判断堆是否满了 
bool IsFull(MinHeap heap, ElementType Size) {
	return (heap->Size == heap->MaxSize);
} 

// 向堆中插入元素 
void Insert(MinHeap heap, ElementType item) {
	int i = 0;
	
	// 检查是否有空间可以插入元素
	if(IsFull(heap)) {
		printf("Heap is full!\n");
		return ;
	} 
	
	/*
	将item加入为堆的一个叶子结点,然后向上调整至合适的位置插入,到堆顶结束
	*/
	
	heap->Size ++; // 堆中的元素数量增加1
	
	for(i = heap->Size; heap->Element[i / 2] > item; i = i / 2) { // 向上与父节点做比较 
		heap->Element[i] = heap->Element[i / 2]; // 父节点下移 
	} 
	
	heap->Element[i] = item;
}

// pop并返回堆顶 
ElementType Pop(MinHeap heap) { 
	ElementType item, temp; // 取出堆顶
	int parent = 0, child = 0;
	
	if(IsEmpty(heap)) {
		printf("Heap is Empty!\n");
		return heap->Element[0]; // 相当于一种安全保护 
	}
	
	/*
	如果堆不空,则将堆顶取出作为返回值,
	将最后一个结点也就是二叉堆的一个叶子结点放在堆顶。
	将堆顶向下调整至合适位置后停止 
	*/ 
	item = heap->Element[1];
	temp = heap->Element[heap->Size];
	heap->Size --; // 堆中元素减少一个
	
	for(int parent = 1; parent * 2 <= heao->Size; parent = child) {
		child = parent * 2;
		// 找出左右子节点中较小的那个
		if(child != heap->Size && (heap->Element[child] > heap->Element[child + 1])) {
			child++;
		} 
		
		// 比较父节点与子节点的大小,如果父节点大就,则二者互换位置继续寻找合适的插入位置,否则?
		if(temp > heap->Element[child]) {
			heap->Element[parent] = heap->Element[child];
		}
		else break;
	}
	heap->Element[child] = temp;
	return item;
} 




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值