7種常見排序演算法的c++實現
阿新 • • 發佈:2019-01-30
今天心血來潮複習了一下基本的排序演算法,實現了一下,就順便發上來咯。。
在程式碼裡做了註釋了-。-
也就不多說了,直接上程式碼吧。。
// order_algorithm.cpp: 定義控制檯應用程式的入口點。 //author: netbin #include "stdafx.h" #include "iostream" #include <stdio.h> #include <stdlib.h> #include <time.h> #include <vector> //指定陣列的大小 const int max_size = 50; using namespace::std; //插入排序 //時間複雜度O(n^2),空間複雜度O(n),是一個穩定演算法; //假定該陣列有有序區和無序區:則不斷地將無序區的第一個元素取出放置於有序區的正確位置; //從i的位置開始,從後往前依次比較,如果nums[j]小於nums[i],則交換二者的位置; //優化:我們可以知道插入排序的前部是有序的,則如果nums[j]>=nums[i],則表明,i之前的所有元素 //都符合這個特性,那麼也就不需要再繼續比較了; void insert_sort(vector<int> &nums) { for (int i = 0; i < nums.size(); i++) { for (int j = i; j > 0; j--) { if (nums[j] < nums[j-1]) { int temp = nums[j]; nums[j] = nums[j-1]; nums[j-1] = temp; } else break; } } } //希爾排序 //時間複雜度 O(n^1.3),準確地說希爾排序的時間複雜度與增量序列有關 //它是一個不穩定的演算法:因為可能數處於不同的組別內 //希爾排序是對插入排序的優化 void shell_sort(vector<int> &nums) { //gap是步長,步長每次減半; //這裡最後的gap/=2要注意。。剛開始寫成了gap/2,沒有等號,所有gap沒作用,會造成死迴圈 for (int gap = nums.size() / 2; gap > 0; gap /= 2) { //從gap位置開始,相當於直接插入排序的第2個元素開始; for (int i = gap; i < nums.size(); i++) { int temp = nums[i]; //相當於插入排序的j = i; //同組內的無序陣列的第一個元素的前一個數組。。。好像挺繞的-。- int j = i - gap; //同組內元素的比較 for (; j >= 0 && nums[j] > temp; j -= gap) { //這裡需要注意的是j的值變化的情況; //第一次的j+gap=i #-。- //其實也就是把大於nums[i]的值都後移 nums[j + gap] = nums[j]; } //這裡需要注意的是在上面的for迴圈中,最後還會執行一次j-=gap; //所以這裡的j+gap會等於上面結束時j的值 nums[j + gap] = temp; } } } //氣泡排序 //時間複雜度: O(n^2),空間複雜度:O(n) //穩定性:是一個穩定演算法 void bubble_sort(vector<int> &nums) { for (int i = 0; i < nums.size()-1; i++) { for (int j = 0; j < nums.size() - i - 1; j++) { if (nums[j] > nums[j + 1]) { int temp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = temp; } } } } //選擇排序:從無序陣列中選出最小(最大)的數,放到亂序陣列的頭部 //優化:同時選出最大和最小 void select_sort(vector<int> &nums) { for (int i = 0; i < nums.size(); i++) { int min = i; for (int j = i+1; j < nums.size(); j++) { if (nums[j] < nums[min]) { min = j; } } int temp = nums[i]; nums[i] = nums[min]; nums[min] = temp; } } //快速排序 void quick_sort(vector<int> &nums, int b, int e, vector<int> &temp) { int m = (b + e) / 2; //判斷是否只有一個元素 if (m != b) { int lb = b; int rb = e - 1; for (int i = b; i < e; i++) { //如果當前位置等於選中元素的位置,則跳過此次迴圈,進入下一次迴圈; if (i == m) { continue; } //如果當前位置元素的值小於選中的元素,則新增到臨時陣列的左邊 if (nums[i] < nums[m]) { temp[lb++] = nums[i]; }else{ //如果當前位置元素的值大於選中的元素,則新增到臨時陣列的右邊 temp[rb--] = nums[i]; } } //迴圈結束時,temp陣列中lb指向的位置就是在nums陣列中選中元素所在的位置 temp[lb] = nums[m]; //將temp陣列複製到nums陣列中 for (int i = b; i < e; i++) { nums[i] = temp[i]; } //遞迴呼叫 quick_sort(nums,b,lb,temp); quick_sort(nums, lb + 1, e, temp); } } //歸併排序 //時間複雜度:O(nlogn) //歸併排序是將元素分割為一個一個的小組,然後對每個小組再進行排序,然後再合併陣列,分而治之的思想 //這種排序的方式與希爾排序的基本思想類似 void merge_array(vector<int> &nums, int b, int m, int e, vector<int> &temp) { int lb = b; int rb = m; int tb = b; //在合併兩個陣列時,如果左邊陣列和右邊的陣列都未空 while (lb != m && rb != e) { if (nums[lb] < nums[rb]) { temp[tb++] = nums[lb++]; } else { temp[tb++] = nums[rb++]; } } //如果右邊的已經空了,而左邊沒空,就將左邊陣列的剩餘所有元素全部入陣列 while (lb < m) temp[tb++] = nums[lb++]; //如果左邊的已經空了,而右邊沒空,就將右邊陣列的剩餘所有元素全部入陣列 while (rb < m) temp[tb++] = nums[rb++]; //將此次合併存入臨時陣列的元素全部複製到nums陣列中 for (int i = b; i < e; i++) { nums[i] = temp[i]; } } void merge_sort(vector<int> &nums, int b, int e, vector<int> &temp) { int m = (b + e) / 2; if (m != b) { //將元素分割成一個一個的 merge_sort(nums, b, m, temp); merge_sort(nums, m, e, temp); //然後對這些元素組成的小組進行遞迴合併; merge_array(nums, b, m, e, temp); } } //堆排序 //建堆以及調整堆 void max_heapofy(vector<int> &nums, int beg, int end) { int curr = beg; int child = curr * 2 + 1; //不是最後一個結點 while (child < end) { //判斷子結點中哪個更大,用最大子節點來和父節點比較就可以了 if (child + 1 < end && nums[child + 1] > nums[child]) child++; //如果父節點小於最大子節點,就交換值 if (nums[curr] < nums[child]) { int temp = nums[curr]; nums[curr] = nums[child]; nums[child] = temp; //調整之後可能會導致下面的子樹不是最大堆,故而要重新調整 curr = child; child = curr * 2 + 1; } else //如果不需要調整,則結束此次迴圈 break; } } void heap_sort(vector<int> &nums) { int n = nums.size(); //建堆 for (int i = n / 2 - 1; i >= 0; i--) { max_heapofy(nums,i,nums.size()); } //將堆頂(最大元素)和陣列的最後一個值交換,然後再調整堆 for (int i = n - 1; i > 0; i--) { int temp = nums[i]; nums[i] = nums[0]; nums[0] = temp; max_heapofy(nums,0,i); } } //初始化vector陣列函式 void init_vec(vector<int> &nums) { srand((unsigned)time(NULL)); for (int i = 0; i < max_size; i++) { nums.push_back(rand()); } } //輸出結果,並清空vector void print_clear(vector<int> &nums) { for (int i = 0; i < max_size; i++) { cout << nums[i] << " "; } cout << endl; nums.clear(); } int main() { vector<int> nums; //插入排序:測試結果成功 init_vec(nums); time_t start = clock(); insert_sort(nums); time_t end = clock(); cout << "插入排序測試結果:" << endl; print_clear(nums); printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC); //希爾排序:測試結果成功 init_vec(nums); start = clock(); shell_sort(nums); end = clock(); cout << "希爾排序測試結果:" << endl; print_clear(nums); printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC); //氣泡排序:成功 init_vec(nums); start = clock(); bubble_sort(nums); end = clock(); cout << "氣泡排序測試結果:" << endl; print_clear(nums); printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC); //選擇排序:成功 init_vec(nums); start = clock(); select_sort(nums); end = clock(); cout << "選擇排序測試結果:" << endl; print_clear(nums); printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC); //快速排序:成功 vector<int> temp(max_size); init_vec(nums); start = clock(); quick_sort(nums,0,nums.size(),temp); end = clock(); temp.clear(); cout << "快速排序測試結果:" << endl; print_clear(nums); printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC); //歸併排序:失敗-。- 陣列下表越界 #因為在快速排序時清空了temp陣列,所以導致了這次的陣列越界 init_vec(temp); init_vec(nums); start = clock(); merge_sort(nums, 0, nums.size(), temp); end = clock(); temp.clear(); cout << "歸併排序測試結果:" << endl; print_clear(nums); printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC); //堆排序:失敗-。-最後一個元素沒有排好序 //修復了 #-。- init_vec(nums); start = clock(); heap_sort(nums); end = clock(); temp.clear(); cout << "堆排序測試結果:" << endl; print_clear(nums); printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC); system("pause"); return 0; }