1. 程式人生 > >c++內部排序演算法

c++內部排序演算法

#include <iostream>
using namespace std;

/*
 *<<直接插入排序>>
 * 為了實現N個數的排序,將後面N-1個數依次插入到前面已排好的子序列中,
 *假定剛開始第1個數是一個已排好序的子序列。經過N-1趟就能得到一個有序序列。
 *****時間複雜度:最好情況O(n),最壞情況O(n^2),平均情況O(n^2).
 *****空間複雜度:O(1)
 *****穩定性:穩定
 */
void InsertSort( int* p, int nLen )
{
    int nTemp;
    for(int i=1; i<nLen; ++i)
    {
        nTemp = *(p+i);
        for(int j=i; j>0; --j)
        {
            if( nTemp < *(p+j-1) )
            {
                *(p+j) = *(p+j-1);
                *(p+j-1) = nTemp;
            }else{
                break;
            }
        }
    }
}
/*
 *<<折半插入排序>>
 * 與直接插入排序不同的是,折半插入排序不是邊比較邊移動,而是將比較和移
 *動操作分離出來,即先折半查找出元素的待插入位置,然後再統一地移動待插入位
 *置之後的所有元素。不難看出折半插入排序僅僅是減少了比較的次數。
 *****時間複雜度:O(n^2)
 *****空間複雜度:O(1)
 *****穩定性:穩定
 */
void BinaryInsertSort( int arr[], int nLen )
{
    int nHigh,nLow,nMid,i,j,nTemp;
    for(i=1; i<nLen; ++i)
    {
        nTemp = arr[i];
        nLow = 0;
        nHigh = i-1;
        while( nLow<=nHigh)
        {
            nMid = (nLow+nHigh)/2;
            if(arr[nMid]>nTemp)
            {
                nHigh = nMid-1;
            }else{
                nLow = nMid+1;
            }
        }
        for(j=i; j>nMid; --j)
        {
            arr[j] = arr[j-1];
        }
        arr[nMid] = nTemp;
    }
}

/*
 *<<希爾排序>>
 * 希爾排序通過比較相距一定間隔的元素,即形如L[i,i+d,i+2d,...i+kd]的序列
 *然後縮小間距,再對各分組序列進行排序。直到只比較相鄰元素的最後一趟排序為
 *止,即最後的間距為1。希爾排序有時也叫做*縮小增量排序*
 *****時間複雜度:依賴於增量序列的選擇,但最壞情況才為O(N^2)
 *****空間複雜度:O(1)
 *****穩定性:不穩定
 */
void ShellSort( int arr[], int nLen )
{
    int i, j, dk;
    int nTemp;

    for(dk=nLen/2; dk>0; dk/=2)
    {
        for(i=dk; i<nLen; ++i)
        {
            nTemp = arr[i];
            for(j=i-dk; j>=0; j-=dk)
            {
                if(arr[j]>nTemp)
                {
                    arr[j+dk] = arr[j];
                    arr[j] = nTemp;
                }
            }
        }
    }
}
/*
 *<<氣泡排序>>
 * 氣泡排序的基本思想是從後往前(或從前往後)兩兩比較相鄰元素的值,若為
 *逆序,則交換它們,直到序列比較完。我們稱它為一趟冒泡。每一趟冒泡都會將一
 *個元素放置到其最終位置上。
 *****時間複雜度:最好情況O(n),最壞情況O(n^2),平均情況O(n^2)
 *****空間複雜度:O(1)
 *****穩定性:穩定
 */
void BubbleSort( int arr[], int nLen )
{
    bool flag = false;
    for(int i=0; i<nLen-1; ++i)
    {
        flag = false;
        for(int j=nLen-1; j>i; --j)
        {
            if(arr[j-1]>arr[j])
            {
                flag = true;
                arr[j-1] = arr[j-1]^arr[j];
                arr[j] = arr[j-1]^arr[j];
                arr[j-1] = arr[j-1]^arr[j];
            }
        }
        if( !flag )
        {
            return;
        }
    }
}
/*
 *<<快速排序>>
 * 快速排序是對氣泡排序的一種改進。其基本思想是基於分治法:在待排序表L[n]
 *中任取一個元素pivot作為基準,通過一趟排序將序列劃分為兩部分L[1...K-1]和
 *L[k+1...n],是的L[1...k-1]中的所有元素都小於pivot,而L[k+1...n]中所有元素
 *都大於或等於pivot。則pivot放在了其最終位置L(k)上。然後,分別遞迴地對兩個子
 *序列重複上述過程,直至每部分內只有一個元素或空為止,即所有元素放在了其最終
 *位置上。
 *****時間複雜度:快排的執行時間與劃分是否對稱有關,最壞情況O(n^2),最好情況
 *O(nlogn),平均情況為O(nlogn)
 *****空間複雜度:由於需要遞迴工作棧,最壞情況為O(n),平均情況為O(logn)
 *****穩定性:不穩定
 */
int Partition(int a[], int low, int high)
{
    int pivot = a[low];
    while(low<high)
    {
        while(low<high && a[high]>=pivot)
        {
            --high;
        }
        a[low] = a[high];
        while(low<high && a[low]<=pivot)
        {
            ++low;
        }
        a[high] = a[low];
    }
    a[low] = pivot;
    return low;
}
void QuickSort(int a[], int low, int high)
{
    if(low<high)
    {
        int pivotPos = Partition(a, low, high);
        QuickSort(a, low, pivotPos-1);
        QuickSort(a, pivotPos+1, high);
    }
}
/*
 *<<簡單選擇排序>>
 * 選擇排序的演算法思想很簡單,假設序列為L[n],第i趟排序即從L[i...n]中選擇
 *關鍵字最小的元素與L(i)交換,每一趟排序可以確定一個元素的最終位置。經過n-1
 *趟排序就可以使得序列有序了。
 *****時間複雜度:始終是O(n^2)
 *****空間複雜度:O(1)
 *****穩定性:不穩定
 */
void SelectedSort( int a[], int n )
{
    for(int i=0; i<n-1; ++i)
    {
        int minPos = i;
        for(int j=i+1; j<n; ++j)
        {
            if(a[j]<a[minPos])
            {
                minPos = j;
            }
        }
        if( minPos != i)
        {
            a[i]=a[i]^a[minPos];
            a[minPos]=a[i]^a[minPos];
            a[i]=a[i]^a[minPos];
        }
    }
}

/*
 *<<堆排序>>
 * 堆排序是一種樹形選擇排序方法,在排序過程中,將L[n]看成是一棵完全二叉
 *樹的順序儲存結構,利用完全二叉樹中雙親節點和孩子節點之間的內在關係,在當
 *前無序區中選擇關鍵字最大(或最小)的元素。堆排序的思路是:首先將序列L[n]
 *的n個元素建成初始堆,由於堆本身的特點(以大根堆為例),堆頂元素就是最大
 *值。輸出堆頂元素後,通常將堆底元素送入堆頂,此時根結點已不滿足大根堆的性
 *質,堆被破壞,將堆頂元素向下調整使其繼續保持大根堆的性質,再輸出堆頂元素。
 *如此重複,直到堆中僅剩下一個元素為止。
 *****時間複雜度:O(nlogn)
 *****空間複雜度:O(1)
 *****穩定性:不穩定
 */
void AdjustUp( int arr[], int i, int nLen )
{
    int nTemp = arr[i];
    for(int largest=2*i+1; largest<nLen; largest=2*largest+1)
    {
        if(largest!=nLen-1 && arr[largest]>arr[largest+1])
            ++largest;
        if( nTemp > arr[largest] )
        {
            arr[i] = arr[largest];
            i = largest;
        }else{
            break;
        }
    }
    arr[i] = nTemp;
}
void BuildHeap( int arr[], int nLen )
{
    for(int i=nLen/2-1; i>=0; --i)
        AdjustUp(arr,i,nLen);
}
void SortHeap( int arr[], int nLen)
{
    BuildHeap(arr, nLen);
    for(int i=nLen-1; i>0; --i)// n-1趟的交換和建堆過程
    {
        arr[0] = arr[0]^arr[i];
        arr[i] = arr[0]^arr[i];
        arr[0] = arr[0]^arr[i];
        AdjustUp(arr, 0, i);
    }
}

int main( int argc, char *argv[])
{
    int arr[] = {9,6,7,4,2,5,3,1,8};
    int nLen = sizeof(arr)/sizeof(int);
    //InsertSort(arr, nLen);
    //BinaryInsertSort(arr, nLen);
    //ShellSort(arr, nLen);
    //BubbleSort(arr, nLen);
    //SortHeap(arr, nLen);
//    SelectedSort(arr,nLen);
    QuickSort(arr, 0, nLen-1);

    for(int i=0; i<nLen; ++i)
    {
        cout<<*(arr+i)<<' ';
    }cout<<endl;

    return 0;
}