通俗點聊聊算法 - 二叉堆與堆排序

何爲二叉堆?

二叉堆嘛,就是特化的二叉樹而已。

二叉堆又分爲最大堆和最小堆。


何爲最大堆

最大堆嘛,任意父節點大等於任何一個子節點的堆。


何爲最小堆

最小堆嘛,參考最大堆。


惡補基礎文章推薦

好,閒話不多說,如果對二叉樹還不瞭解的話,建議先了解一下
以下內容引起極度舒適,建議先把基礎打好。

擁抱STL - 樹的導覽

二叉樹的前中後序遍歷


二叉堆的插入

下面皆以最大堆說事兒

插入完全二叉樹的最後一個位置,然後不斷和父節點比較,不斷上浮,指導小於父節點爲止。


二叉堆的刪除

刪除是刪除堆頂,別問爲什麼,就是刪堆頂。

刪完之後,爲了完全二叉樹的完整性,將最後一個元素放到堆頂,然後不斷比較下沉。(往大的那邊沉)


構建二叉堆

本質就是將一棵無序的二叉樹通過浮沉構建一棵有序的堆樹。

還是說最大堆,從最後一個非葉子節點開始,依次下沉。

再說一下最小堆,從最後一個非葉子節點開始,依次上浮。


堆排序代碼

#include<stdio.h>

void swap(int a[],int i,int j)
{
	int temp;
	temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}
//調整頂堆 使之變成大頂堆或小頂堆
//n是堆中個數 i是根節點
void heapify(int tree[], int n,int i)
{
	if(i>=n)
	{
		return;
	}
	int c1 = 2 * i + 1;//左節點
	int c2 = 2 * i + 2;//右節點
	int max = i;

	if ((c1<n) && (tree[c1] > tree[max]))
	{
		max = c1;
	}
	if ((c2<n) && (tree[c2] > tree[max]))
	{
		max = c2;
	}

	//如果最大值不是在根節點
	if (max != i)
	{
		swap(tree, max, i);
		heapify(tree, n, max);
	}
}

//建造堆
void build_heap(int tree[], int n)
{
	//找到堆中最後一個根結點
	int  last_node = n - 1;
	int parent = (last_node - 1) / 2;
	int i;
	//將這個堆每個根結點進行堆排,則可實現變成一個堆
	for (i = parent; i >= 0; i--)
	{
		heapify(tree, n, i);
	}
}

//堆排序分類
void heap_sort(int tree[], int n)
{
	build_heap(tree, n);
	int i;
	//i是最後一個結點
	for (i = n - 1; i >= 0; i--)
	{
		//將最後一個結點和第一個結點進行交換
		swap(tree, i, 0);
		heapify(tree, i, 0);
	}
}

int main05()
{
	int tree[] = {2,5,3,1,10,4};
	int n = 6;

	printf_s("堆排序後\n");
	//heapify(tree, n, 0);
	//build_heap(tree, n);
	heap_sort(tree,n);
	for (int i = 0; i < n; i++) {
		printf("%d\n", tree[i]);
	}
	return 0;
}



時空複雜度

空:O(1)
時:O(logn)
平均時間複雜度O(nlogn)


堆排序VS快速排序

要是對快速排序不熟,別怕,我也有:通俗點聊聊算法 - 快速排序(親測)

堆排序和快速排序的平均時間複雜度都是 O(nlogn),且都是不穩定排序。
不過,堆排序的最壞時間複雜度穩定在O(nlogn),快速排序的最壞時間複雜度爲O(n^2)。
此外,快速排序的空間複雜度更高,爲O(nlogn)。


爲什麼我更傾向於快速排序?

因爲上面的比對是基於堆建立完的情況下。如果一次排序多次取最值,我會考慮堆排序。注意,多次、最值!


是不是感覺節奏太快啦,我也覺着快了點。小場面,沒事

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