亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C語(yǔ)言深入探究冒泡排序與堆排序使用案例講解

 更新時(shí)間:2022年05月23日 09:15:54   作者:Mi ronin  
算法中排序是十分重要的,而每一個(gè)學(xué)習(xí)計(jì)算機(jī)的都會(huì)在初期的時(shí)候接觸到這種排序,下面這篇文章主要給大家介紹了關(guān)于c語(yǔ)言冒泡排序與堆排序使用的相關(guān)資料,需要的朋友可以參考下

一.冒泡排序

1.1冒泡排序引入

對(duì)于任何編程語(yǔ)言,當(dāng)我們學(xué)到循環(huán)和數(shù)組的時(shí)候,都會(huì)介紹一種排序算法:冒泡排序;深入學(xué)習(xí)更多排序算法后和在實(shí)際使用情況中,冒泡排序的使用還是極少的。它適合數(shù)據(jù)規(guī)模很小的時(shí)候,而且它的效率也比較低,但是作為入門的排序算法,還是值得學(xué)習(xí)的。

1.2冒泡排序的核心思想與算法分析

核心思想:相鄰的元素兩兩比較,較大的數(shù)下沉,較小的數(shù)冒起來,這樣一趟比較下來,最大(小)值就會(huì)排列在一端。

因?yàn)檩^大的數(shù)會(huì)下沉,所以我們也可以將冒泡排序稱作沉石排序。

算法分析:

  • 比較相鄰的元素。如果第一個(gè)比第二個(gè)大,就交換他們兩個(gè);
  • 每趟從第一對(duì)相鄰元素開始,對(duì)每一對(duì)相鄰元素作同樣的工作,直到最后一對(duì);
  • 針對(duì)所有的元素重復(fù)以上的步驟,除了已排序過的元素(每趟排序后的最后一個(gè)元素),直到?jīng)]有任何一對(duì)數(shù)字需要比較。

1.3實(shí)例說明

以3,2,5,6,1,11為例子,排序過程:

  • 底部畫線的為已確定的數(shù)據(jù)
  • 有n個(gè)數(shù)據(jù),需要跑n-1趟即可

1.4優(yōu)化

上面的排序過程在第四趟處理完時(shí),就已經(jīng)完全有序了(肉眼觀察的),理應(yīng)直接退出循環(huán)即可,第五趟順序完全可以省略,那么我們就會(huì)有一個(gè)問題:

怎樣判斷數(shù)據(jù)完全有序?

從先到后遍歷一遍,發(fā)現(xiàn)數(shù)據(jù)兩兩比較都是前面小于后面(沒有交換操作),這個(gè)時(shí)候,就可以判定數(shù)據(jù)已經(jīng)完全有序。

1.5代碼實(shí)現(xiàn)

void BubbleSort(int* arr, int len)
{
	int count = 0;
	bool tag = true;//標(biāo)記  首先賦初值為真
	//從頭到尾遍歷一般,沒有交換操作,則可以認(rèn)定完全有序
	//反過來說:只要有一次交換操作,則不能認(rèn)定完全有序
	for (int i = 0; i < len - 1; i++)//需要多少趟
	{
		tag = true;//注意:不要忘,每一趟開始的時(shí)候,記得將tag重新置為true
		for (int j = 0; j + 1 < len - i; j++)//控制兩兩比較   j指向兩兩比較的開始位置
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				tag = false;
			}
		}
		count++;
		if (tag)//如果一趟跑完之后,發(fā)現(xiàn)tag沒有變,還是真,則代表沒有前面大于后面的情況發(fā)生,則已經(jīng)完全有序
		{
			break;
		}
	}
	printf("%d\n", count);
}

1.6性能分析

  • 時(shí)間復(fù)雜度:o(n^2);
  • 空間復(fù)雜度:o(1);
  • 穩(wěn)定性:穩(wěn)定

二.堆排序

2.1堆的基礎(chǔ)知識(shí)

2.1.1堆是什么

堆是一種數(shù)據(jù)結(jié)構(gòu),一種叫做完全二叉樹的數(shù)據(jù)結(jié)構(gòu)。

2.1.2堆的性質(zhì)

這里我們用到兩種堆,其實(shí)也算是一種。

大頂堆:每個(gè)節(jié)點(diǎn)的值都大于或者等于它的左右子節(jié)點(diǎn)的值。

小頂堆:每個(gè)節(jié)點(diǎn)的值都小于或者等于它的左右子節(jié)點(diǎn)的值。

查找數(shù)組中某個(gè)數(shù)的父結(jié)點(diǎn)和左右孩子結(jié)點(diǎn),比如已知索引為i的數(shù),那么

1.父結(jié)點(diǎn)索引:(i-1)/2(這里計(jì)算機(jī)中的除以2,省略掉小數(shù))

2.左孩子索引:2*i+1

3.右孩子索引:2*i+2

如下圖所示:

兩種堆就是如上圖所示。

如果我們把這種邏輯結(jié)構(gòu)映射到數(shù)組中,如下所示:

大頂堆:

小頂堆:

從這里我們可以得出以下性質(zhì):

對(duì)于大頂堆:arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]

對(duì)于小頂堆:arr[i] <= arr[2i + 1] && arr[i] <= arr[2i + 2]

2.2堆排序的核心思想與基本步驟

核心思想:將無(wú)序數(shù)組構(gòu)造成一個(gè)大頂堆,固定一個(gè)最大值,將剩余的數(shù)重新構(gòu)造成一個(gè)大頂堆,重復(fù)這樣的過程構(gòu)造堆。

基本步驟:

  1. 將帶排序的序列構(gòu)造成一個(gè)大頂堆,根據(jù)大頂堆的性質(zhì),當(dāng)前堆的根節(jié)點(diǎn)(堆頂)就是序列中最大的元素;
  2. 將堆頂元素和最后一個(gè)元素交換,然后將剩下的節(jié)點(diǎn)重新構(gòu)造成一個(gè)大頂堆;
  3. 重復(fù)步驟2,如此反復(fù),從第一次構(gòu)建大頂堆開始,每一次構(gòu)建,我們都能獲得一個(gè)序列的最大值,然后把它放到大頂堆的尾部;
  4. 最后,就得到一個(gè)有序的序列了。

2.3實(shí)例說明與分析

以4,5,8,2,3,9,7,1為例,按照上面的基本步驟進(jìn)行排序,過程如下:

1.將無(wú)序序列構(gòu)造為一個(gè)大頂堆

2.現(xiàn)在我們需要找到最后一個(gè)非葉子節(jié)點(diǎn)的位置,也就是索引值。

對(duì)于一個(gè)完全二叉樹,在填滿的情況下,每一層的元素個(gè)數(shù)是上一層的二倍,根節(jié)點(diǎn)數(shù)量是1,所以最后一層的節(jié)點(diǎn)數(shù)量,一定是之前所有層節(jié)點(diǎn)總數(shù)+1,所以,我們能找到最后一層的第一個(gè)節(jié)點(diǎn)的索引,即節(jié)點(diǎn)總數(shù)/2(根節(jié)點(diǎn)索引為0),這也就是第一個(gè)葉子節(jié)點(diǎn),所以第一個(gè)非葉子節(jié)點(diǎn)的索引就是第一個(gè)葉子結(jié)點(diǎn)的索引-1。

那么對(duì)于填不滿的二叉樹呢?這個(gè)計(jì)算方式仍然適用,當(dāng)我們從上往下,從左往右填充二叉樹的過程中,第一個(gè)葉子節(jié)點(diǎn),一定是序列長(zhǎng)度/2,所以第一個(gè)非葉子節(jié)點(diǎn)的索引就是(數(shù)組長(zhǎng)度/ 2 -1)。

現(xiàn)在找到了最后一個(gè)非葉子節(jié)點(diǎn),即元素值為2的節(jié)點(diǎn),比較它的左右節(jié)點(diǎn)的值,是否比他大,如果大就換位置。這里因?yàn)?<2,所以,不需要任何操作,繼續(xù)比較下一個(gè),即元素值為8的節(jié)點(diǎn),它的左節(jié)點(diǎn)值為9比它本身大,所以交換。

3.因?yàn)樵?沒有子節(jié)點(diǎn),所以繼續(xù)比較下一個(gè)非葉子節(jié)點(diǎn),元素值為5的節(jié)點(diǎn),它的兩個(gè)子節(jié)點(diǎn)值都比本身小,不需要調(diào)整;然后是元素值為4的節(jié)點(diǎn),也就是根節(jié)點(diǎn),因?yàn)?>4,所以需要調(diào)整位置

4.原來元素值為9的節(jié)點(diǎn)值變成4了,而且它本身有兩個(gè)子節(jié)點(diǎn),所以,這時(shí)需要再次調(diào)整該節(jié)點(diǎn)

5.排序序列,將堆頂?shù)脑刂岛臀膊康脑亟粨Q

6.將剩余的元素重新構(gòu)建大頂堆,其實(shí)就是調(diào)整根節(jié)點(diǎn)以及其調(diào)整后影響的子節(jié)點(diǎn),因?yàn)槠渌?jié)點(diǎn)之前已經(jīng)滿足大頂堆性質(zhì)

7.繼續(xù)交換,堆頂節(jié)點(diǎn)元素值為8與當(dāng)前尾部節(jié)點(diǎn)元素值為1的進(jìn)行交換

8.重新構(gòu)建大頂堆

9.重復(fù)交換

10.重新構(gòu)建大頂堆

11.重復(fù)交換

12.重新構(gòu)建大頂堆

13.重復(fù)交換

14.重新構(gòu)建大頂堆

15.重復(fù)交換

16.重新構(gòu)建大頂堆

17.重復(fù)交換

18.重新構(gòu)建大頂堆

19.繼續(xù)交換

這里我么就交換結(jié)束了 得到了最后的結(jié)果。

2.4代碼實(shí)現(xiàn)

void HeapAdjust(int arr[], int start, int end)
{
	//assert
	int tmp = arr[start];
	for (int i = start * 2 + 1; i <= end; i = start * 2 + 1)//start*2+1 相當(dāng)于是start這個(gè)節(jié)點(diǎn)的左孩子
	{                     //i<end  退出for循環(huán)  觸發(fā)的是情況1
		if (i<end && arr[i + 1] > arr[i])//i<end 代表存在右孩子,且右孩子的值還大于左孩子
		{
			i++;//則此時(shí),讓i指向右孩子
		}
		//此時(shí)i肯定已經(jīng)指向較大的那個(gè)孩子
		if (arr[i] > tmp)//子大于父
		{
			arr[start] = arr[i];
			start = i;
		}
		else
		{
			break;//退出for循環(huán),觸發(fā)情況2
		}
	}
	arr[start] = tmp;
}
void HeapSort(int* arr, int len)
{
	//1.整體從最后一個(gè)非葉子節(jié)點(diǎn)開始由內(nèi)到外調(diào)整一次
	//首先需要知道最后一個(gè)非葉子節(jié)點(diǎn)的下標(biāo)
	for (int i = (len - 1 - 1) / 2; i >= 0; i--)//因?yàn)樽詈笠粋€(gè)非葉子節(jié)點(diǎn)肯定是 最后一個(gè)葉子節(jié)點(diǎn)的父節(jié)點(diǎn)
	{
		HeapAdjust(arr, i, len - 1);//調(diào)用我們一次調(diào)整函數(shù)  //這里第三個(gè)值比較特殊,沒有規(guī)律可言,則直接給最大值len-1
	}
	//此時(shí),已經(jīng)調(diào)整為大頂堆了
	//接下來,根節(jié)點(diǎn)的值和當(dāng)前最后一個(gè)節(jié)點(diǎn)的值進(jìn)行交換,然后將尾結(jié)點(diǎn)剔除掉
	for (int i = 0; i < len - 1; i++)
	{
		int tmp = arr[0];
		arr[0] = arr[len - 1 - i];//len-1-i 是我們當(dāng)前的尾結(jié)點(diǎn)下標(biāo)
		arr[len - 1 - i] = tmp;
		HeapAdjust(arr, 0, (len - 1 - i) - 1);//len-1-i 是我們當(dāng)前的尾結(jié)點(diǎn)下標(biāo),然后再給其-1則相當(dāng)于將其剔除出我們的循環(huán)
	}
}

2.5性能分析

  1. 時(shí)間復(fù)雜度:最好和最壞的情況時(shí)間復(fù)雜度都是(n*logn) 。
  2. 空間復(fù)雜度:O(1)。
  3. 穩(wěn)定性:不穩(wěn)定。

到此這篇關(guān)于C語(yǔ)言深入探究冒泡排序與堆排序使用案例講解的文章就介紹到這了,更多相關(guān)C語(yǔ)言排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

  • c++ 巧開平方的實(shí)現(xiàn)代碼

    c++ 巧開平方的實(shí)現(xiàn)代碼

    如果沒有計(jì)算器,我們?nèi)绾吻?的平方根
    2013-05-05
  • 詳解C++中的常量

    詳解C++中的常量

    這篇文章主要介紹了C++中的常量的相關(guān)資料,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • 詳解如何用alpine鏡像做一個(gè)最小的鏡像并運(yùn)行c++程序

    詳解如何用alpine鏡像做一個(gè)最小的鏡像并運(yùn)行c++程序

    這篇文章主要介紹了詳解如何用alpine鏡像做一個(gè)最小的鏡像并運(yùn)行c++程序,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • C++11中的引用限定符示例代碼

    C++11中的引用限定符示例代碼

    C++中有左值和右值的概念,其實(shí),左值和右值的區(qū)分也同樣適用于類對(duì)象,本文中將左值的類對(duì)象稱為左值對(duì)象,將右值的類對(duì)象稱為右值對(duì)象,對(duì)C++11?引用限定符相關(guān)知識(shí)感興趣的朋友跟隨小編一起看看吧
    2023-01-01
  • opencv3機(jī)器學(xué)習(xí)之EM算法示例詳解

    opencv3機(jī)器學(xué)習(xí)之EM算法示例詳解

    這篇文章主要介紹了opencv3機(jī)器學(xué)習(xí)之EM算法的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 基于C++實(shí)現(xiàn)職工管理系統(tǒng)

    基于C++實(shí)現(xiàn)職工管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了基于C++實(shí)現(xiàn)職工管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • mac 配置Clion運(yùn)行C和C++的環(huán)境的詳細(xì)步驟

    mac 配置Clion運(yùn)行C和C++的環(huán)境的詳細(xì)步驟

    這篇文章主要介紹了mac 配置Clion運(yùn)行C和C++的環(huán)境的步驟詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • C語(yǔ)言中自動(dòng)隱式轉(zhuǎn)換與類型強(qiáng)制轉(zhuǎn)換實(shí)例分析

    C語(yǔ)言中自動(dòng)隱式轉(zhuǎn)換與類型強(qiáng)制轉(zhuǎn)換實(shí)例分析

    這篇文章主要介紹了C語(yǔ)言中自動(dòng)隱式轉(zhuǎn)換與類型強(qiáng)制轉(zhuǎn)換實(shí)例分析,需要的朋友可以參考下
    2014-07-07
  • c++下使用windows api遍歷指定文件夾及其子文件夾中的文件

    c++下使用windows api遍歷指定文件夾及其子文件夾中的文件

    這篇文章主要介紹了c++下使用windows api遍歷指定文件夾及其子文件夾中的文件實(shí)現(xiàn)代碼,一般都是通過c++自帶的函數(shù)實(shí)現(xiàn)
    2021-07-07
  • 最新評(píng)論