C/C++_排序算法_堆排序

堆排序

堆排序(Heapsort)是利用堆这种数据结构所设计的一种排序算法, 它是选择排序的一种. 可以利用数组的特点快速定位索引的元素.

(选择排序工作原理 - 第一次从待排序的数据元素中选出最小(或最大)的一个元素, 存放在序列的起始位置, 然后再从剩余的未排序元素中寻求到最小(大)元素, 然后放到已排序的尾部. 以此类推, 直到全部待排序的数据元素的个数为零)

其排序核心实现如下:
第一步:
在这里插入图片描述
第二步:
先变为最大堆先, 再执行第一步.
在这里插入图片描述
重复上面的两个步骤

参考:

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

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

bool initHeap(Heap& heap, int* orginal, int size);
void buildHeap(Heap& heap);
void adjustDown(Heap& heap, int index);
void heapSort(Heap& heap);
bool popMax(Heap& heap, int& value);


/* 初始化堆 */
bool initHeap(Heap& heap, int* orginal, int size)
{
	heap.arr = orginal;
	if (!heap.arr) return false;

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

	/* 如果存在原始数据则构建堆 */
	if (size > 0)
	{
		/* 方式一: 直接调整所有元素(建堆) */
		buildHeap(heap);
	}
	return true;
}


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

/* 将当前的节点和子节点调整成最大堆 */
void adjustDown(Heap& heap, int index)
{
	int cur = heap.arr[index]; /* 当前待调整的节点 */
	int parent, 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 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); /* 向下执行堆调整 */
	}
}

/* 删除最大的节点, 并获得节点的值 */
bool popMax(Heap& heap, int& value)
{
	if (heap.size < 1) return false;

	value = heap.arr[0];
	heap.arr[0] = heap.arr[--heap.size];

	adjustDown(heap, 0); /* 向下执行堆调整 */
	return true;
}

int main()
{
	Heap hp;
	int origVals[] = { 1,2,3,87,93,82,92,86,95 };
	int i = 0;

	if (!initHeap(hp, origVals, sizeof(origVals) / sizeof(origVals[0])))
	{
		fprintf(stderr, "初始化堆失败!\n");
		exit(-1);
	}

	for (i = 0; i < hp.size; i++)
	{
		printf("the %dth elemennt: %d\n", i, hp.arr[i]);
	}

	/* 执行堆排序 */
	heapSort(hp);

	printf("执行堆排序后的结果: \n");
	for (i = 0; i < sizeof(origVals) / sizeof(origVals[0]); i++)
	{
		printf(" %d", origVals[i]);
	}

	system("pause");
	return 0;
}

运行环境: vs 2019
运行结果:
在这里插入图片描述

结语:

学到的知识要, 多复习, 多总结, 多敲. 需要时间的积累, 才能引起质的改变. 自己写不出来的永远是别人的.

分享一下我的技巧: 代数法把具体的数字带进去, 看看能能能找到规律(掌握思想).
还有就是画图, 也很重要. 用笔画出来, 把数代进去, 方法虽然笨, 但真的很实用, 好记忆不如烂笔头!!! 还有多用debug(调试工具)

我是小白, C/C++功力…, 你懂得, 写的文章可能不是很好. 如果存在问题, 欢迎大神给予评判指正.
错了不可怕, 可怕的是找不出bug, 谁没错过!!!

最近学操作系统我认为, 学什么都要成本(时间), 即使它是免费的, 我个人认为要挑来学, 挑重点来学, 而不是从头到尾, 除非考试考研.

这个知识点我没有完全掌握, 就是会了也要复习, 革命尚未成功, 同志还需努力!!! , 我会回来反复复习的

今日是: 2020年5月18日, (由于疫情的原因)现在没有返校. 写博客,也可自己加强记忆,就当写写日记吧!!!

希望给个赞: 反正你又不亏, 顺便而已

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章