最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言五大經(jīng)典排序算法插入、希爾、冒泡、選擇、堆排序完全攻略

 更新時(shí)間:2026年03月08日 10:12:50   作者:藍(lán)羊羊不藍(lán)  
這篇文章主要介紹了C語言五大經(jīng)典排序算法插入、希爾、冒泡、選擇、堆排序的相關(guān)資料,分別詳細(xì)闡述了它們的排序思想、示例代碼、時(shí)間復(fù)雜度、空間復(fù)雜度和穩(wěn)定性,需要的朋友可以參考下

--------------插入排序-------------

1、插入排序思想

插入排序的核心思想是逐步構(gòu)建有序序列

將數(shù)組分為 “已排序” 和 “未排序” 兩部分,初始時(shí)已排序部分只包含第一個元素。

每次從未排序部分取出第一個元素,將其向前插入到已排序序列中的正確位置,使得插入后的序列依然保持有序。

重復(fù)這個過程,直到所有元素都被 插入到已排序序列中。

這個過程就像整理撲克牌:你會把每一張新摸到的牌,插入到手中已排好序的牌堆里,最終讓整副牌都有序。

2、示例代碼

// 插入排序(此處為降序,升序?qū)?a[end] < tmp 改為 a[end] > tmp)
void InsertSort(int* a, int n)
{
    // 遍歷未排序元素(從第2個元素開始)
    for (int i = 1; i < n; i++)
    {
        int end = i - 1;  // 已排序部分末尾下標(biāo)
        int tmp = a[i];   // 保存當(dāng)前待插入元素

        // 向前查找合適位置,大于tmp(降序)則后移
        while (end >= 0)
        {
            if (a[end] < tmp)
            {
                a[end + 1] = a[end];  // 元素后移騰位置
                end--;
            }
            else
            {
                break;  // 找到位置,退出循環(huán)
            }
        }
        a[end + 1] = tmp;  // 插入到正確位置
    }
}

3、效率分析

時(shí)間復(fù)雜度:最壞情況下,插入第 1 個待排序元素時(shí)最多比較 1 次,第 2 個元素最多比較 2 次…… 第 n-1 個元素最多比較 n-1 次,總比較次數(shù)為等差數(shù)列求和,因此時(shí)間復(fù)雜度為O(N^2);但在數(shù)組已有序的情況下,每個元素僅需比較 1 次,時(shí)間復(fù)雜度可優(yōu)化至O(N)。

空間復(fù)雜度:僅定義了常數(shù)級的輔助變量,未額外開辟大規(guī)模空間,因此空間復(fù)雜度為O(1)。

穩(wěn)定性排序是穩(wěn)定的。因?yàn)樵厥侵饌€向前插入的,當(dāng)遇到相等元素時(shí)不會移動,因此相等元素的相對位置在排序前后保持不變。

--------------希爾排序-------------

1、希爾排序思想

希爾排序的核心思想是分組插入排序,逐步縮小增量

將整個待排序數(shù)組按照某個 增量(步長)分割成若干個子序列,每個子序列的元素在原數(shù)組中是等間隔的。對每個子序列分別進(jìn)行插入排序,通過這種分組排序,讓數(shù)組整體變得 “基本有序”。

然后,逐步縮小增量(通常取上一次的一半),重復(fù)上述分組和插入排序的操作。當(dāng)增量縮小到 1 時(shí),整個數(shù)組就變成了一個子序列,此時(shí)再進(jìn)行一次插入排序,數(shù)組就完全有序了。

這個過程就像先把亂序的撲克牌按花色分組整理,再按點(diǎn)數(shù)細(xì)分整理,最后整體微調(diào)

大增量時(shí),元素移動的跨度大,能快速把亂序的數(shù)組變得 “大致有序”。

小增量時(shí),數(shù)組已經(jīng)基本有序,插入排序的效率會非常高。

2、示例代碼

void ShellSort(int* a, int n)
{
	 //gap > 1 預(yù)排序
	 //gap == 1 插入排序
	 int gap = n;
	 while (gap > 1)
	 {
		gap = gap / 3 + 1;

        /*----------------多組并排----------------*/
		//for (int i = 0; i < n - gap; i++)
		//{
		//	int end = i;
	    //  int tmp = a[i + gap];

		//	while (end >= 0)
		//	{
		//		if (tmp < a[end])
		//		{
		//			a[end + gap] = a[end];
		//			end -= gap;
		//		}
		//		else
		//		{
		//			break;
		//		}
		//	}

		//	a[end + gap] = tmp;
		//}

       
		/*-------------一組排完排另一組-------------*/
		for (int j = 0; j < gap; j++)
		{
			for (int i = 0; i < n - gap; i += gap)
			{
				int end = i;
				int tmp = a[i + gap];
				while (end >= 0)
				{
					if (tmp > a[end])
					{
						a[end + gap] = a[end];
						end -= gap;
					}
					else
					{
						break;
					}
				}

				a[end + gap] = tmp;

			}

		}
	 }


}

3、效率分析

時(shí)間復(fù)雜度:

1、外層:外層循環(huán)控制增量gap(公式不同如gap/2、gap/3+1會影響效率)從n逐步縮小至 1,迭代次數(shù)為對數(shù)級別,時(shí)間復(fù)雜度為 O(logN)

2、內(nèi)層:剛開始gap很大,for循環(huán)大致在N這個量級(具體看圖),while循環(huán)插入判斷跳的很快,是常量級別的,所以最開始是時(shí)間復(fù)雜度為O(N),最后gap很小,按理來說應(yīng)該是N^2,但是由于數(shù)組已經(jīng)無限接近有序,所以按最好的情況算O(N)

因此我們可以大概計(jì)算出來應(yīng)該在N*logN這個量級

這是關(guān)于希爾排序時(shí)間復(fù)雜度不同教材的分析:

空間復(fù)雜度:僅定義了常量級的輔助變量,所以為O(1)

穩(wěn)定性:由于是跳躍調(diào)整,相同值的元素可能在分組插入排序的過程中,被交換到彼此的原始相對位置之前,破壞了穩(wěn)定性,所以希爾排序是不穩(wěn)定排序。

--------------選擇排序-------------

1、選擇排序思想

選擇排序的核心思想是逐步選擇最值,構(gòu)建有序序列

將數(shù)組分為 “已排序” 和 “未排序” 兩部分,初始時(shí)已排序部分為空。每次從未排序部分中選出最?。ɑ蜃畲螅┑脑?,將其與未排序部分的第一個元素交換位置,該元素就加入到已排序部分的末尾。

重復(fù)這個過程,直到所有元素都被納入已排序部分,整個數(shù)組就完全有序了。

這個過程就像從一堆打亂的撲克牌里,每次挑出最小的一張,放到已整理好的牌堆后面,最終完成整副牌的排序。

2、示例代碼

void SelectSort(int* a, int n)
{
	  /*
      int left = 0;
	  while (left < n)
	  {
		  int min = left;
		  for (int i = left + 1; i < n; i++)
		  {
			  if (a[min] > a[i])
			  {
				  min = i;
			  }

		  }

          swap(&a[min],&a[left]);
          left++;
		 
	  }
	  */

      int left = 0;
      int right = n - 1;
      //left == right就表示只有一個元素了,所以沒有選擇的必要了
	  while (left < right)
	  {
            //必須要初始為left,因?yàn)槭莾?nèi)層循環(huán)從left+1開始比較的
            //如果有一個初始不為left,就會跳過left這個值
			int max = left;
            int min = left;

			for (int i = left + 1; i <= right; i++)
			{
				if (a[max] < a[i])
				{
					max = i;
				}

				if (a[min] > a[i])
				{
					min = i;
				}
			}

            swap(&a[left],&a[min]);
            //修正:max有可能和left重疊
			if (left == max)
			{
				max = min;
			}
			swap(&a[right],&a[max]);
			left++;
			right--;

	  }

}

修正:

3、效率分析

時(shí)間復(fù)雜度:第一趟遍歷 n-1 遍數(shù)組,第二趟遍歷 n-2 遍數(shù)組,第 n-1 遍遍歷1遍數(shù)組,是個等差數(shù)列,所以時(shí)間復(fù)雜度為O(N^2)

空間復(fù)雜度:僅使用常量級別的變量,因此空間復(fù)雜度是O(1)

穩(wěn)定性:由于交換操作可能會破壞相同值元素的相對順序,所以選擇排序是不穩(wěn)定排序

---------------堆排序--------------

1、堆排序思想

堆排序的核心思想是利用堆的特性進(jìn)行排序

將待排序數(shù)組構(gòu)建成一個大頂堆(或小頂堆),堆頂即為當(dāng)前未排序部分的最大值(或最小值)。每次將堆頂元素與當(dāng)前未排序部分的末尾元素交換,使該最大值(或最小值)歸位到正確的排序位置。交換后,堆的結(jié)構(gòu)會被破壞,需要對剩余的未排序元素重新調(diào)整為大頂堆(或小頂堆)。重復(fù)這個過程,直到整個數(shù)組有序。

這個過程就像從一堆石頭里每次挑出最重的一塊,放到已排好的序列末尾,最終讓所有石頭按重量從大到小排好。

2、示例代碼

//向上調(diào)整算法 - 建大堆
void AdjustUp(int* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] > a[parent])
		{
			swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}


 //向下調(diào)整算法
 void AdjustDown(int* a, int n, int parent)
 {
	 int child = 2 * parent + 1;
	 while (child < n)//等于n時(shí)越界一個位置
	 {
		 if (child + 1 < n && a[child + 1] > a[child])
		 {
			 child++;
		 }

		 if (a[child] > a[parent])
		 {
			 swap(&a[child], &a[parent]);
			 parent = child;
			 child = 2 * parent + 1;
		 }
		 else
		 {
			 break;
		 }
	 }
 }


 //堆排序 
 //N*logN
 void HeapSort(int* a, int n)
 {
	 //向下調(diào)整建堆 -- N
	 for (int i = (n - 2) / 2; i >= 0; i--)
	 {
		 AdjustDown(a,n,i);
	 }
	 //向上調(diào)整建堆 -- N*logN
	 //for (int i = 1; i < n; i++)
	 //{
	 //		AdjustUp(a, i);
	 //}


	 //排序
	 int end = n - 1;
	 while (end > 0)
	 {
		 swap(&a[0], &a[end]);
		 AdjustDown(a, end, 0);
		 end--;
	 }
 }

3、效率分析

時(shí)間復(fù)雜度:

向下調(diào)整建堆的時(shí)間復(fù)雜度為O(N):向下調(diào)整建堆的時(shí)間復(fù)雜度是 O(N),而不是 O(NlogN),核心原因是調(diào)整成本被平攤了。堆的底層節(jié)點(diǎn)數(shù)量最多,占了總節(jié)點(diǎn)數(shù)的一半左右,但它們的調(diào)整深度最小;而堆的上層節(jié)點(diǎn)數(shù)量很少,調(diào)整深度才會達(dá)到 O(logN)。這種 “數(shù)量多的節(jié)點(diǎn)成本低,數(shù)量少的節(jié)點(diǎn)成本高” 的反向分布,把整體的平均調(diào)整成本從 O(logN) 拉低到了 O(1),最終時(shí)間復(fù)雜度就成了 O(N)

向上調(diào)整建堆的時(shí)間復(fù)雜度為O(NlogN),它的調(diào)整邏輯與向下調(diào)整正好相反:上層節(jié)點(diǎn)的調(diào)整深度較淺,但下層節(jié)點(diǎn)的調(diào)整深度很深,而堆的下層恰恰包含了大部分元素。因此,整體來看,大部分節(jié)點(diǎn)都需要進(jìn)行約 logN 次調(diào)整,最終時(shí)間復(fù)雜度為 O(NlogN)。

堆排序的完整過程分為建堆排序階段兩部分:

建堆階段:使用向下調(diào)整建堆,時(shí)間復(fù)雜度為 O(N)

排序階段:共需進(jìn)行 N−1 次堆頂交換與向下調(diào)整,每次調(diào)整的時(shí)間復(fù)雜度為 O(logN),因此這一階段的時(shí)間復(fù)雜度為 O(NlogN)

將兩部分時(shí)間復(fù)雜度相加,取主導(dǎo)項(xiàng),堆排序的整體時(shí)間復(fù)雜度為 O(NlogN),且該復(fù)雜度不受輸入數(shù)據(jù)分布的影響,最優(yōu)、最壞與平均時(shí)間復(fù)雜度均為 O(NlogN)。

空間復(fù)雜度:僅僅使用了常數(shù)級別的變量,所以空間復(fù)雜度為O(1)

穩(wěn)定性:堆排序是不穩(wěn)定的排序算法。因?yàn)樵诙训恼{(diào)整過程中(無論是向上還是向下調(diào)整),相同值的節(jié)點(diǎn)可能會因?yàn)榻粨Q而改變相對順序,破壞了原有的穩(wěn)定性。

--------------冒泡排序-------------

1、冒泡排序思想

冒泡排序的核心思想是通過相鄰元素的比較與交換,讓較大(較小)的元素逐步 “冒泡” 到數(shù)組的末尾。

將數(shù)組視為一個未排序的整體,從頭部開始,依次比較相鄰的兩個元素。

如果前一個元素大于(小于)后一個元素,就交換它們的位置,使較大(較?。┑脑叵蚝笠苿右晃弧?/p>

每一輪遍歷后,當(dāng)前未排序部分的最大值(最小值)會被 “推” 到末尾,成為已排序部分。

重復(fù)這個過程,直到所有元素都完成排序。

這個過程就像水里的氣泡一樣,較大(較小)的元素會慢慢浮到水面(數(shù)組末尾)。

2、示例代碼

 void BubbleSort(int* a, int n)
 {
     //多少趟
	 for (int i = 0;i < n - 1;i++)
	 {
		 //單趟
		 int flag = 0;
		 for (int j = 1; j < n - i; j++)
		 {
			 if (a[j - 1] > a[j])
			 {
				 swap(&a[j - 1], &a[j]);
				 flag = 1;
			 }
		 }

		 if (flag == 0)
		 {
			 break;
		 }
	  }
 }

3、效率分析

時(shí)間復(fù)雜度:冒泡排序共進(jìn)行 n−1 輪遍歷,總比較次數(shù)為等差數(shù)列求和 2n(n−1)?,時(shí)間復(fù)雜度為 O(N^2);若加入提前終止優(yōu)化,最優(yōu)情況可降至 O(n)。

空間復(fù)雜度:冒泡排序僅需常數(shù)級別的臨時(shí)變量用于元素交換,因此空間復(fù)雜度為 O(1)。

穩(wěn)定性:冒泡排序是穩(wěn)定的排序算法,因?yàn)樗鼉H在相鄰元素前大于后時(shí)才交換,相同值的元素不會改變相對順序。

上述五大排序性能對比:

希爾排序堆排序時(shí)間復(fù)雜度都是N*logN這個量級,是這幾個中效率最高的兩個了

((希爾排序的時(shí)間復(fù)雜度)這是一個簡化說法,嚴(yán)格來說它介于 O(NlogN) 和 O(N2) 之間,取決于增量序列的選擇,但常歸為 O(NlogN) 量級)

接下來就是插入排序冒泡排序它倆在數(shù)組有序時(shí),時(shí)間復(fù)雜度都能達(dá)到 O (N),最壞都是 O(N^2) 這個量級,但是他們在一些場景下的性能還是有差距的:

有序:一樣

接近有序:有一些差距

部分有序:差距就很大

 這是由于這兩個算法的單次操作導(dǎo)致的:

最后一個就是選擇排序,無論是否有序時(shí)間復(fù)雜度都是在O(N^2)這個量級,也是這幾個中效率最差的排序算法

穩(wěn)定性補(bǔ)充:冒泡、插入排序是穩(wěn)定的;希爾、堆、選擇排序是不穩(wěn)定的。

總結(jié)

到此這篇關(guān)于C語言五大經(jīng)典排序算法插入、希爾、冒泡、選擇、堆排序的文章就介紹到這了,更多相關(guān)C語言算法插入、希爾、冒泡、選擇、堆排序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++中std::construct()與std::destroy()的使用

    C++中std::construct()與std::destroy()的使用

    std::construct()和std::destroy()是C++ STL中的函數(shù)模板,用于在已分配的存儲區(qū)域中構(gòu)造或銷毀對象,本文主要介紹了C++中std::construct()與std::destroy()的使用,感興趣的可以了解一下
    2024-02-02
  • 深入剖析Android中init進(jìn)程實(shí)現(xiàn)的C語言源碼

    深入剖析Android中init進(jìn)程實(shí)現(xiàn)的C語言源碼

    這篇文章主要介紹了Android中init進(jìn)程實(shí)現(xiàn)的C語言源碼,init屬性服務(wù)在安卓中屬于系統(tǒng)的底層Linux服務(wù),需要的朋友可以參考下
    2015-07-07
  • VC判斷進(jìn)程是否具有administrator權(quán)限的方法

    VC判斷進(jìn)程是否具有administrator權(quán)限的方法

    這篇文章主要介紹了VC判斷進(jìn)程是否具有administrator權(quán)限的方法,在Windows應(yīng)用程序設(shè)計(jì)中具有一定的實(shí)用價(jià)值,需要的朋友可以參考下
    2014-10-10
  • 用c++實(shí)現(xiàn)x的y次冪的代碼

    用c++實(shí)現(xiàn)x的y次冪的代碼

    以下實(shí)例是對使用c++實(shí)現(xiàn)x的y次冪的解決方法進(jìn)行了介紹。需要的朋友參考下
    2013-05-05
  • C語言深度解剖篇之關(guān)鍵字以及補(bǔ)充內(nèi)容

    C語言深度解剖篇之關(guān)鍵字以及補(bǔ)充內(nèi)容

    C語言的關(guān)鍵字共有32個,根據(jù)關(guān)鍵字的作用,可分其為數(shù)據(jù)類型關(guān)鍵字、控制語句關(guān)鍵字、存儲類型關(guān)鍵字和其它關(guān)鍵字四類,這篇文章主要給大家介紹了關(guān)于C語言深度解剖篇之關(guān)鍵字以及補(bǔ)充內(nèi)容的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • C語言常見的指針筆試題解析

    C語言常見的指針筆試題解析

    在我們學(xué)習(xí)指針之后,應(yīng)該在實(shí)際應(yīng)用中去理解和掌握它,畢竟實(shí)踐才是檢驗(yàn)真理的唯一標(biāo)準(zhǔn),我們以后在找工作的過程中免不了會遇到與指針相關(guān)的試題,本篇文章可以幫助我們提前了解一些常見的指針考點(diǎn),需要的可以了解一下
    2022-10-10
  • 簡單介紹C語言中的umask()函數(shù)和truncate()函數(shù)

    簡單介紹C語言中的umask()函數(shù)和truncate()函數(shù)

    這篇文章主要介紹了簡單介紹C語言中的umask()函數(shù)和truncate()函數(shù),是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • C語言?智能指針?shared_ptr?和?weak_ptr

    C語言?智能指針?shared_ptr?和?weak_ptr

    這篇文章主要介紹了C語言?智能指針?shared_ptr?和?weak_ptr,weak_ptr引入可以解決shared_ptr交叉引用時(shí)無法釋放資源的問題,下面來學(xué)習(xí)具體相關(guān)內(nèi)容吧,需要的朋友可以參考一下
    2022-04-04
  • C++中調(diào)用復(fù)制(拷貝)函數(shù)的三種情況總結(jié)

    C++中調(diào)用復(fù)制(拷貝)函數(shù)的三種情況總結(jié)

    這篇文章主要介紹了C++中調(diào)用復(fù)制(拷貝)函數(shù)的三種情況總結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • c++中的前向聲明用法解讀

    c++中的前向聲明用法解讀

    這篇文章主要介紹了c++中的前向聲明用法解讀,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06

最新評論

临清市| 枣阳市| 盐亭县| 航空| 恭城| 明水县| 鹿邑县| 株洲县| 区。| 新巴尔虎右旗| 玉林市| 济阳县| 神池县| 塘沽区| 会理县| 汕头市| 新邵县| 定结县| 乐业县| 汉沽区| 长宁县| 寿光市| 大连市| 灵川县| 广昌县| 沈阳市| 湘潭市| 巴马| 绩溪县| 个旧市| 宁波市| 大荔县| 黄山市| 乐都县| 日照市| 乌鲁木齐县| 平邑县| 高州市| 都江堰市| 汾西县| 密山市|