C語言——排序

排序

1.插入排序

(1).代碼實現
//插入排序  
void InsertSort(int array[], int size)
{
    for (int i=1;i<size;i++)
    {
        int end = i - 1;
        int key = array[i];
        //尋找插入位置
        while (end>=0&&array[end]>key)
        {
            array[end+1] = array[end];
            end--;
        }
        //插入元素
        array[end + 1] = key;
    }
}
(2).特性

​ a. 元素集合越接近有序,直接插入排序算法的時間效率越高 算法

​ b. 時間複雜度:O(N^2) 數組

​ c.空間複雜度:O(1),它是一種穩定的排序算法 markdown

​ d. 穩定性:穩定 ide

2.希爾排序

(1).代碼實現
//希爾排序
void ShellSort(int array[], int size)
{
    int gap = size;
    while (gap > 1)
    {
        gap = gap / 3 + 1;
        for (int i = gap; i < size; i++)
        {
            int end = i - gap;
            int key = array[i];
            while (end>=0&&array[end]>key)
            {
                array[end+gap] = array[end];
                end=end-gap;
            }
            array[end + gap] = key;
        }
    }
}
(2).特性

​ a. 希爾排序是對直接插入排序的優化 性能

​ b. 希爾排序的時間複雜度很差計算,須要進行推導,推導出來平均時間複雜度: O(N^1.3—N^2) 優化

​ c.穩定性:不穩定ui

3.選擇排序

(1).代碼實現
void swap(int arr1[], int arr2[])
{
    int temp = 0;
    temp = *arr1;
    *arr1 = *arr2;
    *arr2 = temp;
}
//選擇排序
void SelectSort(int array[], int size)
{
    for(int i=0;i<size-1;i++)//最後剩一個數就不用排了,所以是size-1
    {
        int maxPos = 0;
        //尋找最大值的位置
        for (int j = 1; j < size - i; j++)
        {
            if (array[j] > array[maxPos])
            {
                maxPos = j;
            }
        }
        //將最大值放在數組最後
        if (maxPos != size - 1 - i)
        {
            swap(&array[maxPos], &array[size - 1 - i]);
        }
    }
}
//選擇排序另外一種方法
void SelectSortOP(int array[], int size)
{
    int begin = 0,end = size - 1;
    while (begin < end)
    {
        //找最大最小元素位置
        int maxPos = begin;
        int minPos = begin;
        int index = begin + 1;
        while (index <= end)
        {
            if (array[index] > array[maxPos])
            {
                maxPos = index;
            }
            if (array[index] < array[minPos])
            {
                minPos = index;
            }
            index++;
        }
        if (maxPos != end)
        {
            swap(&array[maxPos], &array[end]);
        }
        //若是最小的元素恰巧在end處,則上面操做會改變最小元素的位置
        if (minPos == end)
        {
            minPos = maxPos;
        }
        if (minPos != begin)
        {
            swap(&array[minPos], &array[begin]);
        }
        begin++;
        end--;
    }
}
(2).特性

​ a.直接選擇排序思考很是好理解,可是效率不是很好。實際中不多使用 code

​ b.時間複雜度:O(N^2)排序

​ c.空間複雜度:O(1) 遞歸

​ d.穩定性:不穩定

4.堆排序

(1).代碼實現
void swap(int arr1[], int arr2[])
{
    int temp = 0;
    temp = *arr1;
    *arr1 = *arr2;
    *arr2 = temp;
}
//向下調整算法
void HeapAdjust(int array[], int size, int parent)
{
    //先標記左孩子,parent可能有左沒有右
    int child = parent * 2 + 1;
    while (child<size)
    {
        //找到左右孩子中較大的,用child標記
        if (child+1 < size && array[child] < array[child + 1])
        {
            child += 1;
        }
        //若是雙親結點小於較大的子結點,則交換
        if (array[parent] < array[child])
        {
            swap(&array[parent], &array[child]);
            parent = child;
            child = parent * 2 + 1;
        }
        else
        {
            return;
        }
    }

}
//堆排序
void HeapSort(int array[], int size)
{
    int end = size - 1;
    //建堆, 升序-->大堆    降序-->小堆
    //從倒數第一個非葉子結點到根結點一直向下調整
    for (int root = (end - 1) / 2; root >= 0; root--)
    {
        HeapAdjust(array, size, root);
    }
    //排序
    while(end)
    {
        swap(&array[0], &array[end]);
        HeapAdjust(array, end , 0);
        end--;
    }
}
(2).特性

​ a.堆排序使用堆來選數,效率就高了不少

​ b.時間複雜度:O(N*logN)

​ c.空間複雜度:O(1)

​ d.穩定性:不穩定

6.冒泡排序

(1).代碼實現
//冒泡排序
void BubbleSort(int array[], int size)
{
    for (int i = 0; i < size - 1; i++)
    {
        int flag=0;
        //相鄰兩個元素比較,不知足就交換
        for (int j = 0; j < size - i-1; j++)
        {
            if (array[j]>array[j+1])
            {
                flag=1;
                swap(&array[j] ,&array[j+1]);
            }   
        }
        if(!flag)//若是flag爲0,則沒有發生交換,則數組已經有序,就不用再比較了
        {
            return;
        }
    }
}
(2).特性

​ a.時間複雜度:O(N^2)

​ b.空間複雜度:O(1)

​ c.穩定性:穩定

7.計數排序

(1).代碼實現
//計數排序
void CountSort(int array[], int size)
{
    //1.找數據範圍
    int max = array[0];
    int min = array[0];
    int index = 0;
    for (int i = 0; i < size; i++)
    {
        if (array[i] > max)
        {
            max = array[i];
        }
        if (array[i] < min)
        {
            min = array[i];
        }
    }
    //2.申請空間
    int* count = (int*)calloc(max - min + 1, sizeof(int));
    if (NULL == count)
    {
        return NULL; 
    }
    //3.統計每一個元素出現次數
    for (int i = 0; i < size; i++)
    {
        count[array[i] - min]++;
    }
    //4.array數組排序
    for (int i=0;i<max-min+1;i++)
    {
        while (count[i]--)
        {
            array[index++] = i + min;
        }
    }
    free(count);
}
(2).特性

​ a. 計數排序在數據範圍集中時,效率很高,可是適用範圍及場景有限

​ b. 時間複雜度:O(MAX(N,範圍))

​ c. 空間複雜度:O(範圍)

​ d. 穩定性:穩定

8.快速排序

(1).代碼實現
//第一種:hoare法
int Partion1(int array[], int left, int right)
{
    int begin = left;
    int end = right - 1;
    int key = array[end];//基準值是最後一個元素
    while (begin < end)
    {
        while (begin<end&&array[begin] <= key) //保證有效區間
        {
            begin++;
        }
        while (begin < end&&array[end] >= key)   
        {
            end--;  
        }
        if (begin < end)
        {
            swap(&array[begin], &array[end]);
        }
    }
    if (begin!=right-1)
    {
        swap(&array[begin], &array[right - 1]);//將基準值放在數組中間
    }
    return begin;//返回基準值位置
}
//第二種:挖坑法   
int Partion2(int array[], int left, int right)
{
    int begin = left;
    int end = right - 1;
    int key = array[end];
    while (begin < end)
    {
        //begin從前日後找,找比基準值大的元素 
        while (begin < end&&array[begin] <= key)
        {
            begin++;
        }
        if (begin < end)
        {
            array[end] = array[begin];
            end--;
        }

        while (begin < end&&array[end] >= key)
        {
            end--;
        }
        if (begin < end)
        {
            array[begin] = array[end];
            begin++;
        }
    }
    array[begin] = key;
    return begin;
}
//第三種
int Partion3(int array[], int left, int right)
{
    int cur = left;
    int prev = cur-1;
    int key = array[right - 1];
    while (cur < right) 
    {
        if (array[cur] < key&&++prev != cur)
        {
            swap(&array[cur], &array[prev]);
        }
        cur++;
    }
    if (++prev != right - 1)//將基準值放在正確的位置
    {
        swap(&array[prev], &array[right-1]);
    }
    return prev;
}

void QuickSort(int array[], int left, int right)
{
    int div = 0;
    if (right - left <= 1)
    {
        return;
    }
    //找基準值對區間中的數據進行劃分,div表述劃分好等候基準值位置
    div = Partion3(array, left, right);
    //遞歸
    QuickSort(array, left, div);
    QuickSort(array, div+1, right);
}
(2).特性

​ a. 快速排序總體的綜合性能和使用場景都是比較好的,因此纔敢叫快速排序

​ b. 時間複雜度:O(N*logN)

​ c. 空間複雜度:O(logN)

​ d. 穩定性:不穩定

9.歸併排序

(1).代碼實現
//合併兩個有序數組
void MergeData(int array[], int left, int mid, int right, int temp[])
{
    int begin1 = left, end1 = mid;
    int begin2 = mid , end2 = right;
    int index = left;
    while (begin1 < end1 && begin2 < end2)
    {
        if (array[begin1] <= array[begin2])
        {
            temp[index++] = array[begin1++];
        }
        else
        {
            temp[index++] = array[begin2++];
        }
    }
    while (begin1<end1)
    {
        temp[index++] = array[begin1++];
    }
    while (begin2 < end2)
    {
        temp[index++] = array[begin2++];
    }
}
//歸併排序
void MergeSort(int array[], int left, int right, int temp[])
{
    if (right - left <= 1)
    {
        return;
    }
    int mid = left + ((right - left) / 2);

    MergeSort(array, left, mid, temp);
    MergeSort(array,mid , right, temp);
    MergeData(array, left, mid, right, temp);   
    memcpy(array + left, temp+left, sizeof(array[0])*(right - left));
}
(2).特性

​ a. 歸併的缺點在於須要O(N)的空間複雜度,歸併排序的思考更多的是解決在磁盤中的外排序問題。

​ b. 時間複雜度:O(N*logN)

​ c. 空間複雜度:O(N)

​ d. 穩定性:穩定

相關文章
相關標籤/搜索