堆算法
特点:
1.每个节点最多可以有两个节点;
2.根节点的键值是所有堆节点键值中最大者,且每个根节点的值都比其子节点的值大;
3.除了根节点没有兄弟节点,最后一个左节点可以没有兄弟节点,其他节点必须要有兄弟节点;
计算公式:
i的子节点左节点的位置: 2i+1; i的右子节点位置: 2i+2; i的父节点位置: (i-1)/2 (都是取整数的);

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DEFAULT_CAPCITY 64
typedef int DataType;

//创建一个堆数组
typedef struct _Heap {
	DataType* arr;//存储堆元素的数组
	int size;//当前已存储的元素个数
	int capacity;//当前存储的容量
}Heap;

//初始化堆
bool initHeap(Heap& heap, DataType* orginal, int size);
//插入元素
bool insert(Heap& heap, DataType val);
//删除元素
bool popMax(Heap& heap, DataType&val);
//建立一个堆
static void buildHeap(Heap& heap);
//调整父节点的下一个位置元素
static void adjustDown(Heap& heap, int index);
//调整父节点的上一个位置元素
static void adjustUp(Heap& heap, int index);

bool initHeap(Heap& heap, DataType* orginal, int size) {
	int capacity = DEFAULT_CAPCITY > size ? DEFAULT_CAPCITY : size;

	heap.arr = new DataType[capacity];
	if (!heap.arr) {
		return false;
	}

	heap.capacity = capacity;
	heap.size = 0;

	//如果存在原始数据则构建堆
	if (size > 0) {
		方式1: 直接调整所有元素
		//memcpy(heap.arr, orginal, size * sizeof(int));
		//heap.size = size;
		建堆
		//buildHeap(heap);

		//方式2: 一次插入一个
		for (int i = 0; i < size; i++) {
			insert(heap, orginal[i]);
		}
	}
	return true;
}
bool popMax(Heap& heap, DataType&val){
	if (heap.size == NULL) {
		return false;
	}
	//获取堆中最大的元素,然后把堆中最后的一个元素放到最大元素的位置
	//再进行堆排列
	val=heap.arr[0];
	heap.arr[0] = heap.arr[--heap.size];
	adjustDown(heap, 0);

	return true;
}
//从最后一个父节点(size/2-1的位置)逐个往前调整所有父节点(直到根节点)
//确保每一个父节点都是一个最大堆,最后整体上形成一个最大堆
void buildHeap(Heap& heap) {
	for (int i = heap.size / 2 - 1; i >= 0; i--) {
		adjustDown(heap, i);
	}
}

//将当前的节点和子节点调整成最大堆
void adjustDown(Heap& heap, int index) {
	int cur = heap.arr[index];//当前待调整的节点
	int parent;
	int child;
	//判断是否存在大于当前节点子节点,如果不存在,则堆本身是平衡的,不需要调整;
	//如果存在,则将最大的子节点与之交换,交换后,如果这个子节点还有子节点
	//则要继续按照同样的步骤堆这个子节点进行调整
	for (parent = index; (parent * 2 + 1) < heap.size; parent = child) {
		child = parent * 2 + 1;
		//取两个子节点中的最大的节点
		if (((child + 1) < heap.size) && (heap.arr[child] < heap.arr[child + 1])) {
			child++;
		}
		//判断最大的节点是否大于当前的父节点
		if (cur >= heap.arr[child]) {
			//不大于,则不需要整理,跳出循环
			break;
		}
		else {
			//大于当前的父节点,进行交换,然后从子节点位置继续下调整
			heap.arr[parent] = heap.arr[child];
			heap.arr[child] = cur;
		}
	}
}

//将当前的节点和父节点调整成最大堆
void adjustUp(Heap& heap, int index) {
	if (index < 0 || index >= heap.size) {
		return;
	}
	while (index > 0) {
		int temp = heap.arr[index];
		int parent = (index - 1) / 2;

		if (parent >= 0) {
			//如果索引没有出界就执行相要的操作
			if (temp > heap.arr[parent]) {
				heap.arr[index] = heap.arr[parent];
				heap.arr[parent] = temp;
				index = parent;
			}
			else {
				//如果已经比父节点小,直接结束循环
				break;
			}
		}
		else {
			//越界结束循环
			break;
		}
	}
}

//最大堆尾部插入节点,同时保证最大堆的特性
bool insert(Heap& heasp, int val) {
	if (heasp.size == heasp.capacity) {
		fprintf(stderr, "栈空间耗尽!\n");
		return false;
	}

	int index = heasp.size;
	heasp.arr[heasp.size++] = val;
	adjustUp(heasp, index);
	return true;
}

堆的企业级应用案例
优先队列:
如果最小键值元素拥有最高的优先级,那么这种优先队列叫作升序优先队列(即总是先删除最小 的元素),类似的,如果最大键值元素拥有最高的优先级,那么这种优先队列叫作降序优先队列 (即总是先删除最大的元素);由于这两种类型是完全对称的,所以只需要关注其中一种,如升 序优先队列
堆排序:
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特 点快速定位指定索引的元素. (选择排序工作原理 - 第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置, 然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待 排序的数据元素的个数为零)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

using namespace std;

#define DEFAULT_CAPCITY 64
typedef int DataType;
#define Less(a,b) (a<b)

//创建一个堆数组
typedef struct _Heap {
	DataType* arr;//存储堆元素的数组
	int size;//当前已存储的元素个数
	int capacity;//当前存储的容量
}Heap;

//初始化堆
bool initHeap(Heap& heap, DataType* orginal, int size);
//删除元素
bool popMax(Heap& heap, DataType&val);
//建立一个堆
static void buildHeap(Heap& heap);
//调整父节点的下一个位置元素
static void adjustDown(Heap& heap, int index);

bool initHeap(Heap& heap, DataType* orginal, int size) {
	/*int capacity = DEFAULT_CAPCITY > size ? DEFAULT_CAPCITY : size;

	heap.arr = new DataType[capacity];*/
	heap.arr = orginal;
	if (!heap.arr) {
		return false;
	}

	heap.capacity = size;
	heap.size = size;

	//如果存在原始数据则构建堆
	if (size > 0) {
		//方式1: 直接调整所有元素
		/*memcpy(heap.arr, orginal, size * sizeof(int));
		heap.size = size;*/
		//建堆
		buildHeap(heap);

		//方式2: 一次插入一个
		/*for (int i = 0; i < size; i++) {
			insert(heap, orginal[i]);
		}*/
	}
	return true;
}
bool popMax(Heap& heap, DataType&val){
	if (heap.size == NULL) {
		return false;
	}
	//获取堆中最大的元素,然后把堆中最后的一个元素放到最大元素的位置
	//再进行堆排列
	val=heap.arr[0];
	heap.arr[0] = heap.arr[--heap.size];
	adjustDown(heap, 0);

	return true;
}
//从最后一个父节点(size/2-1的位置)逐个往前调整所有父节点(直到根节点)
//确保每一个父节点都是一个最大堆,最后整体上形成一个最大堆
void buildHeap(Heap& heap) {
	for (int i = heap.size / 2 - 1; i >= 0; i--) {
		adjustDown(heap, i);
	}
}

//将当前的节点和子节点调整成最大堆
void adjustDown(Heap& heap, int index) {
	int cur = heap.arr[index];//当前待调整的节点
	int parent;
	int child;
	//判断是否存在大于当前节点子节点,如果不存在,则堆本身是平衡的,不需要调整;
	//如果存在,则将最大的子节点与之交换,交换后,如果这个子节点还有子节点
	//则要继续按照同样的步骤堆这个子节点进行调整
	for (parent = index; Less((parent * 2 + 1), heap.size); parent = child) {
		child = parent * 2 + 1;
		//取两个子节点中的最大的节点
		if ((Less((child + 1),heap.size) && Less(heap.arr[child], heap.arr[child + 1]))) {
			child++;
		}
		//判断最大的节点是否大于当前的父节点
		if (Less(heap.arr[child],cur)) {
			//不大于,则不需要整理,跳出循环
			break;
		}
		else {
			//大于当前的父节点,进行交换,然后从子节点位置继续下调整
			heap.arr[parent] = heap.arr[child];
			heap.arr[child] = cur;
		}
	}
}

//实现堆排序
void heapsort(Heap& heap) {
	if (heap.size < 1) {
		return;
	}
	while (heap.size > 0) {
		int tmp = heap.arr[0];
		heap.arr[0] = heap.arr[heap.size - 1];
		heap.arr[heap.size-1] = tmp;
		heap.size--;

		adjustDown(heap, 0);
	}
}

int main(void) {

	Heap hp;
	int origvals[] = { 2,3,6,9,11,80,45 };

	if (!initHeap(hp, origvals, sizeof(origvals) / sizeof(origvals[0]))) {
		fprintf_s(stderr, "初始化堆失败!\n");
		exit(-1);
	}
	for (int i = 0; i < hp.size; i++) {
		cout << i << "个元素:" << hp.arr[i] << endl;
	}
	heapsort(hp);

	for (int i = 0; i < sizeof(origvals)/sizeof(origvals[0]); i++) {
		cout <<"元素:" << origvals[i] << endl;
	}

	cout << "最大的3个元素:";
	for (int i = sizeof(origvals) / sizeof(origvals[0])-1; i > (sizeof(origvals) / sizeof(origvals[0]))-4; i--) {
		cout << origvals[i]<<",";
	}
	cout << endl;
	cout << "最小的3个元素:";
	for (int i = 0; i < 3; i++) {
		cout << origvals[i] << ",";
	}
	cout << endl;
	
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值