1. 程式人生 > >[置頂] 找工作知識儲備(3)---從頭說12種排序演算法:原理、圖解、動畫視訊演示、程式碼以及筆試面試題目中的應用

[置頂] 找工作知識儲備(3)---從頭說12種排序演算法:原理、圖解、動畫視訊演示、程式碼以及筆試面試題目中的應用

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

[置頂] 找工作知識儲備(3)---從頭說12種排序演算法:原理、圖解、動畫視訊演示、程式碼以及筆試面試題目中的應用

分類: 筆試面試基礎知識 
演算法那些事兒
  199人閱讀  評論(0)  收藏  舉報 12種排序演算法 原理 程式碼 圖解flash視訊 對應筆試面試題

目錄(?)[+]

作者:寒小陽

時間:2013年9月。
出處:http://blog.csdn.net/han_xiaoyang/article/details/12163251
宣告:版權所有,轉載請註明出處,謝謝。


0、前言    

 從這一部分開始直接切入我們計算機網際網路筆試面試中的重頭戲演算法了,初始的想法是找一條主線,比如資料結構或者解題思路方法,將博主見過做過整理過的演算法題逐個分析一遍(博主當年自己學演算法就是用這種比較笨的刷題學的,囧),不過又想了想,演算法這東西,博主自己學的過程中一直深感,基礎還是非常重要的,很多難題是基礎類資料結構和題目的思想綜合發散而來。比如說作為最基本的排序演算法就種類很多,而事實上筆試面試過程中發現掌握的程度很一般,有很多題目,包括很多演算法難題,其母題或者基本思想就是基於這些經典演算法的,比如說快排的partition演算法,比如說歸併排序中的思想,比如說桶排序中桶的思想。


        這裡對筆試面試最常涉及到的12種排序演算法(包括插入排序、二分插入排序、希爾排序、選擇排序、氣泡排序、雞尾酒排序、快速排序、堆排序、歸併排序、桶排序、計數排序和基數排序)進行了詳解。每一種演算法都有基本介紹、演算法原理分析、圖解/flash演示/視訊演示、演算法程式碼、筆試面試重點分析、筆試面試題等板塊,希望能幫助大家真正理解這些排序演算法,並能使用這些演算法的思想解決一些題。不多說了,下面就進入正題了。

一、插入排序

1)演算法簡介

        插入排序(Insertion Sort)的演算法描述是一種簡單直觀的排序演算法。它的工作原理是通過

構建有序序列,對於未排序資料,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,通常採用in-place排序(即只需用到O(1)的額外空間的排序),因而在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,為最新元素提供插入空間。

2)演算法描述和分析

    一般來說,插入排序都採用in-place在陣列上實現。具體演算法描述如下:

    1、從第一個元素開始,該元素可以認為已經被排序

    2、取出下一個元素,在已經排序的元素序列中從後向前掃描

    3、如果該元素(已排序)大於新元素,將該元素移到下一位置

    4、重複步驟3,直到找到已排序的元素小於或者等於新元素的位置

    5、將新元素插入到該位置後

    6、重複步驟2~5

        如果目標是把n個元素的序列升序排列,那麼採用插入排序存在最好情況和最壞情況。最好情況就是,序列已經是升序排列了,在這種情況下,需要進行的比較操作需(n-1)次即可。最壞情況就是,序列是降序排列,那麼此時需要進行的比較共有n(n-1)/2次。插入排序的賦值操作是比較操作的次數減去(n-1)次。平均來說插入排序演算法複雜度為O(n^2)。因而,插入排序不適合對於資料量比較大的排序應用。但是,如果需要排序的資料量很小,例如,量級小於千,那麼插入排序還是一個不錯的選擇。 插入排序在工業級庫中也有著廣泛的應用,在STL的sort演算法和stdlib的qsort演算法中,都將插入排序作為快速排序的補充,用於少量元素的排序(通常為8個或以下)。

3)演算法圖解、flash演示、視訊演示

圖解:


Flash:

http://www.tjbpi.com/jpk/shujujiegou/flash/%B5%DA%CA%AE%D2%BB%D5%C2%20%C5%C5%D0%F2/%D6%B1%BD%D3%B2%E5%C8%EB%C5%C5%D0%F2.swf

視訊:插入排序舞蹈

http://v.youku.com/v_show/id_XMjU4NTY5MzEy.html

4)演算法程式碼

[cpp]  view plain copy
  1. void insertion_sort(int array[], int first, int last)  
  2.  {  
  3.         int i,j;  
  4.         int temp;  
  5.         for (i = first+1; i<=last;i++)  
  6.         {  
  7.                 temp = array[i];  
  8.                 j=i-1;  
  9.    
  10.                 //與已排序的數逐一比較,大於temp時,該數後移  
  11.                 while((j>=first) && (array[j] > temp))  //當first=0,j迴圈到-1時,由於[[短路求值]],不會運算array[-1]  
  12.                 {  
  13.                         array[j+1] = array[j];  
  14.                         j--;  
  15.                 }  
  16.                 array[j+1] = temp;      //被排序數放到正確的位置  
  17.    
  18.         }  
  19.  }  

 5)考察點,重點和頻度分析

        把插入排序放在第一個的原因是因為其出現的頻度不高,尤其是這裡提到的直接排序演算法,基本在筆試的選擇填空問時間空間複雜度的時候才可能出現。畢竟排序速度比較慢,因此演算法大題中考察的次數比較比較少。

6)筆試面試例題

例題1、

請寫出連結串列的插入排序程式

[cpp]  view plain copy
  1. template<typename T>  
  2. struct list_node  
  3. {  
  4.     struct list_node<T> *next;  
  5.     T value;  
  6. };  
  7. template<typename T>  
  8. struct _list  
  9. {  
  10.     struct list_node<T> *head;  
  11.     int size;  
  12. };  
  13. template<typename T>  
  14. void SortLink(struct _list<T> * link) {  
  15.     struct list_node<T> *pHead,*pRear,*p,*tp;  
  16.     if (!link) return;  
  17.     for (pHead=link->head,pRear=0;pHead;pHead=pHead->next) {  
  18.         for (tp=pHead,p=pHead->next;p;tp=p,p=p->next)  
  19.             if (pHead->value>=p->value)  
  20.                 tp->next=p->next,p->next=pHead,pHead=p,p=tp;  
  21.         if (!pRear) link->head=pHead;  
  22.         else pRear->next=pHead;  
  23.         pRear=pHead;  
  24.     }  
  25. }  

例題2、

下列排序演算法中最壞複雜度不是n(n-1)/2的是 D

A.快速排序     B.氣泡排序   C.直接插入排序   D.堆排序

二、二分插入排序

1)演算法簡介

       二分(折半)插入(Binary insert sort)排序是一種在直接插入排序演算法上進行小改動的排序演算法。其與直接排序演算法最大的區別在於查詢插入位置時使用的是二分查詢的方式,在速度上有一定提升。

2)演算法描述和分析

    一般來說,插入排序都採用in-place在陣列上實現。具體演算法描述如下:

    1、從第一個元素開始,該元素可以認為已經被排序

    2、取出下一個元素,在已經排序的元素序列中二分查詢到第一個比它大的數的位置

    3、將新元素插入到該位置後

    4、重複上述兩步


        1)穩定

        2)空間代價:O(1)

        3)時間代價:插入每個記錄需要O(log i)比較,最多移動i+1次,最少2次。最佳情況O(n log n),最差和平均情況O(n^2)

        二分插入排序是一種穩定的排序。當n較大時,總排序碼比較次數比直接插入排序的最差情況好得多,但比最好情況要差,所元素初始序列已經按排序碼接近有序時,直接插入排序比二分插入排序比較次數少。二分插入排序元素移動次數與直接插入排序相同,依賴於元素初始序列。

3)演算法圖解、flash演示、視訊演示

圖解:

                                                          

視訊:二分插入排序

http://v.youku.com/v_show/id_XMTA1MTkwMTEy.html

4)演算法程式碼

[cpp]  view plain copy
  1. void BinInsertSort(int a[], int n)   
  2. {   
  3.         int key, left, right, middle;   
  4.         for (int i=1; i<n; i++)   
  5.         {   
  6.                 key = a[i];   
  7.                 left = 0;   
  8.                 right = i-1;   
  9.                 while (left<=right)   
  10.                 {   
  11.                         middle = (left+right)/2;   
  12.                         if (a[middle]>key)   
  13.                                 right = middle-1;   
  14.                         else   
  15.                                 left = middle+1;   
  16.                 }   
  17.                    
  18.                 for(int j=i-1; j>=left; j--)   
  19.                 {   
  20.                         a[j+1] = a[j];   
  21.                 }   
  22.                    
  23.                 a[left] = key;          
  24.         }   
  25. }  

 5)考察點,重點和頻度分析

        這個排序演算法在筆試面試中出現的頻度也不高,但畢竟是直接排序演算法的一個小改進演算法,同時二分查詢又是很好的思想,有可能會在面試的時候提到,演算法不難,留心一下就會了。

6)筆試面試例題

例題1、

下面的排序演算法中,初始資料集的排列順序對演算法的效能無影響的是(B)

A、二分插入排序         B、堆排序         C、氣泡排序            D、快速排序

例題2、

寫出下列演算法的時間複雜度。

(1)氣泡排序;(2)選擇排序;(3)插入排序;(4)二分插入排序;(5)快速排序;(6)堆排序;(7)歸併排序;

三、希爾排序

1)演算法簡介

希爾排序,也稱遞減增量排序演算法,因DL.Shell於1959年提出而得名,是插入排序的一種高速而穩定的改進版本。

2)演算法描述

    1、先取一個小於n的整數d1作為第一個增量,把檔案的全部記錄分成d1個組。

    2、所有距離為d1的倍數的記錄放在同一個組中,在各組內進行直接插入排序。

    3、取第二個增量d2<d1重複上述的分組和排序,

    4、直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有記錄放在同一組中進行直接插入排序為止。

          希爾排序的時間複雜度與增量序列的選取有關,例如希爾增量時間複雜度為O(n^2),而Hibbard增量的希爾排序的時間複雜度為O(N^(5/4)),但是現今仍然沒有人能找出希爾排序的精確下界。

3)演算法圖解、flash演示、視訊演示

圖解:





Flash:

http://ds.fzu.edu.cn/fine/resources/FlashContent.asp?id=92

視訊:希爾排序Shell Sort 舞蹈

http://v.youku.com/v_show/id_XMjU4NTcwMDIw.html

4)演算法程式碼

[cpp]  view plain copy
  1. #include <stdio.h>  
  2.    
  3. int main()  
  4. {  
  5.      const int n = 5;  
  6.      int i, j, temp;   
  7.      int gap = 0;  
  8.      int a[] = {5, 4, 3, 2, 1};   
  9.      while (gap<=n)  
  10.      {  
  11.           gap = gap * 3 + 1;  
  12.      }   
  13.      while (gap > 0)   
  14.      {  
  15.          for ( i = gap; i < n; i++ )  
  16.          {  
  17.              j = i - gap;  
  18.              temp = a[i];               
  19.              while (( j >= 0 ) && ( a[j] > temp ))  
  20.              {  
  21.                  a[j + gap] = a[j];  
  22.                  j = j - gap;  
  23.              }  
  24.              a[j + gap] = temp;  
  25.          }  
  26.          gap = ( gap - 1 ) / 3;  
  27.      }      
  28.  }  

5)考察點,重點和頻度分析

        事實上希爾排序演算法在筆試面試中出現的頻度也不比直接插入排序高,但它的時間複雜度並不是一個定值,所以偶爾會被面試官問到選擇的步長和時間複雜度的關係,要稍微有點了解吧。演算法大題中使用該方法或者其思想的題也不多。

6)筆試面試例題

例題1、

寫出希爾排序演算法程式,並說明最壞的情況下需要進行多少次的比較和交換。

    程式略,需要O(n^2)次的比較

例題2、

設要將序列(Q, H, C, Y, P, A, M, S, R, D, F, X)中的關鍵碼按字母序的升序重新排列,則:

氣泡排序一趟掃描的結果是       H, C, Q, P, A, M, S, R, D, F, X ,Y      ;

初始步長為4的希爾(shell)排序一趟的結果是   P, A, C, S, Q, D, F, X , R, H,M, Y     ;

二路歸併排序一趟掃描的結果是   H, Q, C, Y,A, P, M, S, D, R, F, X&

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述

作者:寒小陽

時間:2013年9月。
出處:http://blog.csdn.net/han_xiaoyang/article/details/12163251
宣告:版權所有,轉載請註明出處,謝謝。


0、前言    

 從這一部分開始直接切入我們計算機網際網路筆試面試中的重頭戲演算法了,初始的想法是找一條主線,比如資料結構或者解題思路方法,將博主見過做過整理過的演算法題逐個分析一遍(博主當年自己學演算法就是用這種比較笨的刷題學的,囧),不過又想了想,演算法這東西,博主自己學的過程中一直深感,基礎還是非常重要的,很多難題是基礎類資料結構和題目的思想綜合發散而來。比如說作為最基本的排序演算法就種類很多,而事實上筆試面試過程中發現掌握的程度很一般,有很多題目,包括很多演算法難題,其母題或者基本思想就是基於這些經典演算法的,比如說快排的partition演算法,比如說歸併排序中的思想,比如說桶排序中桶的思想。
        這裡對筆試面試最常涉及到的12種排序演算法(包括插入排序、二分插入排序、希爾排序、選擇排序、氣泡排序、雞尾酒排序、快速排序、堆排序、歸併排序、桶排序、計數排序和基數排序)進行了詳解。每一種演算法都有基本介紹、演算法原理分析、圖解/flash演示/視訊演示、演算法程式碼、筆試面試重點分析、筆試面試題等板塊,希望能幫助大家真正理解這些排序演算法,並能使用這些演算法的思想解決一些題。不多說了,下面就進入正題了。

一、插入排序

1)演算法簡介

        插入排序(Insertion Sort)的演算法描述是一種簡單直觀的排序演算法。它的工作原理是通過構建有序序列,對於未排序資料,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,通常採用in-place排序(即只需用到O(1)的額外空間的排序),因而在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,為最新元素提供插入空間。

2)演算法描述和分析

    一般來說,插入排序都採用in-place在陣列上實現。具體演算法描述如下:

    1、從第一個元素開始,該元素可以認為已經被排序

    2、取出下一個元素,在已經排序的元素序列中從後向前掃描

    3、如果該元素(已排序)大於新元素,將該元素移到下一位置

    4、重複步驟3,直到找到已排序的元素小於或者等於新元素的位置

    5、將新元素插入到該位置後

    6、重複步驟2~5

        如果目標是把n個元素的序列升序排列,那麼採用插入排序存在最好情況和最壞情況。最好情況就是,序列已經是升序排列了,在這種情況下,需要進行的比較操作需(n-1)次即可。最壞情況就是,序列是降序排列,那麼此時需要進行的比較共有n(n-1)/2次。插入排序的賦值操作是比較操作的次數減去(n-1)次。平均來說插入排序演算法複雜度為O(n^2)。因而,插入排序不適合對於資料量比較大的排序應用。但是,如果需要排序的資料量很小,例如,量級小於千,那麼插入排序還是一個不錯的選擇。 插入排序在工業級庫中也有著廣泛的應用,在STL的sort演算法和stdlib的qsort演算法中,都將插入排序作為快速排序的補充,用於少量元素的排序(通常為8個或以下)。

3)演算法圖解、flash演示、視訊演示

圖解:


Flash:

http://www.tjbpi.com/jpk/shujujiegou/flash/%B5%DA%CA%AE%D2%BB%D5%C2%20%C5%C5%D0%F2/%D6%B1%BD%D3%B2%E5%C8%EB%C5%C5%D0%F2.swf

視訊:插入排序舞蹈

http://v.youku.com/v_show/id_XMjU4NTY5MzEy.html

4)演算法程式碼

[cpp]  view plain copy
  1. void insertion_sort(int array[], int first, int last)  
  2.  {  
  3.         int i,j;  
  4.         int temp;  
  5.         for (i = first+1; i<=last;i++)  
  6.         {  
  7.                 temp = array[i];  
  8.                 j=i-1;  
  9.    
  10.                 //與已排序的數逐一比較,大於temp時,該數後移  
  11.                 while((j>=first) && (array[j] > temp))  //當first=0,j迴圈到-1時,由於[[短路求值]],不會運算array[-1]  
  12.                 {  
  13.                         array[j+1] = array[j];  
  14.                         j--;  
  15.                 }  
  16.                 array[j+1] = temp;      //被排序數放到正確的位置  
  17.    
  18.         }  
  19.  }  

 5)考察點,重點和頻度分析

        把插入排序放在第一個的原因是因為其出現的頻度不高,尤其是這裡提到的直接排序演算法,基本在筆試的選擇填空問時間空間複雜度的時候才可能出現。畢竟排序速度比較慢,因此演算法大題中考察的次數比較比較少。

6)筆試面試例題

例題1、

請寫出連結串列的插入排序程式

[cpp]  view plain copy
  1. template<typename T>  
  2. struct list_node  
  3. {  
  4.     struct list_node<T> *next;  
  5.     T value;  
  6. };  
  7. template<typename T>  
  8. struct _list  
  9. {  
  10.     struct list_node<T> *head;  
  11.     int size;  
  12. };  
  13. template<typename T>  
  14. void SortLink(struct _list<T> * link) {  
  15.     struct list_node<T> *pHead,*pRear,*p,*tp;  
  16.     if (!link) return;  
  17.     for (pHead=link->head,pRear=0;pHead;pHead=pHead->next) {  
  18.         for (tp=pHead,p=pHead->next;p;tp=p,p=p->next)  
  19.             if (pHead->value>=p->value)  
  20.                 tp->next=p->next,p->next=pHead,pHead=p,p=tp;  
  21.         if (!pRear) link->head=pHead;  
  22.         else pRear->next=pHead;  
  23.         pRear=pHead;  
  24.     }  
  25. }  

例題2、

下列排序演算法中最壞複雜度不是n(n-1)/2的是 D

A.快速排序     B.氣泡排序   C.直接插入排序   D.堆排序

二、二分插入排序

1)演算法簡介

       二分(折半)插入(Binary insert sort)排序是一種在直接插入排序演算法上進行小改動的排序演算法。其與直接排序演算法最大的區別在於查詢插入位置時使用的是二分查詢的方式,在速度上有一定提升。

2)演算法描述和分析

    一般來說,插入排序都採用in-place在陣列上實現。具體演算法描述如下:

    1、從第一個元素開始,該元素可以認為已經被排序

    2、取出下一個元素,在已經排序的元素序列中二分查詢到第一個比它大的數的位置

    3、將新元素插入到該位置後

    4、重複上述兩步


        1)穩定

        2)空間代價:O(1)

        3)時間代價:插入每個記錄需要O(log i)比較,最多移動i+1次,最少2次。最佳情況O(n log n),最差和平均情況O(n^2)

        二分插入排序是一種穩定的排序。當n較大時,總排序碼比較次數比直接插入排序的最差情況好得多,但比最好情況要差,所元素初始序列已經按排序碼接近有序時,直接插入排序比二分插入排序比較次數少。二分插入排序元素移動次數與直接插入排序相同,依賴於元素初始序列。

3)演算法圖解、flash演示、視訊演示

圖解:

                                                          

視訊:二分插入排序

http://v.youku.com/v_show/id_XMTA1MTkwMTEy.html

4)演算法程式碼

[cpp]  view plain copy
  1. void BinInsertSort(int a[], int n)   
  2. {   
  3.         int key, left, right, middle;   
  4.         for (int i=1; i<n; i++)   
  5.         {   
  6.                 key = a[i];   
  7.                 left = 0;   
  8.                 right = i-1;   
  9.                 while (left<=right)   
  10.                 {   
  11.                         middle = (left+right)/2;   
  12.                         if (a[middle]>key)   
  13.                                 right = middle-1;   
  14.                         else   
  15.                                 left = middle+1;   
  16.                 }   
  17.                    
  18.                 for(int j=i-1; j>=left; j--)   
  19.                 {   
  20.                         a[j+1] = a[j];   
  21.                 }   
  22.                    
  23.                 a[left] = key;          
  24.         }   
  25. }  

 5)考察點,重點和頻度分析

        這個排序演算法在筆試面試中出現的頻度也不高,但畢竟是直接排序演算法的一個小改進演算法,同時二分查詢又是很好的思想,有可能會在面試的時候提到,演算法不難,留心一下就會了。

6)筆試面試例題

例題1、

下面的排序演算法中,初始資料集的排列順序對演算法的效能無影響的是(B)

A、二分插入排序         B、堆排序         C、氣泡排序            D、快速排序

例題2、

寫出下列演算法的時間複雜度。

(1)氣泡排序;(2)選擇排序;(3)插入排序;(4)二分插入排序;(5)快速排序;(6)堆排序;(7)歸併排序;

三、希爾排序

1)演算法簡介

希爾排序,也稱遞減增量排序演算法,因DL.Shell於1959年提出而得名,是插入排序的一種高速而穩定的改進版本。

2)演算法描述

    1、先取一個小於n的整數d1作為第一個增量,把檔案的全部記錄分成d1個組。

    2、所有距離為d1的倍數的記錄放在同一個組中,在各組內進行直接插入排序。

    3、取第二個增量d2<d1重複上述的分組和排序,

    4、直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有記錄放在同一組中進行直接插入排序為止。

          希爾排序的時間複雜度與增量序列的選取有關,例如希爾增量時間複雜度為O(n^2),而Hibbard增量的希爾排序的時間複雜度為O(N^(5/4)),但是現今仍然沒有人能找出希爾排序的精確下界。

3)演算法圖解、flash演示、視訊演示

圖解:





Flash:

http://ds.fzu.edu.cn/fine/resources/FlashContent.asp?id=92

視訊:希爾排序Shell Sort 舞蹈

http://v.youku.com/v_show/id_XMjU4NTcwMDIw.html

4)演算法程式碼

[cpp]  view plain copy
  1. #include <stdio.h>  
  2.    
  3. int main()  
  4. {  
  5.      const int n = 5;  
  6.      int i, j, temp;   
  7.      int gap = 0;  
  8.      int a[] = {5, 4, 3, 2, 1};   
  9.      while (gap<=n)  
  10.    &nb