C語言-排序算法

在排序算法中關鍵步驟涉及到元素的比較和交換,讓無序的數據元素按照規定排列成有序的數據過程。

內排序——涉及數據量少,整個排序過程不需要外存便能完成。

外排序——涉及數據量大,不能一次性讀取到內存中,需要時從外部一部分一部分調用。

時間性能——關鍵性能差異體現在比較和交換的數量。

輔助存儲空間——在考慮排序的性能時,必要時可以“空間換時間”。

算法的複雜度——排序算法的複雜度影響着代碼的可讀性和維護性,過於複雜可能影響排序的性能。

選擇法

首先通過n-1次關鍵字比較,從n個記錄中找出關鍵字最小的記錄,將它與第一個記錄交換。

通過n-2次關鍵字比較,從n-1個記錄中找出關鍵字最小的記錄,將它與第二個記錄交換。

重複上述操作,直到n-i(i = 0,1,...,n-2),排序結束。

大白話:假設k = 0;0號元素爲初始最小值,通過循環所有元素,找到下一個最小的值,把其下標位置賦給k,直到找到最小值,最後交換0號位置元素與k位置元素的值。依次往後執行(k = 0,1,...,n-2);這裏爲什麼是n-2而不是n-1,因爲前n-2排好序之後,最後一位是不需要再進行比較的。

void Spaw(int *arr, int k, int i)
{
    int temp = arr[k];
    arr[k] = arr[i];
    arr[i] = temp;
}

void SelectSort(int *arr, int len)
{
    int i,j = 0;
    int k = 0;

    for (i = 0; i < len-1; i++)
    {
        k = i;
        for (j = i + 1; j < len; j++)
        {
            if (arr[j] < arr[k])
            {
                k = j;
            }
        }
        Spaw(arr, i, k);
    }
}

插入排序

排序過程:整個排序過程爲n-1趟插入,即先將序列中第1個記錄看成是一個有序子序列,然後從第2個記錄開始,逐個進行插入,直至整個序列有序

實質:對線性表執行n-1次插入操作,只是先要找到插入位置

大白話:假設0號元素爲一個有序序列,從1號元素開始,把1號元素賦值給臨時變量,再讓臨時變量同前面的有序序列逐項遞減比較,找到要插入的位置後,後面的有序元素依次往後位移給要插入的元素騰出位置,最後臨時變量插入對應位置組成新的有序序列。依次類推執行n-1次。

void IntertionSort(int *arr,int len)
{
    int i = 0;
    int j = 0;
    int k = i;
    int temp = 0;

    for (i = 1; i < len; i++)
    {
        k = i;
        temp = arr[k];
        for (j = k - 1; j >= 0; j--)
        {
            if (temp < arr[j])
            {
                arr[j+1] = arr[j];
                k = j;
            }
        }
        arr[k] = temp;
    }
}

冒泡排序

將第一個記錄的關鍵字與第二個記錄的關鍵字進行比較,如果爲升序array[0]>array[1],然後比較第二個記錄的關鍵字和第三個記錄的關鍵字;以此類推,直到第n-1個關鍵字與第n個關鍵字比較爲止,這樣進行了一趟之後把關鍵字最大的記錄放到了最後一個位置上。

在對前n-1個記錄進行第二趟冒泡排序,讓其中最大的關鍵字放在n-1的位置上。

重複上述過程,直到沒有交換記錄的操作爲止。

大白話:假設有n個元素,第一趟從0號元素開始與1號位置元素比較,如果0號位置元素大於1號位置,則交換位置,繼續1號位置與2號位置元素比較,這樣依次比較完,會把其中最大的元素放到最後一位。這樣只是進行了一趟操作。

因爲最後一個元素已經是最大的了,下一趟就不需要對它進行比較,因此我們只需要對前n-1個元素進行比較,這是第二趟。這樣下來總共執行n趟,對前n-i(i = 0,1,...,n-1)個元素進行比較,就排好序了。

void Spaw(int *arr, int i, int j)
{
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

void PopoSort(int *array,int len)
{
    int i = 0;
    int	j = 0;
    int exchange = 1;
    for (i = 0; i < len && exchange; i++)
    {
        exchange = 0;
        for (j = 0; j < len - 1 - i; j++)
        {
            if (array[j] > array[j + 1])
            {
                Spaw(array, j, j + 1);
                exchange = 1;
            }
        }
    }
}

這裏增加exchange標誌位,意思是判斷是否需要執行下趟交換,因爲一般無序序列不一定正正好好需要執行n趟纔可以變成有序序列,有可能第6趟就會變成有序序列,因此後面的幾趟就不需要在比較了,提高執行效率。

希爾排序

排序過程:先取一個正整數d1<n,把所有相隔d1的記錄放一組,組內進行直接插入排序;然後取d2<d1,重複上述分組和排序操作;直至di=1,即所有記錄放進一個組中排序爲止。

大白話:選取一個間隔數,把所有元素按照間隔分組,分組之後按照插入排序進行組內排序;然後選取新的間隔數,重複上述分組操作和插入排序;直到間隔數=1。

間隔值 :gap = gap / 3 + 1 (通過大量數據實驗得來的,直接這麼用)

void ShellSort(int *array, int len)
{
    int i = 0;
    int j = 0;
    int k = 0;
    int temp = 0;
    int gap = len;

    do
    {
        gap = gap / 3 + 1;
        for (i = gap; i < len; i+=gap)
        {
            k = i;
            temp = array[k];
            for (j = k - gap; j >= 0; j-=gap)
            {
                if (temp < array[j])
                {
                    array[j + gap] = array[j];
                    k = j;
                }
            }
            array[k] = temp;
        }
    } while (gap > 1);
}

快速排序

快速排序是對冒泡排序的一種改進。它的基本思想是:

通過一躺排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,基準數據排在這兩個子序列的中間;

然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。

void Spaw(int *arr, int i, int j)
{
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

int  Partition(int *array,int low,int hight)
{
    int pv = array[low];

    while (low < hight)
    {
        while (low<hight && (array[hight] >= pv))
        {
            hight--;
        }
        Spaw(array, low, hight);

        while (low < hight && (array[low] <= pv))
        {
            low++;
        }
        Spaw(array, low, hight);
    }
    return low;
}

void QSort(int *array, int low, int hight)
{
    if (low < hight)
    {
        int pv = Partition(array, low, hight);

        QSort(array, low, pv-1);
        QSort(array, pv + 1, hight);
    }
}

void QuickSort(int *array, int len)
{
    QSort(array, 0, len - 1);
}

歸併排序

歸併排序採用了分治策略, 將一個無序序列通過向下分解,分解到單個元素時,再通過相互比較重新組合成局部有序序列,最後將組合好的兩個局部有序序列合併到一起組成一個完整的有序序列的過程。

void Merger(int *array1, int *array2, int low, int mid, int high)
{
    int i = low;
    int j = mid+1;
    int k = low;

    while ((i <= mid) && (j <= high))
    {
        if (array1[i] < array1[j])
        {
            array2[k++] = array1[i++];
        }
        else
        {
            array2[k++] = array1[j++];
        }
    }
    while (i == mid)
    {
        array2[k++] = array1[i++];
    }

    while (j <= high)
    {
        array2[k++] = array1[j++];
    }
}

void MSort(int *array1, int *array2, int low, int high,int max)
{
    if (low == high)
    {
        array2[low] = array1[low];
    }
    else
    {
        int mid = (low + high) / 2;
        int *space = (int *)malloc(sizeof(int)*max);

        if (space != NULL)
        {
            MSort(array1, space, low, mid, max);
            MSort(array1, space, mid+1, high, max);
            Merger(space, array2, low, mid, high);
        }
        free(space);
    }
}

void MergerSort(int *array,int len)
{
    MSort(array, array, 0, len - 1, len);
    printf("\n");
}

還有其他排序算法,一般實際項目中使用,選擇法、插入法、冒泡法的比重較大,主要是學習思想,思想很重要,如果上面的還是看的不怎麼太懂,有點似懂非懂的推薦去十大經典排序算法(動圖演示),這裏涵蓋了大部分的排序算法,帶有動圖,更直觀具體。

 

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