通俗理解九大排序算法

轉自本人知乎文章:https://zhuanlan.zhihu.com/p/30311662算法

如今,但凡規模大一點的互聯網公司招聘軟件相關的崗位,都會對數據結構和算法有必定要求。做爲非科班出身的程序yuan,要想進好一點的公司,仍是老老實實地把基礎打紮實吧。數組

說到排序,你們應該都不陌生,由於你生活中確定有過網購吧,你在淘寶搜索寶貝的時候,遇到的就是排序,好比有按價格高低排序、按綜合排序、按信用高低排序。因此排序算法應該能夠說是算法裏面很重要的一個分支。數據結構

開始以前,先簡單介紹一下排序算法的幾個重要指標,這裏,我儘可能用本身理解的傻瓜式方法解讀:數據結構和算法

(1)穩定性:當序列中存在兩個或兩個以上的關鍵字相等的時候,若是排序前序列中r1領先於r2,那麼排序後r1若是仍舊領先r2的話,則是穩定的。(相等的元素排序後相對位置不變)ui

(2)不穩定性:當序列中存在兩個或兩個以上的關鍵字相等的時候,若是排序前序列中r1領先於r2,那麼排序後r1若是落後r2的話,則是不穩定的。(相等的元素排序後相對位置發生改變)spa

(3)時間複雜度:算法的時間開銷是衡量其好壞的最重要的標誌。高效率的算法應該具備更少的比較次數和記錄移動次數。3d

(4)空間複雜度:即執行算法所須要的輔助存儲的空間。code

1、直接插入排序(插入類)blog

流程描述:遍歷序列中的關鍵字,每次取一個待排序的關鍵字,從待排序關鍵字的前一個關鍵字逐次向前掃描,若是掃描到的關鍵字大於待排序關鍵字,則把掃描到的關鍵字日後移一個位置。最後找到插入位置,將待排序關鍵字插入。排序

void InsertSort(int R[],int n)
{
int i,j
int temp;
for(i=1;i<n;++i)
 {
temp=R[i];   //將待排關鍵字暫時存放在temp中
j=i-1;      //待排關鍵字的前一個關鍵字序號
while(j>=0&&temp<R[j])
//從待排關鍵字的前一個關鍵字開始掃描,若是大於待排關鍵字,則日後移一個位置
  {
  R[j+1]=R[j];
  --j; 
  }
  R[j+1]=temp; //找到插入位置,將temp中暫存的待排關鍵字插入
 }
}

最壞狀況:整個序列是逆序的時候,則內層循環的條件temp<R[j]始終成立,此時對於每一次外層循環,內層循環次數每次達到最大值(即內層循環位i次),外層循環i取值爲1~i-1,因此總的執行次數爲n(n-1)/2 。

最好狀況:整個序列爲正序的時候。內層循環條件始終不成立,因此內層循環始終不執行,始終執行語句R[j+1]=temp。因此時間複雜度爲O(n)。

空間複雜度:算法所需的輔助存儲空間不隨待排序列的規模變化而變化,是個常量,因此爲O(1)。

2、折半插入排序(插入類)

過程描述:過程同直接插入排序,只是不一樣於直接插入排序時用順序查找,這裏用的是折半查找。因此折半插入排序在查找過程上比直接插入排序節約很多時間。可是關鍵字移動次數和直接插入排序同樣。

最好狀況時間複雜度:

最壞狀況時間複雜度:

平均狀況時間複雜度:

 

3、冒泡排序(交換類)

過程描述:經過一系列的交換動做實現排序。首先第一個關鍵字和第二個關鍵字比較,若是第一個關鍵字大,兩者交換;而後第二個關鍵字和第三個關鍵字比較,若是第二個關鍵字大,兩者交換,不然不交換。一直進行下去,知道最終最大的哪一個關鍵字被交換到了最後,一趟冒泡排序完成。

void BubbleSort(int R[],int n)
{
int i,j,flag;
int temp;
for(i=n-1;i>=1;--i)
{
  flag=0;    //flag用來標記本趟排序是否發生了交換
  for(j=1;j<=i;++j)
  {
    if(R[j-1]>R[j])
     {
     temp=R[j];
     R[j-1]=R[j];
     R[j]=temp;
     flag=1;   //flag=1表示本次排序發生了交換
     }  
   if(flag==0)//若是沒有發生交換,說明序列有序,排序結束
   return;
}
}

最壞狀況:序列逆序,此時內層循環if語句的條件始終成立,基本操做執行的次數爲n-i。i取值爲1~n-1,因此總的執行次數爲(n-1+1)(n-1)/2=n(n-1)/2,因此時間複雜度爲O(n^2)。

最好狀況:序列正序。此時內層循環的條件比較語句始終不成立,不發生交換,內層循環執行n-1次,因此時間複雜度爲O(n)。

平均狀況:時間複雜度O(n^2)。

4、簡單選擇排序(選擇類)

void SelectSort(int R[],int n)
{
int i,j,k;
int temp;
  for(i=0;i<n;++i)
  {
    k=i;
    for(j=i+1;j<n;++j) //從i後面的序列中挑選一個最小的關鍵字
    {
       if(R[k]>R[j])
       k=j;            //
       temp=R[i];
       R[i]=R[k];
       R[k]=temp;
    }
  }
}

5、希爾排序(插入類)

過程 描述:重點在增量的選取。若是增量爲m,那麼將下標爲0、m、2m、3m的關鍵字分紅一組,將下標爲一、m+一、2m+一、3m+1等關鍵字分紅另一組,分別對這些組進行插入排序。這就是一趟希爾排序。

 

6、快速排序(交換類)

過程描述:每一趟選擇當前子序列中的一個關鍵字做爲樞軸(通常選擇第一個關鍵字做爲樞軸),將子序列中比樞軸小的移到樞軸前面,比樞軸大的移到樞軸後面,本趟交換完成後獲得新的更短的子序列,成爲下一趟交換的初始序列。一趟排序以後能夠肯定樞軸的最終位置。比樞軸小的所有在樞軸左邊,比樞軸大的所有在樞軸右邊。

void QuickSort(int R[],int high,int low)
{
int temp;
int i=low,j=high;
if(low<high)
{
temp=R[low];
while(i!=j)
 {
    while(j>i&&R[j]>=temp) --j; //從右往左掃描,找到一個小於樞軸temp的關鍵字
    if(i<j)
    {
      R[i]=R[j];  //將右邊小於樞軸temp的關鍵字放在temp的左邊
      ++i;       //左邊序列號向右移一位
    }
    while(i<j&&R[i]<temp) ++i;//從左向右掃描,找到一個大於樞軸關鍵字temp的關鍵字
    if(i<j)
     {
       R[j]=R[i];//將左邊大於樞軸temp的關鍵字放在temp的右邊
       --j;      //右邊序號向左移動一位
     }  
  }
 R[i]=temp;
 QuickSort(R,low,i-1);
 QuickSort(R,i+1,high);
 }
}

最好狀況:時間複雜度爲O(nlogx_{2}n) ,待排序列越接近無序,本算法效率越高。

最壞狀況:時間複雜度爲 O(n^{2}) ,待排序列越接近有序,本算法效率越低。

平均狀況:時間複雜度 O(nlogx_{2}n) 。

空間複雜度:從頭至尾只用了temp這一個輔助存儲,因此爲O(1)。

7、堆排序(選擇類)

把堆當作徹底二叉樹,大根堆---父親大孩子小;小根堆---父親小孩子大。

過程描述:整個排序的過程就是不斷地將序列調整爲堆。

以原始序列:49 38 65 97 76 13 27 49爲例,調整爲大根堆。

(1)調整97,97>49,不須要調整

(2)調整65,65>13,65>27,不須要調整

(3)調整38,38<97,38<76。須要調整,38和97交換,交換後38成爲49的根節點,,繼續將38和49交換。

(4)調整49,49<97,49<65,因此49和較大者97交換,交換後,49<76,仍然不知足大根堆,將49與76交換。

8、2路歸併排序

void mergeSort(int A[],int low,int high)
{
  if(low<high)
  {
    int mid=(low+high)/2;
    mergeSort(A,low,mid);   //歸併排序前半段
    mergeSort(A,mid+1,high);//歸併排序後半段
    merge(A,low,mid,high);  //把數組中的low到mid  和 mid+1到high的兩段有序序列歸併成一段有序序列
  }
}

9、基數排序

"多關鍵字排序",(1)最高位優先(2)最低位優先。例如最高位優先:先按最高位排成若干子序列,再對每一個子序列按次高位進行排序。

以下圖,低位優先的排序過程:每一個桶至關於一個隊列,先進先出規則。

最後獲得的結果:最高爲有序,最高位相同的關鍵字次高位有序,次高位相同的關鍵字最低位有序,因此整個序列有序。

相關文章
相關標籤/搜索