1. 程式人生 > >面試常考8種排序演算法的總結

面試常考8種排序演算法的總結

(1)插入排序
直接插入排序是一種較簡單的排序方法;
演算法思想:
將一個記錄插入到已排好的有序表中,從而得到一個新的記錄數加一的有序表;
示例:{3,45,66,97,1,6,65}
初始關鍵字 :
(3) 45 66 97 1 6 65
i=2: (45) (3 45) 66 97 1 6 65
i=3: (66) (3 45 66) 97 1 6 65
i=4: (97) (3 45 66 97) 1 6 65
i=5: (1) (1 3 45 66 97) 6 65
i=6: (6) (1 3 6 45 66 97) 65
i=7: (65) (1 3 6 45 65 66 97)
插入排序程式碼如下:

void insert_Sort(int *arr, int size)
{//arr 需要傳入的陣列,size陣列的大小
    for (int i = 1; i < size; i++)//進行size-1次插入
    {
        int j = 0;
        while (arr[j] < arr[i] && j < i)//找到插入的位置
        {
            j++;
        }
        if (i != j)  
        {
            int tmp = arr[i];
            for
(int k = i; k>j; k--) arr[k] = arr[k-1]; arr[j] = tmp; } } }

(2)希爾排序
希爾排序屬於插入排序類的方法;
演算法思想:
先將整個待排序序列分割成若干子序列分別進行直接插入排序,
待整個序列的記錄基本有序的時候,再對全體記錄進行一次直接插入排序。
希爾排序示例
希爾排序程式碼

void shell_Sort(int *arr, int size)
{
    int i, j, step;
    for (step
= size / 2; step > 0; step /= 2) { for (i = step; i < size;i++) for (j = i - step; j >= 0 && arr[j]>arr[j + step]; j -= step) swap(arr[j],arr[j+step]); } }

(3)氣泡排序
氣泡排序的演算法比較簡單;
演算法思想:
比較相鄰的兩個數,小的往上走,大的往下走,第一次比較之後,將最大放在最下面,一次類推,直至按順序排好。
冒泡示例
程式碼如下:

void mpSort(int *a,int size) //氣泡排序
{
    for (int i = 0; i <size; i++)//比較的數
    {
        for (int j = 0; j < size-i-1; j++)//比較的趟數
        {
            if (a[j] > a[j+1])
            {
                int t;
                 t=a[j];
                a[j] = a[j+1];
                a[j + 1] = t;
            }
        }
    }
}

(4)快速排序
對氣泡排序的一種改進方法;
演算法思想:
通過一趟排序將待排序的資料分割成獨立的兩個部分,其中一部分的記錄的資料比另一部分記錄資料小,
則可分別對這兩個部分繼續排序,即可達到整個資料有序。
快排示例如下

快速排序簡單程式碼如下:

void quick_Sort(int *arr, int h,int r)
{
    if (h < r)
    {

        int i = h, j = r, tmp = arr[i];
        while (i < j)
        {

            while (i < j&&tmp <= arr[j]) //以第一個數為基準,從右到左找小於tmp的數
                j--;
            if (i < j)
            {
                arr[i] = arr[j];
                i++;
            }
            while (i<j&&tmp>arr[i]) //從左到右再找大於tmp的數
                i++;
            if (i < j)
            {
                arr[j] = arr[i];
                j--;
            }
        }
        arr[i] = tmp;
        quick_Sort(arr, h, i - 1); //對以第一個數為基準的左邊的進行排序
        quick_Sort(arr, i + 1, r); //對以第一個數為基準的右邊的數進行排序
    }
}

(5)選擇排序
選擇排序比較簡單。
演算法思想:
通過n-i+1(i=1,2…n-1)個記錄中選擇關鍵字最小的作為有序序列的第i個記錄。
程式碼如下:

void selectSort(int *a,int size)
{
    for (int i = 0; i < size; i++)
    {
        int r = i;//記錄下標

        for (int j = i+1; j < size; j++)
          if (a[j] < a[r])
            r = j;
        if (i != r)
        {
                int t = a[i]; //交換最小的數和第一個數,
                a[i] = a[r]; //交換次小的和第二個,依次類推
                a[r] = t;
        }

    }
}

(6)堆排序(Heap Sort)
堆排序只需要一個記錄大小的輔助空間,每個待排序的記錄僅佔有一個儲存空間。
堆是改進版的選擇結構(樹形版),排序過程中可將元素看成一個完全二叉樹,每個結點的值都大(小)
於其子節點的值,當每個結點的值都大於子節點的值,稱為大頂堆;
當每個結點的值都小於子節點的值,稱為小頂堆;
(大頂堆)堆排序演算法的思想:
(1)將待排序的陣列進行堆的有序化形成一個大頂堆;
(2)將堆頂結點與堆的最後一個結點交換並輸出交換後的尾結點;
(3)將剩下的資料重新進行堆的有序化
(4)重複(2)(3)步驟,直至剩下最後一個數據為止。
(小頂堆的排序演算法的思想與大頂堆相反)
下面以這組資料為例:
資料 {3,2,1,4,6}
初始堆
3
/ \
2 1
/ \
4 6
(1)調整堆,形成大頂堆
6
/ \
4 1
/ \
2 3
(2)輸出最大的值,在從剩餘的數中在組成一個大頂堆
4
/ \
3 1
/
2 6
(3)調整堆,使堆頂的值最大,繼續輸出堆頂,直到剩下最後一個數
3
/ \
2 1
/
4 6

(4)重複(3)
2
/
1 3

4 6
(5)重複(3)
1
2 3
4 6
輸出排序後的資料:1 2 3 4 6
堆排序的程式碼如下所示:

#include <iostream>
using namespace std;
void adjustHeap(int *a, int i, int size) //調整堆,使其成為大頂堆
{                                       //結點的值大於左結點的值和右結點的值 
    int lchild = 2 * i + 1;
    int rchild = 2 * i + 2;
    if (lchild <size &&a[lchild]>a[i])
    {
        swap(a[lchild], a[i]);
    }
    if (rchild<size&&a[rchild]>a[i])
    {
        swap(a[rchild], a[i]);
    }                                                    }
void createHeap(int *a, int size) //建立堆
{
    int i,j;
    for (int j = 0; j <size / 2; j++) 
    {
        for (i = size / 2 - 1; i >= 0; i--)
        {
            adjustHeap(a, i, size);
        }
    }
    for (int i = 0; i < 8; i++)
    {
        cout << " " << a[i];
    }
    cout << endl;
}
void HeapSort(int *a,int size)  //堆排序
{
    int i;
    createHeap(a, size);
    for (i = size - 1; i >0; i--)        
    {
        swap(a[0],a[i]);       //交換堆頂的元素和最後一個結點的值
            adjustHeap(a, 0, i);//再次對堆進行調整
    }
}
int main()
{
    int a[8] = {3,2,1,4,6.7,9,76};
    HeapSort(a, 8);
    for (int i = 0; i < 8; i++)
    {
        cout << " " << a[i];
    }
    cout << endl;
    return 0;
}

(7)歸併排序
將兩個或兩個以上的有序表組合成一個新的有序表。
演算法思想:
將陣列前後相鄰的兩個有序序列歸併為一個有序序列。
歸併排序示例
歸併排序的程式碼可以去看這篇部落格:
http://blog.csdn.net/left_la/article/details/8656953
(8)基數排序
將資料按位拆分,從低到高位逐次比較大小。
eg:以整數為例,將要排序的數先按照個位數的大小,依次放入0-9桶中;
收集,再將數按照十位數的大小,依次放入0-9號桶中;
依次類推,再收集,依次比較高位,依次放入0-9號桶,即可得到結果;
{21,22,44,55,10,3,78,97,66,46}
步驟(1):以個位比較
0:10
1: 21
2:22
3:3
4: 44
5:55
6: 66,46
7:97
8:78
9:
收集:10 21 22 3 44 55 66 46 97 78
步驟(2):以十位比較
0:3
1: 10
2:21,22
3:
4: 44,46
5:55
6: 66
7:78
8:
9:97
收集:3,10,21,22,44,46,55,66,78,97
在資料最高位是2位,排序兩次,即可得到正確結果。

#include <iostream>
#include <stdlib.h>
#include <malloc.h>
using namespace std;
#define base_size 10 //關鍵字的基數,此時是十進位制的基數
#define Size 10
int base(int num, int pos)
{
  //得到數對應的高位和低位
    int tmp=1;
    for (int i= 0; i < pos - 1; i++)
    {
        tmp *= 10;
    }
    return   (num / tmp) % 10;
}

void baseSort(int *arr, int size)
{
    //定義二維陣列,即就是待排序陣列
    int *wat_arr[Size];
    for (int i = 0; i <10; i++)
    {
        wat_arr[i] = (int *)malloc(sizeof(int)*(size+1));
        wat_arr[i][0]=0;//記錄每個基準對應的資料個數

    }
    int j, pos;
    for (pos = 1; pos <= base_size; pos++)
    {
        for (j = 0; j < size; j++)
        {
            int num = base(arr[j], pos);
            cout << "num=" << num<<endl;
            int inde = ++wat_arr[num][0];
            wat_arr[num][inde] = arr[j];
        }


        for (int w = 0,j = 0; j < Size; j++)
        {

            for (int k = 1; k <= wat_arr[j][0]; k++)
                arr[w++] = wat_arr[j][k];

            wat_arr[j][0] = 0;
        }

    }
}

int GetNumInPos(int num, int pos)
{
    int temp = 1;
    for (int i = 0; i < pos - 1; i++)
        temp *= 10;

    return (num / temp) % 10;
}

int main()
{
    int arr[5] = { 19, 12, 39, 45, 57 };
    baseSort(arr, 5);
    for (int i = 0; i < 5; i++)
    {
        cout << arr[i] << " ";
    }
    return 0;
}

對於幾種排序的時間複雜度下面這個表做一總結
排序複雜度表格
圖片參考來自:資料結構C語言版(嚴蔚敏版)
部分程式碼參考到:http://blog.csdn.net/morewindows/article/details/6668714
總結,8種排序演算法其實挺重要的,在面試中會經常考到,希望有興趣的可以好好研究一下。