常用排序算法合集

排序分類:插入排序,選擇排序,交換排序,歸併排序(不討論)

插入排序:直接插入排序,希爾排序

選擇排序:簡單選擇排序,堆排序

交換類排序:冒泡排序,快速排序

 

typedef struct {
    int *date;
    int lenth;
}sqlist;

一.冒泡排序算法

/**************冒泡排序算法實現************/
// 時間複雜度=O(n*n)
//思想:從後往前,不斷比較相鄰連個數的大小,將小的數放在前面
int SelectSort(sqlist *L)
{
    int i = 0;
    int j = 0;
    int flag = 1; 
    for (i = 0; i < L->lenth&&flag; i++) 
        {
            flag = 0; //初次遍歷數組時初始化爲0,如果遍歷完後沒有數據交換
                     // 說明此時後面的數據是有序排列

            for (j = L->lenth - 2; j >= i; j--) //從後往前進行比較犟嘴曉得一個數放在第i個位置
            {
                if (L->date[j]>L->date[j+1]) //若前者大於後者交換兩者數據
                {
                    L->date[j] = L->date[j] ^ L->date[j+1];
                    L->date[j+1] = L->date[j] ^ L->date[j + 1];
                    L->date[j] = L->date[j] ^ L->date[j + 1];
                    flag = 1;//遇到數據交換置1
                }
            }
        }
    return 0;
}

二.簡單選擇排序算法

/**************簡單選擇排序算法實現************/
// 時間複雜度=O(n*n)
//與冒泡排序相似只不過簡單選擇排序是再一次循環中找到最小值下標,在循環結束後才進行值得交換
//雖然時間複雜度相同,但是簡單選擇排序的性能優於冒泡排序
int SelectSort(sqlist *L)
{
    int i = 0;
    int j = 0;
    int min = 0;
    for (i = 0; i < L->lenth; i++)
    {
        min = i; //記錄當前下標
        for (j = L->lenth - 1; j > i; j--) //從後往前進行比較犟嘴曉得一個數放在第i個位置
        {
            if (L->date[min]>L->date[j ]) //若前者大於後者交換兩者數據
            {
                
                min = j; //如果下標j的置小於min下標表示的值,記錄最小下標
            }
        }
        if (min != i) 
        {
            L->date[min] = L->date[min] ^ L->date[i];
            L->date[i] = L->date[min] ^ L->date[i];
            L->date[min] = L->date[min] ^ L->date[i];
        }
    }
    return 0;
}

三.直接插入排序算法

/********直接插入排序*******/
//時間複雜度:O=(n*n)算法性能優於冒泡和簡單選擇
//思想:
//分段比較:即是從數組中第二個元素開始一次和前面的一個比較。
//若果購後面一個小於前面一個,那麼記錄這個數字,將前面的數據後移直到前出現一個數
//小於這個記錄的數,停止移動,降記錄的數據插入即可。
int InsertSort(sqlist *L)
{
    int i,j;
    int flag = 0;
    i = j = 0;

    for (i = 1; i < L->lenth; i++) //從第二個數開始判斷前一個和後一個大小關係
    {
        if (L->date[i] < L->date[i - 1]) //判斷前後數據的大小關係
        {
            flag = L->date[i]; //記錄這個小的數
            for (j = i - 1; flag<L->date[j]&&j>-1; j--) //數據後移直到出現一個數小於flag爲止
                                                        //或者遍歷完整個子數組序列爲止(此時j=-1)
            {
                L->date[j + 1] = L->date[j]; 
            }
            L->date[j + 1] = flag; //插入到合適位置
        }
    }

    return 0;
}
四.希爾排序算法

/********希爾排序*******/
//時間複雜度:O=(n的2/3次方)要好於直接排序
//注意:增量序列(increment)的最後一個增量值必須等於1,即是必須要做一次直接插入排序
//希爾排序並不是一種穩定的排序算法
//增量(increment)選取參考大話數據結構P395的介紹
//思想:
//1:選取合適分段區間
//2:以這個分段區間爲間隔執行插入排序
//例如:{ 50, 10, 60, 70, 20, 40, 80, 1, 15 }若是分段區間爲2則;
//對{50,60,20,80,15}這個子序列執行直接插入排序
int ShellSort(sqlist *L)
{
    int i, j;
    int increment = L->lenth;
    int flag = 0;
    i = j = 0;

    while (increment > 1)
    {
        increment = increment / 3 + 1; //注意值了不要把3換爲2不然會出現increment=2時 increment / 3 + 1恆爲2死循環
        for (i = increment ; i <L->lenth; i++)
        {
            if (L->date[i] < L->date[i - increment])
            {
                flag = L->date[i];
                for (j = i - increment; (j>-1) && (flag < L->date[j]); j = j - increment)
                {
                    L->date[j + increment] = L->date[j];
                }
                L->date[j+increment] = flag;
            }
        }
    } 
    
    return 0;
}

五.堆排序算法

///********堆排序*******/
//時間複雜度:O=(nlogn) (排序優選項)
//思想:不斷構造大頂堆,然後將最大值(根的值)放入數組末尾
//繼續從lenth-2(末尾前一個)繼續構造大頂堆依次下去
//注意大頂堆特點:所有根節點的值逗比左右子節點值大
//堆排序時間複雜度:O=(nlogn)空間複雜度O=1,而由於構建堆所需
//的次數比較多,因此它並不適合待排個數較少情況


//以根節點爲中心遍歷樹,將根節點下面的子樹(包括根)按照根的數值最大排序
int HeapAdjust(sqlist *L, int s, int max)  
{
    int temp, j;
    temp = L->date[s]; //記錄根的值
    for (j = 2 * s; j <=max; j = j * 2)  //從s根節點的左子樹開始遍歷
    {
        if (j < max&&L->date[j] < L->date[j + 1]) //左子樹小於右子樹
            j++;
        if (temp >= L->date[j]) //根大於該數的最大節點那麼退出
            break;
        L->date[s] = L->date[j]; //交換根的值
        s = j;                   //以這個節點爲根繼續向下排序,使得根爲最大的數
    }
    L->date[s] = temp;  
    return 0;
}
void HeapSort(sqlist *L) //堆排序算法
{
    int i;
    for (i = L->lenth / 2; i > -1; i--)//構建大頂推使得每科字數的根節點爲最大節點
        HeapAdjust(L, i, L->lenth);      
    for (i = L->lenth-1; i > 0; i--) //交換數據
    {
        L->date[0] = L->date[0] ^ L->date[i];
        L->date[i] = L->date[0] ^ L->date[i];
        L->date[0] = L->date[0] ^ L->date[i];
        HeapAdjust(L, 0,i-1);      //以根節點(第一個節點)目標找到最大值放在根節點位置
    }
}

六.快速排序算法

  /******快排算法實現*/
//時間複雜度:最優:O=(nlogn),平均:(n*n)
//思想;選取一個關鍵字使得比這個關鍵字小的數位於他的左邊,比他大的位於右邊
//重複進行,不斷將整個序列劃分爲若干個子序列
//low:待交換的數組起始位置
//high:待交換的數組末尾起始位置
int partiton(sqlist *L, int low, int high)  //使得關鍵左邊的數小於關鍵字右邊的數大於關鍵字
{
    int pivotkey; //定義關鍵字變量
    pivotkey = L->date[low];//關鍵字取線性表中的第一個元素
    while (low < high) 
    {
        while (low < high&&L->date[high] >= pivotkey)//low < high限制low和high最終指向同一個元素也就是pinokey的值
            high--;                                  //如果沒有這條限制語句那麼最終low和high不會指向同一個數(low<high或者high),
                                                    //那麼我們在後面就要判斷pinokey的座標值是位於low還是high
        if (L->date[low] != L->date[high])
        {
            L->date[low] = L->date[low] ^ L->date[high];
            L->date[high] = L->date[low] ^ L->date[high];
            L->date[low] = L->date[low] ^ L->date[high];
        } 
        while (low < high&&L->date[low] <= pivotkey)
            low++;
        if (L->date[low] != L->date[high]) //避免兩者相等時出現交換失敗
        {
            L->date[low] = L->date[low] ^ L->date[high];
            L->date[high] = L->date[low] ^ L->date[high];
            L->date[low] = L->date[low] ^ L->date[high];
        }
    }
    return low;
}
int qsort(sqlist *L, int low, int high) //劃分序列
{
    int pivot;
    if (low < high)
    {
        pivot = partiton(L, low, high);
        qsort(L,low,pivot-1); //遞歸排序左邊
        qsort(L, pivot +1,high);  //遞歸排序右邊
    }
    return 0;
}

所有的算法都測試通過,如果出現問題可聯繫筆者,或者換個姿勢。。。。

注意:由於使用異或運算交換兩個元數的值得時候如果兩個元數相等那麼會出現交換失敗導致兩個數的值都爲0

例如:

int a,b;

a=b=5;

a=a^b;

b=a^b;

a=a^b;

結果b=a=0

經過測試除了直接插入排序要加條件判斷外其他幾種排序算法都可以不用加上條件判斷。

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