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日, (由於疫情的原因)現在沒有返校. 寫博客,也可自己加強記憶,就當寫寫日記吧!!!

希望給個贊: 反正你又不虧, 順便而已

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