国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

十大經典排序算法----堆排序(超詳細)

這篇具有很好參考價值的文章主要介紹了十大經典排序算法----堆排序(超詳細)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

1.?堆排序的基礎知識

1.1?大頂堆&&小頂堆?

1.2?向下調整算法

1.3?物理結構與邏輯結構的關系

2.?堆排序詳解

2.1?堆排序整體思路?

2.2?思路詳解

2.2.1?建堆

2.2.2?大堆or小堆

2.2.3?輸出數(shù)據(jù)

3.?時間復雜度分析

4.?完整代碼

?5.?彩蛋


1.?堆排序的基礎知識

堆排序(Heap?Sort)就是對直接選擇排序的一種改進。此話怎講呢?直接選擇排序在待排序的n個數(shù)中進行n-1次比較選出最大或者最小的,但是在選出最大或者最小的數(shù)后,并沒有對原來的序列進行改變,這使得下一次選數(shù)時還需要對全部數(shù)據(jù)進行比較,效率大大降低。

堆排序算法是Floyd和Williams在1964年共同發(fā)明的,同時他們發(fā)明了“堆”這種數(shù)據(jù)結構。

1.1?大頂堆&&小頂堆?

對于待排序的數(shù)組元素,我們可以將它的邏輯結構看成二叉樹。滿足某種條件的這種邏輯結構就是堆啦。

堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++

顯然,這是一棵完全二叉樹。那么某種條件是啥呢?

堆是具有下列性質的完全二叉樹:每個節(jié)點的值都大于或等于其左右孩子節(jié)點的值,稱為:大頂堆(大堆);或者每個節(jié)點的值都小于或等于其左右孩子節(jié)點的值,稱為小頂堆(小堆)。?

堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++?

1.2?向下調整算法

使用該算法的前提是該節(jié)點的左右子樹要么都是大堆,要么都是小堆。

該算法就是將該節(jié)點與左右子樹的節(jié)點進行比較,重新構建成一個大堆或者小堆。

堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++

1.3?物理結構與邏輯結構的關系

假設我們有了一個待排序的數(shù)組,并且構建好了他的邏輯結構,怎么能通過孩子找到雙親,或者通過雙親找到左右孩子呢?

先看公式:?parent = (child - 1) / 2 ;

? ? ? ? ? ? ? ? ? ?leftchild = parent * 2 + 1 ;

? ? ? ? ? ? ? ? ? ?rightchild = parent * 2 + 2 ;

? ? ? ? ? ? ? ? ? ?rightchild = leftchild + 1;

有了這個公式,左孩子,右孩子,雙親的下標知道一個就可以求其他兩個啦!

堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++

?文章來源地址http://www.zghlxwxcb.cn/news/detail-777647.html

2.?堆排序詳解

是的,堆排序就是通過建堆的方式來彌補直接選擇排序的缺陷滴。?

2.1?堆排序整體思路?

1):給出待排序的數(shù)組,咱們腦補一個邏輯結構,然后將該邏輯結構整體調整為大堆或者小堆。?

2):?留個問題:升序是構建大堆還是小堆呢?提示:請參考直接選擇排序的缺陷,以及堆排序如何彌補該缺陷的。搞清楚這個問題后排序即可。

3):打印輸出數(shù)據(jù)。

2.2?思路詳解

2.2.1?建堆

大堆為例哈:既然前面都鋪墊了向下調整算法,你們肯定猜到了是通過該算法來建堆啦。

注意該算法的使用前提:要求左右子樹都是大堆。怎么辦呢?聰明如你們,我們從邏輯結構的后面往前面用該算法不就行啦??!

堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++?

/// <summary>
/// 交換數(shù)組元素
/// </summary>
/// <param name="pa">被交換的元素a</param>
/// <param name="pb">被交換的元素b</param>
void Swap(int* pa, int* pb)
{
	int tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}


/// <summary>
/// 對邏輯結構進行向下調整,構建大堆
/// </summary>
/// <param name="arr">數(shù)組首元素地址</param>
/// <param name="n">數(shù)組大小</param>
/// <param name="root">要調整的節(jié)點</param>
void AdjustDown(int* arr, int n, int root)
{
	//雙親的下標
	int parent = root;
	//較大孩子的下標,默認為左孩子
	int child = parent * 2 + 1;
	//如果孩子的下標不越界,進入循環(huán)
	while (child < n)
	{
		//如果右孩子存在(下標沒越界),并且右孩子大于左孩子,更新child
		if (child + 1 < n && arr[child + 1] > arr[child])
		{
			child = child + 1;
		}
		//如果較大的孩子大于雙親,交換
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			//改變parent的下標如果滿足條件繼續(xù)向下調整
			parent = child;
			child = parent * 2 + 1;
		}
		//如果較大的孩子不大于雙親,root節(jié)點的大堆構建完畢
		else
		{
			break;
		}
	}
}

/// <summary>
/// 堆排序函數(shù)
/// </summary>
/// <param name="arr">數(shù)組首元素地址</param>
/// <param name="n">數(shù)組大小</param>
void HeapSort(int* arr, int n)
{
	//循環(huán)從后面往前面對需要的數(shù)組元素使用向下調整算法
	int i = 0;
	for (i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, n, i);
	}
}

2.2.2?大堆or小堆

以升序為例:建大堆完成后就是這個樣子啦:9, 8, 6, 7, 3, 1, 2, 4, 5, 0 ;

? ? ? ? ? ? ? ? ? ? ? 建小堆完成后就是這個樣子:0, 3, 1, 5, 4, 2, 9, 7, 8, 6 ;

建小堆只需要將AdjustDown里面的兩個if語句的大于改成小于。

堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++

2.2.3?輸出數(shù)據(jù)

這部分比較簡單,不多分析。?

3.?時間復雜度分析

堆排序的時間復雜度分析,應該是排序算法中最復雜的,需要具備高中的基礎知識!?。?!

堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++

堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++?

堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++?

4.?完整代碼

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>

/// <summary>
/// 交換數(shù)組元素
/// </summary>
/// <param name="pa">被交換的元素a</param>
/// <param name="pb">被交換的元素b</param>
void Swap(int* pa, int* pb)
{
	int tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}


/// <summary>
/// 對邏輯結構進行向下調整,構建大堆
/// </summary>
/// <param name="arr">數(shù)組首元素地址</param>
/// <param name="n">數(shù)組大小</param>
/// <param name="root">要調整的節(jié)點</param>
void AdjustDown(int* arr, int n, int root)
{
	//雙親的下標
	int parent = root;
	//較大孩子的下標,默認為左孩子
	int child = parent * 2 + 1;
	//如果孩子的下標不越界,進入循環(huán)
	while (child < n)
	{
		//如果右孩子存在(下標沒越界),并且右孩子大于左孩子,更新child
		if (child + 1 < n && arr[child + 1] > arr[child])
		{
			child = child + 1;
		}
		//如果較大的孩子大于雙親,交換
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			//改變parent的下標如果滿足條件繼續(xù)向下調整
			parent = child;
			child = parent * 2 + 1;
		}
		//如果較大的孩子不大于雙親,root節(jié)點的大堆構建完畢
		else
		{
			break;
		}
	}
}
/// <summary>
/// 打印數(shù)組元素
/// </summary>
/// <param name="arr">數(shù)組首元素地址</param>
/// <param name="n">數(shù)組元素個數(shù)</param>
void PrintArray(int* arr, int n)
{
	int i = 0;
	for (i = 0; i < n; i++)
	{
		printf("%d ", arr[i]);
	}
}

/// <summary>
/// 堆排序函數(shù)
/// </summary>
/// <param name="arr">數(shù)組首元素地址</param>
/// <param name="n">數(shù)組大小</param>
void HeapSort(int* arr, int n)
{
	//循環(huán)從后面往前面對需要的數(shù)組元素使用向下調整算法
	int i = 0;
	for (i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, n, i);
	}
	//用來控制向下調整時的數(shù)組元素個數(shù)
	int end = n - 1;
	while (end > 0)
	{
		//交換元素,獲得最大值
		Swap(&arr[0], &arr[end]);
		//進行向下調整, 因為開始end為n-1嘛
		AdjustDown(arr, end, 0);
		//去除較大值
		--end;
	}
}





int main()
{
	//待排序的數(shù)組
	int arr[] = { 6,4,2,8,3,1,9,7,5,0 };
	//調用主體函數(shù)
	HeapSort(arr, sizeof(arr) / sizeof(arr[0]));
	//打印數(shù)據(jù)
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));

	return 0;
}

?5.?彩蛋

為了直觀的比較幾大排序算法的快慢,我們可以設計程序以毫秒數(shù)來量化排序的快慢。

堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++?堆排序,十大經典排序算法,排序算法,數(shù)據(jù)結構,算法,c++

?

到了這里,關于十大經典排序算法----堆排序(超詳細)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包