1. 程式人生 > >整理了下常用的排序演算法

整理了下常用的排序演算法

1、組內有個分享的活動,我整理了常用的排序演算法。講的不太通,備份下,會陸續把程式碼附上。

內部排序:

例子中都是從小到大排序的。

1、 插入排序

1.1、       直接插入排序:將一個記錄插入到一個有序的列表中,得到一個新的,記錄數加一的新的列表。進行關鍵字比較和移動的次數約N^2/4,時間複雜度ON^2)。

1.2、       折半插入排序:在直接插入排序的基礎上減少比較的次數。其中“查詢”的動作用“折半查詢”來實現。只能減少比較的次數,不能減少移動的次數,時間複雜度ON^2)。N較大的時候效果明顯。

1.3、       2-路插入排序:在折半插入排序上再改進,減少移動的次數。需要N個輔助空間,如a[N],從小到大排序,將第一個數放在a[0]中,如果比a[0]大,放在後面,如果比a[0]小,放在前面。將陣列a[]看成一個迴圈向量。移動的次數約為

N^2/8.時間複雜度O(N^2)。如果a[0]是最小的話,就失效了。

1.4、       希爾排序:主要是通過增量序列中5和3,把整個序列弄的基本有序。以減少排序的比較和移動的次數。【如何取增量序列,和如何計算時間複雜度沒有定論】

2、 快速排序

2.1、       起泡排序:每次比較後,將待排序的數中最大的那個放到最後。比較和移動的次數為N*(N-1)/2。時間複雜度ON^2)。

2.2、       快速排序:對起泡排序進行改進,每趟排序,將待排記錄中提取一個關鍵字,將其分成兩塊,一塊都比這個關鍵字小,一塊都比這個關鍵字大。遞迴下去,直到結束。時間複雜度ON*logN)。注意棧的深度。

非遞迴的版本:URL:http://blog.163.com/[email protected]/blog/static/31809050201146113859317/

#include <iostream>
#include <stack>
using namespace std;

template <class T>
int partition(T a[],int low,int high)
{
    T v=a[low];
    while(low<high)
    {
        while(low<high && a[high]>=v)
            high--;
        a[low]=a[high];
        while(low<high && a[low]<=v)
            low++;
        a[high]=a[low];
    }
    a[low]=v;

    return low;
}

template <class T>
void QuickSort(T a[],int p,int q)
{
    stack<int> st;
    int j;

    do{
        while(p<q)
        {
            j=partition(a,p,q);
            if( (j-p)<(q-j) )
            {
                st.push(j+1);
                st.push(q);
                q=j-1;
            }
            else
            {
                st.push(p);
                st.push(j-1);
                p=j+1;
            }
        }

        if(st.empty())
            return;
        q=st.top();st.pop();
        p=st.top();st.pop();
    }while(1);
}

int main()
{
    int a[7]={3,5,2,3,1,66,225};

    for(int i=0;i<7;i++)
        cout<<a[i]<<" ";
    cout<<endl;

    QuickSort(a,0,6);

    for(int i=0;i<7;i++)
        cout<<a[i]<<" ";
    return 0;
}

3、 選擇排序

3.1、簡單選擇排序:每一趟在N-i+1(I = 1,2….N)中找到最小的作為有序序列的第i個記錄。               關鍵字間比較的次數為N(N-1)/2.時間複雜度為O(N^2)。

3.2、樹形選擇排序:改進的方向是減少比較次數,是因為前一次的比較對後面也是有意                     義的。從體育比賽錦標賽中引申而來。時間複雜度為

3.3、堆形選擇排序: 

    n個關鍵字序列Kl,K2,…,Kn稱為(Heap),當且僅當該序列滿足如下性質(簡稱  為堆性質):(1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n),當然,這是小根堆,大根堆    則換成>=號。//k(i)相當於二叉樹的非葉結點,K(2i)則是左孩子,k(2i+1)是右孩    子完全二叉樹。得到最小的值,然後調整剩下的元素,讓其滿足堆的性質,繼續取出最小值。知道堆中只剩下一個元素為止。適用於較多的數。時間複雜度為:O(N*logN)

對應的程式碼:

#include <map>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <iostream>

using namespace std;

int NUM = 19;
int a[19] ={0,1,2,3,4,5,6,7,8,0,1,2,3,4,5,6,7,8,0};

//int i代表開始的位置,lenth總的長度
void heapsort(int a[],int i,int lenth)
{
    cout<<"i is "<<i<<" lenth is "<<lenth<<" "<<endl;
    int tmp = a[i], child = 2*i;
    for (; child <= lenth; child *= 2)
    {
        if ((child + 1 <= lenth ) && (a[child] < a[child+1]))
            ++child;
        if (tmp > a[child])
            break;
        a[i] = a[child];
        i = child;
    }

    a[i] = tmp;
}

int main()
{
    int t,tmp;
    int i;

    for(i = 0; i < NUM; i++)
        cout<<a[i]<<" ";
    cout<<endl;

    for (t = NUM/2; t > 0; t--)
    {
        heapsort(a,t,NUM - 1);

        for(i = 0; i < NUM; i++)
            cout<<a[i]<<" ";
        cout<<endl;
    }
    cout<<"--------------"<<endl;

    for (t = NUM - 1; t > 1; t--)
    {
       tmp = a[1]; a[1]=a[t]; a[t]=tmp;
       heapsort(a,1,t-1);

        for(i = 0; i < NUM; i++)
            cout<<a[i]<<" ";
        cout<<endl;
    }
}

 4、 計數排序: 每次掃描所有的數,將比要排序的數小的數的個數記下來,然後將這個要排序的數放在個數+1的位置。

5、 基數排序:將所有待比較數值(正整數)統一為同樣的數位長度,數位較短的數前面補零。然後,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以後, 數列就變成一個有序序列。基數排序的時間複雜度是O(k·n),其中n是排序元素個數,k是數字位數。

6、 桶排序:假定:輸入是由一個隨機過程產生的[0, 1)區間上均勻分佈的實數。將區間[0, 1)劃分為n個大小相等的子區間(桶),每桶大小1/n:[0, 1/n), [1/n, 2/n), [2/n, 3/n),…,[k/n, (k+1)/n ),…將n個輸入元素分配到這些桶中,對桶中元素進行排序,然後依次連線桶輸入0 ≤A[1..n] <1輔助陣列B[0..n-1]是一指標陣列,指向桶(連結串列)。

7、歸併排序:歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表。SR[1,2,3,…n],SR中為n個前後相鄰且長度為h的有序序列。時間複雜度為,空間O(n)。其中n是指序列的個數。

外部排序

利用外存對資料檔案進行排序的方法稱為外部排序。

1、 簡單歸併排序。