1. 程式人生 > >c/c++再學習:排序算法了解

c/c++再學習:排序算法了解

_id 選擇 vid 元素 chan 復雜度 數組 ear 最終

1.冒泡排序

冒泡排序是一種簡單的排序算法。它重復地走訪過要排序的數列,一次比較兩個元素,如果它們的順序錯誤就把它們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端。

算法描述

1.比較相鄰的元素。如果第一個比第二個大,就交換它們兩個;
2.對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對,這樣在最後的元素應該會是最大的數;
3.針對所有的元素重復以上的步驟,除了最後一個;
4.重復步驟1~3,直到排序完成。

代碼實現

void bubble_sort(vector<int>& nums)
{
    int temp = 0;
    int isChange = 0;
    int len = nums.size();

    for (int i = 0; i < len - 1; i++)
    {
        isChange = 0;

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

        /* 如果沒有數據交換,則數據已有序 */
        if (isChange)
        {
            break;
        }
    }
}

2.選擇排序

選擇排序(Selection-sort)是一種簡單直觀的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然後,再從剩余未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。
表現最穩定的排序算法之一,因為無論什麽數據進去都是O(n2)的時間復雜度,所以用到它的時候,數據規模越小越好。唯一的好處可能就是不占用額外的內存空間了吧。理論上講,選擇排序可能也是平時排序一般人想到的最多的排序方法了吧。

算法描述

n個記錄的直接選擇排序可經過n-1趟直接選擇排序得到有序結果。具體算法描述如下:
1.初始狀態:無序區為R[1..n],有序區為空;

2.第i趟排序(i=1,2,3…n-1)開始時,當前有序區和無序區分別為R[1..i-1]和R(i..n)。該趟排序從當前無序區中-選出關鍵字最小的記錄 R[k],將它與無序區的第1個記錄R交換,使R[1..i]和R[i+1..n)分別變為記錄個數增加1個的新有序區和記錄個數減少1個的新無序區;
3.n-1趟結束,數組有序化了。

代碼實現

void select_sort(vector<int>& nums)
{
    int len = nums.size();
    int select_id = 0;
    int temp = 0;

    for (int i = 0; i < len - 1; i++)
    {
        select_id = i;
        for (int j = i + 1; j < len; j++)
        {
            if (nums[j] < nums[select_id])
            {
                select_id = j;
            }
        }
        temp = nums[i];
        nums[i] = nums[select_id];
        nums[select_id] = temp;
    }
}

3.插入排序

插入排序(Insertion-Sort)的算法描述是一種簡單直觀的排序算法。它的工作原理是通過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。
插入排序在實現上,通常采用in-place排序(即只需用到O(1)的額外空間的排序),因而在從後向前掃描過程中,需要反復把已排序元素逐步向後挪位,為最新元素提供插入空間

算法描述

一般來說,插入排序都采用in-place在數組上實現。具體算法描述如下:
1.從第一個元素開始,該元素可以認為已經被排序;
2.取出下一個元素,在已經排序的元素序列中從後向前掃描;
3.如果該元素(已排序)大於新元素,將該元素移到下一位置;
4.重復步驟3,直到找到已排序的元素小於或者等於新元素的位置;
5.將新元素插入到該位置後;
6.重復步驟2~5。

void insert_sort(vector<int>& nums)
{
    int len = nums.size();
    int now_id = 0;
    int now_num = 0;

    for (int i = 1; i < len; i++)
    {
        now_id = i - 1;
        now_num = nums[i];

        while ((now_id >= 0) && (nums[now_id] > now_num))
        {
            nums[now_id + 1] = nums[now_id];
            now_id--;
        }
        nums[now_id + 1] = now_num;
    }
}

4.計數排序

計數排序不是基於比較的排序算法,其核心在於將輸入的數據值轉化為鍵存儲在額外開辟的數組空間中。 作為一種線性時間復雜度的排序,計數排序要求輸入的數據必須是有確定範圍的整數。
計數排序是一個穩定的排序算法。當輸入的元素是 n 個 0到 k 之間的整數時,時間復雜度是O(n+k),空間復雜度也是O(n+k),其排序速度快於任何比較排序算法。當k不是很大並且序列比較集中時,計數排序是一個很有效的排序算法。

算法描述

1.找出待排序的數組中最大和最小的元素;
2.統計數組中每個值為i的元素出現的次數,存入數組C的第i項;
3.對所有的計數累加(從C中的第一個元素開始,每一項和前一項相加);
4.反向填充目標數組:將每個元素i放在新數組的第C(i)項,每放一個元素就將C(i)減去1。

void count_sort(vector<int>& nums, int max)
{
    vector<int> countpool(max);
    int len = nums.size();
    int max_value = 0;

    for (int i = 0; i < len; i++)
    {
        countpool[nums[i]]++;

        if (max_value < nums[i])
        {
            max_value = nums[i];
        }
    }

    nums.clear();

    for (int i = 0; i < max_value; i++)
    {
        if (countpool[i] != 0)
        {
            for (int j = 0; j < countpool[0]; j++)
            {
                nums.push_back(i);
            }
        }
    }
}

5.歸並排序

歸並排序是建立在歸並操作上的一種有效的排序算法。該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合並,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合並成一個有序表,稱為2-路歸並。

算法描述

1.把長度為n的輸入序列分成兩個長度為n/2的子序列;
2.對這兩個子序列分別采用歸並排序;
3.將兩個排序好的子序列合並成一個最終的排序序列。

vector<int> merge_list(vector<int>& num1, vector<int>& num2)
{
    int len1 = num1.size();
    int len2 = num2.size();
    int len = len1 + len2;

    vector<int> rst(len);
    int idx1 = 0, idx2 = 0;

    for (int i = 0; i < len; i++)
    {
        if (idx1 == len1)
        {
            rst[i] = num2[idx2];
            idx2++;
        }
        else if (idx2 == len2)
        {
            rst[i] = num1[idx1];
            idx1++;
        }
        else
        {
            if (num1[idx1] < num2[idx2])
            {
                rst[i] = num1[idx1];
                idx1++;
            }
            else
            {
                rst[i] = num2[idx2];
                idx2++;
            }
        }
    }
    
    return rst;
}

void merge_sort(vector<int>& nums)
{
    int len = nums.size();
    int mid = (len + 1) / 2;

    if (len == 1)
    {
        return;
    }

    if (len == 2)
    {
        if (nums[0] > nums[1])
        {
            int temp = nums[0];
            nums[0] = nums[1];
            nums[1] = temp;
        }
        return;
    }

    vector<int> num1(nums.begin(), nums.begin() + mid);
    vector<int> num2(nums.begin() + mid, nums.end());
    merge_sort(num1);
    merge_sort(num2);
    nums = merge_list(num1, num2);  

    return;
}

c/c++再學習:排序算法了解