日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

C++实现十大排序算法(冒泡,选择,插入,归并,快速,堆,希尔,桶,计数,基数)排序算法时间复杂度、空间复杂度、稳定性比较(面试经验总结)

發布時間:2023/11/27 生活经验 32 豆豆

排序算法分類

?

內部排序算法又分為基于比較的排序算法和不基于比較的排序算法,其分類如下:

比較排序:?? 直接插入排序? ? 希爾排序?(插入) ?冒泡排序? ? ?快速排序 ?(交換)?直接選擇排序? 堆排序(選擇)? ?歸并排序

非比較排序:桶排序? 基數排序

排序算法比較表格

?

排序算法平均時間復雜度最壞時間復雜度空間復雜度是否穩定
冒泡排序O(n2)O(n2)O(1)
選擇排序O(n2)O(n2)O(1)不是
直接插入排序O(n2)O(n2)O(1)
歸并排序O(nlogn)O(nlogn)O(n)
快速排序O(nlogn)O(n2)O(logn)不是
堆排序O(nlogn)O(nlogn)O(1)不是
希爾排序O(nlogn)O(ns)O(1)不是
計數排序O(n+k)O(n+k)O(n+k)
基數排序O(N?M)O(N?M)O(M)

注:

1 歸并排序可以通過手搖算法將空間復雜度降到O(1),但是時間復雜度會提高。

2 基數排序時間復雜度為O(N*M),其中N為數據個數,M為數據位數。

輔助記憶

  • 時間復雜度記憶-?
    • 冒泡、選擇、直接 排序需要兩個for循環,每次只關注一個元素,平均時間復雜度為O(n2)O(n2)(一遍找元素O(n),一遍找位置O(n))
    • 快速、歸并、希爾、堆基于二分思想,log以2為底,平均時間復雜度為O(nlogn))(一遍找元素O(n),一遍找位置O(logn))
  • 穩定性記憶-“快希選堆”(快犧牲穩定性)?
    • 排序算法的穩定性:排序前后相同元素的相對位置不變,則稱排序算法是穩定的;否則排序算法是不穩定的。

原理理解

1 冒泡排序

1.1 過程

冒泡排序從小到大排序:一開始交換的區間為0~N-1,將第1個數和第2個數進行比較,前面大于后面,交換兩個數,否則不交換。再比較第2個數和第三個數,前面大于后面,交換兩個數否則不交換。依次進行,最大的數會放在數組最后的位置。然后將范圍變為0~N-2,數組第二大的數會放在數組倒數第二的位置。依次進行整個交換過程,最后范圍只剩一個數時數組即為有序。(相鄰兩項比較,將最大數選出,放到最后位置)站在位置的角度考慮

2 動圖

1.3 核心代碼(函數)

//array[]為待排序數組,n為數組長度
void BubbleSort(int array[], int n)
{int i, j, k;for(i=0; i<n-1; i++)for(j=0; j<n-1-i; j++){if(array[j]>array[j+1]){k=array[j];array[j]=array[j+1];array[j+1]=k;}}
}

2 選擇排序

2.1 過程

選擇排序從小到大排序:一開始從0~n-1區間上選擇一個最小值,將其放在位置0上,然后在1~n-1范圍上選取最小值放在位置1上。重復過程直到剩下最后一個元素,數組即為有序。

2.2 動圖

2.3 核心代碼(函數)

//array[]為待排序數組,n為數組長度
void selectSort(int array[], int n)
{int i, j ,min ,k;for( i=0; i<n-1; i++){min=i; //每趟排序最小值先等于第一個數,遍歷剩下的數for( j=i+1; j<n; j++) //從i下一個數開始檢查{if(array[min]>array[j]){min=j;}}if(min!=i){k=array[min];array[min]=array[i];array[i]=k;}}
}
  • 3 插入排序

3.1 過程

插入排序從小到大排序:首先位置1上的數和位置0上的數進行比較,如果位置1上的數大于位置0上的數,將位置0上的數向后移一位,將1插入到0位置,否則不處理。位置k上的數和之前的數依次進行比較,如果位置K上的數更大,將之前的數向后移位,最后將位置k上的數插入不滿足條件點,反之不處理。

3.2 動圖

?

3.3 核心代碼(函數)

//array[]為待排序數組,n為數組長度
void insertSort(int array[], int n)
{int i,j,temp;for( i=1;i<n;i++){if(array[i]<array[i-1]){temp=array[i];for( j=i;array[j-1]>temp;j--){array[j]=array[j-1];}array[j]=temp;}}
}

4 歸并排序

4.1 過程

歸并排序從小到大排序:首先讓數組中的每一個數單獨成為長度為1的區間,然后兩兩一組有序合并,得到長度為2的有序區間,依次進行,直到合成整個區間。

4.2 動圖

?

4.3 核心代碼(函數)

  • 遞歸實現
實現歸并,并把數據都放在list1里面 
void merging(int *list1, int list1_size, int *list2,  int list2_size)
{int i=0, j=0, k=0, m=0;int temp[MAXSIZE];while(i < list1_size && j < list2_size){if(list1[i]<list2[j]){temp[k++] = list1[i++];}else{temp[k++] = list2[j++];}}while(i<list1_size){temp[k++] = list1[i++];}while(j<list2_size){temp[k++] = list2[j++];}for(m=0; m < (list1_size+list2_size); m++){list1[m]=temp[m];}
}
//如果有剩下的,那么說明就是它是比前面的數組都大的,直接加入就可以了 
void mergeSort(int array[], int n)
{if(n>1){int *list1 = array;int list1_size = n/2;int *list2 = array + n/2;int list2_size = n-list1_size;mergeSort(list1, list1_size);mergeSort(list2, list2_size);merging(list1, list1_size, list2, list2_size);}
}
//歸并排序復雜度分析:一趟歸并需要將待排序列中的所有記錄  
//掃描一遍,因此耗費時間為O(n),而由完全二叉樹的深度可知,  
//整個歸并排序需要進行[log2n],因此,總的時間復雜度為  
//O(nlogn),而且這是歸并排序算法中平均的時間性能  
//空間復雜度:由于歸并過程中需要與原始記錄序列同樣數量級的  
//存儲空間去存放歸并結果及遞歸深度為log2N的棧空間,因此空間  
//復雜度為O(n+logN)  
//也就是說,歸并排序是一種比較占內存,但卻效率高且穩定的算法 
  • 迭代實現
void MergeSort(int k[],int n)  
{  int i,next,left_min,left_max,right_min,right_max;  //動態申請一個與原來數組一樣大小的空間用來存儲int *temp = (int *)malloc(n * sizeof(int));  //逐級上升,第一次比較2個,第二次比較4個,第三次比較8個。。。  for(i=1; i<n; i*=2)  {  //每次都從0開始,數組的頭元素開始  for(left_min=0; left_min<n-i; left_min = right_max)  {  right_min = left_max = left_min + i;  right_max = left_max + i;  //右邊的下標最大值只能為n  if(right_max>n)  {  right_max = n;  }  //next是用來標志temp數組下標的,由于每次數據都有返回到K,  //故每次開始得重新置零  next = 0;  //如果左邊的數據還沒達到分割線且右邊的數組沒到達分割線,開始循環  while(left_min<left_max&&right_min<right_max)  {  if(k[left_min] < k[right_min])  {  temp[next++] = k[left_min++];  }  else  {  temp[next++] = k[right_min++];  }  }  //上面循環結束的條件有兩個,如果是左邊的游標尚未到達,那么需要把  //數組接回去,可能會有疑問,那如果右邊的沒到達呢,其實模擬一下就可以  //知道,如果右邊沒到達,那么說明右邊的數據比較大,這時也就不用移動位置了  while(left_min < left_max)  {  //如果left_min小于left_max,說明現在左邊的數據比較大  //直接把它們接到數組的min之前就行  k[--right_min] = k[--left_max];   }  while(next>0)  {  //把排好序的那部分數組返回該k  k[--right_min] = temp[--next];        }  }  }  
}  
//非遞歸的方法,避免了遞歸時深度為log2N的棧空間,
//空間只是用到歸并臨時申請的跟原來數組一樣大小的空間,并且在時間性能上也有一定的提升,
//因此,使用歸并排序是,盡量考慮用非遞歸的方法。

5 快速排序

5.1 過程

快速排序從小到大排序:在數組中隨機選一個數(默認數組首個元素),數組中小于等于此數的放在左邊,大于此數的放在右邊,再對數組兩邊遞歸調用快速排序,重復這個過程。

5.2 動圖

?

5.3 核心代碼(函數)

推薦程序(好理解)

//接口調整
void adjust_quicksort(int k[],int n)  
{  quicksort(k,0,n-1);  
}  
void quicksort(int a[], int left, int right)  
{  int i,j,t,temp;  if(left>right)   //(遞歸過程先寫結束條件)return;  temp=a[left]; //temp中存的就是基準數  i=left;  j=right;  while(i!=j)  {  //順序很重要,要先從右邊開始找(最后交換基準時換過去的數要保證比基準小,因為基準                               //選取數組第一個數,在小數堆中) while(a[j]>=temp && i<j)  j--;  //再找右邊的  while(a[i]<=temp && i<j)  i++;  //交換兩個數在數組中的位置  if(i<j)  {  t=a[i];  a[i]=a[j];  a[j]=t;  }  }  //最終將基準數歸位 (之前已經temp=a[left]過了,交換只需要再進行兩步)a[left]=a[i];  a[i]=temp;  quicksort(left,i-1);//繼續處理左邊的,這里是一個遞歸的過程  quicksort(i+1,right);//繼續處理右邊的 ,這里是一個遞歸的過程  
}  

6.1 過程

堆排序從小到大排序:首先將數組元素建成大小為n的大頂堆,堆頂(數組第一個元素)是所有元素中的最大值,將堆頂元素和數組最后一個元素進行交換,再將除了最后一個數的n-1個元素建立成大頂堆,再將最大元素和數組倒數第二個元素進行交換,重復直至堆大小減為1。

  • 注:完全二叉樹?
    假設二叉樹深度為n,除了第n層外,n-1層節點都有兩個孩子,第n層節點連續從左到右。如下圖?

  • 注:大頂堆?
    大頂堆是具有以下性質的完全二叉樹:每個節點的值都大于或等于其左右孩子節點的值。?
    即,根節點是堆中最大的值,按照層序遍歷給節點從1開始編號,則節點之間滿足如下關系:?
    ?(1<=i<=n/2)

6.2 動圖

?
?

6.3 核心代碼(函數)


注意!!!數組從1開始,1~n

void heapSort(int array[], int n)
{int i;for (i=n/2;i>0;i--){HeapAdjust(array,i,n);//從下向上,從右向左調整}for( i=n;i>1;i--){swap(array, 1, i);HeapAdjust(array, 1, i-1);//從上到下,從左向右調整}
}
void HeapAdjust(int array[], int s, int n )
{int i,temp;temp = array[s];for(i=2*s;i<=n;i*=2){if(i<n&&array[i]<array[i+1]){i++;}if(temp>=array[i]){break;}array[s]=array[i];s=i;}array[s]=temp;
}
void swap(int array[], int i, int j)
{int temp;temp=array[i];array[i]=array[j];array[j]=temp;
}

7 希爾排序

7.1 過程

希爾排序是插入排序改良的算法,希爾排序步長從大到小調整,第一次循環后面元素逐個和前面元素按間隔步長進行比較并交換,直至步長為1,步長選擇是關鍵。

7.2 動圖

?

7.3 核心程序(函數)

//下面是插入排序
void InsertSort( int array[], int n)
{int i,j,temp;for( i=0;i<n;i++ ){if(array[i]<array[i-1]){temp=array[i];for( j=i-1;array[j]>temp;j--){array[j+1]=array[j];}array[j+1]=temp;}}
}
//在插入排序基礎上修改得到希爾排序
void SheelSort( int array[], int n)
{int i,j,temp;int gap=n; //~~~~~~~~~~~~~~~~~~~~~do{gap=gap/3+1;  //~~~~~~~~~~~~~~~~~~for( i=gap;i<n;i++ ){if(array[i]<array[i-gap]){temp=array[i];for( j=i-gap;array[j]>temp;j-=gap){array[j+gap]=array[j];}array[j+gap]=temp;}}}while(gap>1);  //~~~~~~~~~~~~~~~~~~~~~~}

8 桶排序(基數排序和基數排序的思想)

8.1 過程

桶排序是計數排序的變種,把計數排序中相鄰的m個”小桶”放到一個”大桶”中,在分完桶后,對每個桶進行排序(一般用快排),然后合并成最后的結果。

8.2 圖解

8.3 核心程序

#include <stdio.h>
int main()
{int a[11],i,j,t;for(i=0;i<=10;i++)a[i]=0;  //初始化為0for(i=1;i<=5;i++)  //循環讀入5個數{scanf("%d",&t);  //把每一個數讀到變量t中a[t]++;  //進行計數(核心行)}for(i=0;i<=10;i++)  //依次判斷a[0]~a[10]for(j=1;j<=a[i];j++)  //出現了幾次就打印幾次printf("%d ",i);getchar();getchar(); //這里的getchar();用來暫停程序,以便查看程序輸出的內容//也可以用system("pause");等來代替return 0;
}

9 計數排序

9.1 過程

算法的步驟如下:?
- 找出待排序的數組中最大和最小的元素?
- 統計數組中每個值為i的元素出現的次數,存入數組C的第i項?
- 對所有的計數累加(從C中的第一個元素開始,每一項和前一項相加)?
- 反向填充目標數組:將每個元素i放在新數組的第C(i)項,每放一個元素就將C(i)減去1

9.2 圖解

9.3 核心程序(函數)

程序1:
#define NUM_RANGE (100)    //預定義數據范圍上限,即K的值void counting_sort(int *ini_arr, int *sorted_arr, int n)  //所需空間為 2*n+k
{  int *count_arr = (int *)malloc(sizeof(int) * NUM_RANGE);  int i, j, k;  //初始化統計數組元素為值為零 for(k=0; k<NUM_RANGE; k++){  count_arr[k] = 0;  }  //統計數組中,每個元素出現的次數    for(i=0; i<n; i++){  count_arr[ini_arr[i]]++;  }  //統計數組計數,每項存前N項和,這實質為排序過程for(k=1; k<NUM_RANGE; k++){  count_arr[k] += count_arr[k-1];  }  //將計數排序結果轉化為數組元素的真實排序結果for(j=n-1 ; j>=0; j--){  int elem = ini_arr[j];          //取待排序元素int index = count_arr[elem]-1;  //待排序元素在有序數組中的序號sorted_arr[index] = elem;       //將待排序元素存入結果數組中count_arr[elem]--;              //修正排序結果,其實是針對算得元素的修正}  free(count_arr);  
}  程序2:C++(最大最小壓縮桶數)
public static void countSort(int[] arr) {if (arr == null || arr.length < 2) {return;}int min = arr[0];int max = arr[0];for (int i = 1; i < arr.length; i++) {min = Math.min(arr[i], min);max = Math.max(arr[i], max);}int[] countArr = new int[max - min + 1];for (int i = 0; i < arr.length; i++) {countArr[arr[i] - min]++;}int index = 0;for (int i = 0; i < countArr.length; i++) {while (countArr[i]-- > 0) {arr[index++] = i + min;}
}
  • 10 基數排序

10.1 過程

基數排序是基于數據位數的一種排序算法。?
它有兩種算法?
①LSD–Least Significant Digit first 從低位(個位)向高位排。?
②MSD– Most Significant Digit first 從高位向低位(個位)排。?
時間復雜度O(N*最大位數)。?
空間復雜度O(N)。

10.2 圖解

?
對a[n]按照個位0~9進行桶排序:?
?
對b[n]進行累加得到c[n],用于b[n]中重復元素計數?
!!!b[n]中的元素為temp中的位置!!!跳躍的用++補上:?
?
temp數組為排序后的數組,寫回a[n]。temp為按順序倒出桶中的數據(聯合b[n],c[n],a[n]得到),重復元素按順序輸出:?

10.3 核心程序

1.1 VS2010程序

#include "stdafx.h"
#include "stdio.h"
#include <stdlib.h>void BubbleSort(int array[], int n){int i,j,k,count1=0, count2=0;for(i=0; i<n-1; i++)for(j=n-1; j>i; j--){count1++;if(array[j-1]>array[j]){count2++;k=array[j-1];array[j-1]=array[j];array[j]=k;}}printf("總共的循環次序為:%d,  總共的交換次序為:%d\n\n", count1, count2);
}int main(int argc, _TCHAR* argv[])
{int as[]={0,1,2,3,4,6,8,5,9,7};BubbleSort(as, 10);for(int i=0; i<10; i++){printf("%d", as[i]);}printf("\n\n");system("pause");return 0;
}

1.2 執行程序(OJ)

#include <stdio.h>void BubbleSort(int array[], int n){int i,j,k,count1=0, count2=0;for(i=0; i<n-1; i++)for(j=n-1; j>i; j--){count1++;if(array[j-1]>array[j]){count2++;k=array[j-1];array[j-1]=array[j];array[j]=k;}}printf("總共的循環次序為:%d,  總共的交換次序為:%d\n\n", count1, count2);
}int main()
{int as[]={0,1,2,3,4,6,8,5,9,7};BubbleSort(as, 10);int i=0;for(i=0; i<10; i++){printf("%d", as[i]);}return 0;
}

2 關于交換的優化

不用中間變量進行交換

?C語言實現數組動態輸入

#include <stdio.h>  
#include <assert.h>  //斷言頭文件
#include <stdlib.h>  int main(int argc, char const *argv[])  
{  int size = 0;  scanf("%d", &size);   //首先輸入數組個數assert(size > 0);     //判斷數組個數是否非法int *array = (int *)calloc(size, sizeof(int));  //動態分配數組if(!R1)  {  return;           //申請空間失敗  }  int i = 0;  for (i = 0; i < size; ++i) {  scanf("%d", &array[i]);  }  mergeSort(array, size);  printArray(array, size);  free(array);  return 0;  
} 

注:?
1.colloc與malloc類似,但是主要的區別是存儲在已分配的內存空間中的值默認為0,使用malloc時,已分配的內存中可以是任意的值.?
2.colloc需要兩個參數,第一個是需要分配內存的變量的個數,第二個是每個變量的大小.

參考博文

[1]https://blog.csdn.net/yushiyi6453

[2]https://blog.csdn.net/yushiyi6453/article/details/76407640

?

版權聲明:本文為博主原創文章,未經博主允許不得轉載。

總結

以上是生活随笔為你收集整理的C++实现十大排序算法(冒泡,选择,插入,归并,快速,堆,希尔,桶,计数,基数)排序算法时间复杂度、空间复杂度、稳定性比较(面试经验总结)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。