【總結】經典排序算法(C++)

最近在學習算法,趁這個機會總結一些算法。慢慢更新,歡迎交流探討。

參考書籍:《算法導論》

排序:

輸入:n個數

輸出:有序(從大到小、從小到大)序列

一、插入排序

做排序的都需要做遍歷,而插入排序,顧名思義,就是插隊。

不必多說,給個案例體會一下:

輸入:5 4 3 2 1

處理

  •    4 5 3 2 1
  •    3 4 5 2 1
  •    2 3 4 5 1
  •    1 2 3 4 5

輸出:1 2 3 4 5

 

輸入:6 8 2 4 5

處理

  • 6 8 2 4 5
  • 2 6 8 4 5
  • 2 4 6 8 5
  • 2 4 5 6 8

代碼如下(測試):

(排序部分第11-16行);

input:輸入數組元素數n;輸入數組元素a[i];輸入n=0代碼結束;

#include<iostream>
#include<string.h>
using namespace std;
int main()
{
    int n,key,i,j,a[100];
    while (cin>>n,n!=0)
    {
        for(int i=0;i<n;i++)
        cin>>a[i];
        for(int j=1;j<n;j++)
        {
            key=a[j];
           for(i=j-1;i>=0&&a[i]>key;i--)
               a[i+1]=a[i];
            a[i+1]=key;
        }
        for(int k=0;k<n;k++)
        {
            cout<<a[k]<<" ";
        }
        cout<<endl;
    }
}

二、選擇排序:

規則:首先找到數組的最小數,與a[0]交換;循環下去,找到第n小的數,與數組的第n個數交換;

案例

    輸入: 5 4 9 8 3

    處理

  • 3 4 9 8 5
  • 3 4 9 8 5
  • 3 4 5 8 9
  • 3 4 5 8 9

輸出:3 4 5 8 9

代碼如下:

#include<iostream>
using namespace std;
int main()
{
    int n,a[100],key,x;
    while(cin>>n,n!=0)
    {
        for(int i=0;i<n;i++)
            cin>>a[i];
        for(int i=0;i<n;i++)
    {
       key=a[i];
       x=i;
       for(int j=i+1;j<n;j++)
       {
           if(a[j]<key)
           {
               key=a[j];
               x=j;
           }
       }
       int tem=a[i];
       a[i]=a[x];
       a[x]=tem;
    }
    for(int i=0;i<n;i++)
        cout<<a[i]<<" ";
    }
}

三、歸併排序(MERGE SORT)

規則:將原數組分解成n個子序列,再對子序列遞歸地進行排序。其中,單個元素被視爲是已經排列好的。

說明:這個算法在下根據課本先做了兩個函數,第一個是做對數組的分割,其次是對數組的排序;而在主函數中,用了srand產生100以內的隨機數。

案例:

輸入:5 2 4 7 1 3 2 6

處理:分割:5     2    4    7    1    3    2    6

           合併:2 5    4 7    1 3     2 6  

           再合併:2 4 5 7    1 2 3 6

           再合併:1 2 3 4 5 6 7

代碼如下:

#include <iostream>
#include <time.h>
#include <stdlib.h>
using namespace std;

void Merge(int *_Array, int p, int q, int r) {// p:第0個;r:第n-1個數,q:第(r + p) / 2個數
    int len1 = q - p + 1;
    int len2 = r - q;
    int *L = new int[len1 + 1];//用動態數組儲存左邊的數
    int *R = new int[len2 + 1];//用動態數組儲存右邊的數

    for (int i = 0; i < len1; i++) {// 把Array數組左邊的數放入L數組
        L[i] = _Array[p + i];
    }

    for (int j = 0; j < len2; j++) {// 把Array數組右邊的數放入R數組
        R[j] = _Array[q + 1 + j];
    }
    L[len1]=R[len2]=INT_MAX;    //定義無窮大
    int i = 0, j = 0;
    for (int k = p; k <= r; k++) {
        if (L[i] < R[j]) {//小的放左邊,大的放右邊
            _Array[k] = L[i];
            i++;
        }
        else {
            _Array[k] = R[j];
            j++;
        }
    }
}

void MergeSort(int _Array[], int p, int r) {
    if (p < r) {//p:第0個;r:第n-1個數。數組至少要有兩個數據
        int q;
        q = (r + p) / 2;//拆分兩組
        MergeSort(_Array , p , q);//拆分第0個到第 (r + p) / 2個 ,即拆分左半部分
        MergeSort(_Array , q+1 , r);//拆分第(r + p) / 2個到第r個 ,即拆分右半部分
        Merge(_Array , p , q , r);//調用合併函數,從第0個到第n-1個排好
    }
}

int main() {
    int n;
    cout<<"請輸入數組的元素數:";
    cin >> n;
    cout << endl;
    int *Array = new int[n];
    cout << "隨機數組爲:";
    srand((unsigned)time(0));

    for (int i = 0; i < n; i++) {
        Array[i] =  (rand()%(100-0+1))+0;
        //cin>>;
        cout<<Array[i]<<"  ";
    }
    cout<<endl;

    MergeSort(Array,0,n-1);

    cout << "排序後的數組爲:";
    for(int j  = 0;j<n;j++){
        cout<<Array[j]<<"  ";
    }
    return 0 ;
}

 

四、快速排序法

  • 介紹:

       快速排序的最壞情況(輸入數從小到大或從大到小)的運行時間爲cita(n^2),但快速排序是用於排序的最佳實用選擇,因爲其平均性能相當好,一般的運行時間爲cita(nlgn),且cita(nlgn)中的常數因子很小。此外,快速排序還可以就地排序,在虛存環境中也能很好運行。

        同歸並排序類似地,快速排序也是基於分治法的,

  • divide 分解:將數組A[p....r]劃分爲兩個子數組A[p..q-1]和A[q...r]排序,使得A[p...q-1]<=A(q)<=A[q+1...r]
  • conquer解決:通過遞歸調用Quicksort,對子數組A[p...q-1]和A[q...r]排序。
  • combine.合併:此步可忽略,因爲A[p...r]已經排序。
  • 原理:

  • 案例:(來自算法導論)僅partition部分:

代碼如下:

#include<iostream>
#include<time.h>
#include<stdlib.h>
using namespace std;
int Partition(int *a,int p,int q)        //函數:使得<x的數在X的左邊,>x的數在x的右邊
{
    int x=a[p];
    int i=p;
    for(int j=p+1;j<=q;j++)
    {
        if(a[j]<=x)
        {
            i++;
            int temp=a[i];
            a[i]=a[j];
            a[j]=temp;
        }
    }
    int temp=a[i];
    a[i]=a[p];
    a[p]=temp;
    return i;
    }
void QuickSort(int *a,int p,int q)
{
    if(p<q)            //遞歸停止的信號p>=q
    {
        int r=Partition(a,p,q);
        QuickSort(a,p,r-1);
        QuickSort(a,r+1,q);
    }
}
int main()
{
    int n;
    cout<<"請輸入";
    cin >> n;
    cout << endl;
    int *Array = new int[n];
    cout << "產生的隨機數組爲:";
    srand((unsigned)time(0));
    for (int i = 0; i < n; i++) {
        Array[i] =  (rand()%(100-0+1))+0;
        cout<<Array[i]<<"  ";
    }
    cout<<endl;

    QuickSort(Array,0,n-1);

    cout << "排序後的數組爲:";
    for(int j  = 0;j<n;j++){
        cout<<Array[j]<<"  ";
    }
    return 0;
}

快速排序的最佳情況運行時間爲cita(nlgn);

快速排序的最壞情況運行時間爲cita(n^2)   //即是劃分得不平衡,如劃分爲n-1與1;

,而插入排序的最壞情況運行時間爲cita(n),這時候快速排序真是徒負虛名。這歸咎於我們選取的x的位置被固定住了,所以下面的隨機快速排序就是一種優化。

五、隨機快速排序

作爲一種優化,其實也是用一個隨機種子生產隨機數,隨機抽取某一個數做爲x,再調用partition函數,僅僅加了一個函數,再做一點點修改,代碼如下:

#include<iostream>
#include<time.h>            //添加文件
#include<stdlib.h>
using namespace std;
int Partition(int *a,int p,int q)
{
    int x=a[p];
    int i=p;
    for(int j=p+1;j<=q;j++)
    {
        if(a[j]<=x)
        {
            i++;
            int temp=a[i];
            a[i]=a[j];
            a[j]=temp;
        }
    }
    int temp=a[i];
    a[i]=a[p];
    a[p]=temp;
    return i;
    }
int Random_Partition(int* a,int p,int q)    //產生隨機數做下標,使得中間數是隨機的數
{
    int i=rand()%(q-p)+0;
    int temp=a[i];
    a[i]=a[q];
    a[q]=temp;
    return Partition(a,p,q);
}
void QuickSort(int *a,int p,int q)
{
    if(p<q)
    {
        int r=Random_Partition(a,p,q);
        QuickSort(a,p,r-1);
        QuickSort(a,r+1,q);
    }
}
int main()
{
    int n;
    cout<<"請輸入";
    cin >> n;
    cout << endl;
    int *Array = new int[n];
    cout << "產生的隨機數組爲:";
    srand((unsigned)time(0));
    for (int i = 0; i < n; i++) {
        Array[i] =  (rand()%(100-0+1))+0;
        cout<<Array[i]<<"  ";
    }
    cout<<endl;

    /*cout<<"請輸入數組:"<<endl;
    for(int i=0;i<n;i++)
        cin>>Array[i];*/
    QuickSort(Array,0,n-1);
    cout << "返回的下標爲:"<<Partition(Array,0,n-1)<<endl;
    cout << "排序後的數組爲:";
    for(int j  = 0;j<n;j++){
        cout<<Array[j]<<"  ";
    }
    delete []Array ;
    return 0;
}

六、計數排序法

#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
void Counting_Sort(int *a,int *b,int n,int *c,int m)
{
    for(int i=0;i<m;i++)
        c[i]=0;
    for(int j=0;j<n;j++)
        c[a[j]]++;
    for(int i=1;i<m;i++)
        c[i]+=c[i-1];
    for(int j=n-1;j>=0;j--)
    {
        b[c[a[j]]-1]=a[j];
        c[a[j]]--;
    }
}
int main()
{
    int n,m;
    cout<<"input an number as the size of the matrix:"<<endl;
    cin>>n;
    cout<<"input the largest number you hope:"<<endl;
    cin>>m;
    int *a = new int[n];
    int *b = new int[n];
    int *c = new int[m];
    cout<<"here is the matrix:"<<endl;
    srand((unsigned)time(0));
    for(int i=0;i<n;i++)
    {
        a[i]=rand()%(m+1)+0;
        cout<<a[i]<<" ";
    }
    cout<<endl;
    /*寫成函數。。
    for(int i=0;i<m;i++)//注意這些循環的界限
        c[i]=0;
    for(int j=0;j<n;j++)
        c[a[j]]++;
    for(int i=1;i<m;i++)
        c[i]+=c[i-1];
    for(int j=n-1;j>=0;j--)
    {
        b[c[a[j]]-1]=a[j];
        c[a[j]]--;
    }*/
    Counting_Sort(a,b,n,c,m);
    cout<<"and the result is:"<<endl;
    for(int i=0;i<n;i++)
        cout<<b[i]<<" ";
    cout<<endl;
    delete []a;                 //new之後最好delete掉
    delete []b;
    delete []c;
}

七、基數排序法

#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int GetMax(int a[],int n)
{
    int max=a[0];
    for (int i=0;i<n;i++)
        max= a[i]>max?a[i]:max;
    return max;
}
void CountingSort(int a[],int n,int exp)
{
    int b[n]={0};
    int c[10]={0};
    for(int i=0;i<n;i++)
        c[(a[i]/exp)%10]++;
    for(int i=1;i<10;i++)
        c[i]+=c[i-1];
    for(int j=n-1;j>=0;j--)
    {
        b[c[(a[j]/exp)%10]-1]=a[j];
        c[(a[j]/exp)%10]--;
    }
    for(int i=0;i<n;i++)
        a[i]=b[i];
}
void RadixSort(int a[],int n)
{
    int exp;
    int max=GetMax(a,n);
    for(exp=1;max/exp>0;exp*=10)
        CountingSort(a,n,exp);
}
int main()
{
    int n,m;
    cout<<"please input a numb as the length of matrix:"<<endl;
    cin>>n;
    cout<<"please input the largest numb you hope:"<<endl;
    cin>>m;
    int *a = new int [n];
    srand((unsigned)time(0));
    for(int i=0;i<n;i++)
    {
        a[i]=rand()%m;
        cout<<a[i]<<" ";
    }cout<<endl;
    RadixSort(a,n);
    for(int i=0;i<n;i++)
    {
        cout<<a[i]<<" ";
    }cout<<endl;
    delete []a;
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章