c/c++再學習:排序算法了解
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],有序區為空;
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++再學習:排序算法了解