在C++和數據結構的學習中,我學到了很多種排序方法。
下面我簡單列出這些排序算法的C++實現方法。還有很多不成熟的地方,以後會及時改正!!!
#include<stack> #include<assert.h> //直接插入排序 void InsertSort(int* a,size_t size) { assert(a); for (int i = 0; i < size - 1; ++i) { //進入for循環,tmp保存end後一個位置的值 int end = i; int tmp = a[end + 1]; //end之前的值所有比tmp大的都向後挪 while (end>=0 && a[end]>tmp) { //將end位置的值向後挪一個位置 a[end + 1] = a[end]; --end; } a[end + 1] = tmp; } } //打印數組 void PrintArray(int* a,size_t size) { for (int i = 0; i < size; ++i) { cout << a[i] << " "; } cout << endl; } //希爾排序 //原理類似於插入排序,把數組分爲不同組,每兩個元素之間有一定的間隔,提高了效率 void ShellSort(int* a,size_t size) { assert(a); int gap = size; while (gap > 1) { gap = gap/3+1; //元素間隔 for (int i = 0; i < size-gap; ++i) { int end = i; int tmp = a[end + gap]; while (end >= 0 && a[end] > tmp) { a[end + gap] = a[end]; end -= gap; } a[end + gap] = tmp; } } } //堆排序 void AdjustDown(int* a, size_t size, size_t parent) { int child = parent * 2 + 1; while (child < size) { //child指向左子樹,若存在右子樹且大於左子樹,則child指向右子樹 if ((child+1<size) && (a[child]<a[child+1])) { ++child; } //孩子節點大於父節點,就交換,同時更新父節點和子節點 if (a[child] > a[parent]) { swap(a[parent],a[child] ); parent = child; child = parent * 2 + 1; } //已經爲有序狀態 else { break; } } } void HeapSort(int* a, size_t size) { assert(a); //建堆(大堆) for (int i=(size-2)/2; i >= 0; --i) { AdjustDown(a, size, i); } //調整 for (int i = 0; i < size-i-1; ++i) { swap(a[0], a[size-i-1]); AdjustDown(a, size-i-1, 0); } } //單趟排序 int PartSort1(int* a, int left, int right) { //以最後一個值爲key int key = a[right]; int begin = left; int end = right; while (begin < end) { //begin從前往後找到大與key的值,則停止 while (begin<end && a[begin]<key) { ++begin; } //end從後往前找到小於key的值,則停止 while (begin<end && a[end]>key) { --end; } //將大於key的值換到後面,將小於key的值換到前面 if (begin < end) { swap(a[begin], a[end]); } } //解決只有兩個元素時出現的bug if (a[begin]>a[right]) { swap(a[begin], a[right]); return begin; } else { return right; } } //挖坑法 int PartSort2(int* a, int left, int right) { int key = a[right]; while (left < right) { //找到left的值大於key,停止,否則向後走 while (left < right && a[left] <= key) { ++left; } //此時將left的值填到剛纔挖走的right上 if (left < right) { a[right] = a[left]; } //找到right的值小於key,停止,否則向前走 while (left < right && a[right] >= key) { --right; } //此時將right的值填到剛纔挖走的left上 if (left < right) { a[left] = a[right]; } } a[left] = key; return left; } //三數取中間 int GetMidIndex(int* a, int left, int right) { int mid = left + (right - left) / 2; if (a[mid] < a[right]) { //a[left] a[mid] a[right] if (a[left] < a[mid]) { return mid; } //a[mid] a[right] a[left] if (a[right] < a[left]) { return right; } //a[mid] a[left] a[right] else { return left; } } else { //a[right] a[mid] a[left] if (a[mid] < a[left]) { return mid; } //a[left] a[right] a[mid] if (a[left] < a[right]) { return right; } //a[right] a[left] a[mid] else { return left; } } } //優化---解決快排基本有序時效率太低問題 int PartSort3(int* a, int left, int right) { int midIndex = GetMidIndex(a, left, right);//得到中間值 int key = a[right]; int prev = left - 1; int cur = left; while (cur < right) { //cur探路,找小 2, 5, 7, 1, 4, 8, 0, 9, 6, 3 //prev找大 2, 1, 0, 3, 4, 8, 7, 9, 6, 5 if (a[cur] < key && ++prev != cur) { swap(a[cur], a[prev]); } ++cur; } //將key放在剛纔prev的下一個位置 swap(a[++prev], a[right]); return prev; } //快速排序 void QuickSort(int* a, int left, int right) { assert(a); if (left >= right) { return; } //數組中元素個數小於13,用插入排序效率更高 if (left - right < 13) { InsertSort(a, right-left+1); } //快排遞歸 else { int div = PartSort3(a, left, right); //遞歸排序,解決每一個子問題 QuickSort(a, left, div - 1); QuickSort(a, div + 1, right); } } //選擇排序 void SelectSort(int* a, int size) { int left = 0; int right = size - 1; while (left < right) { //[left,right] 閉區間 for (int i = left; i <= right; ++i) { if (a[i] < a[left]) { swap(a[i], a[left]); } if (a[i]>a[right]) { swap(a[i], a[right]); } } //區間逐漸向中間收攏,直到left和right相遇 ++left; --right; } } //非遞歸快速排序 void QuickSort_NonR(int* a, int left, int right) { assert(a); stack<int> s; if (left < right) { //得到中間點 int mid = PartSort3(a, left, right); //左半部分 if (left < mid - 1) { s.push(left); s.push(mid - 1); } //右半部分 if (mid + 1 < right) { s.push(mid + 1); s.push(right); } while (!s.empty()) { //每部分先push的是左,後push的右 //取時先得到每部分的右,再是左 int r = s.top(); s.pop(); //棧中取出數,需要pop一下 int l = s.top(); s.pop(); //給當前的小數組單趟排序,並且得到中間點 mid = PartSort3(a, l, r); if (l < mid - 1) { s.push(l); s.push(mid - 1); } if (mid + 1 < r) { s.push(mid + 1); s.push(r); } } } } //合併每兩個排好序的小組元素 void _Merge(int* a, int* tmp, int begin, int mid, int end) { int index = begin; int i = begin; int j = mid + 1; while (i <= mid && j <= end) { //先排小的 if (a[i] < a[j]) { tmp[index++] = a[i++]; } else { tmp[index++] = a[j++]; } } //剩餘數據 while (i <= mid) { tmp[index++] = a[i++]; } while (j <= end) { tmp[index++] = a[j++]; } //將tmp中數據複製到a中 for (int i = 0; i < index; i++) { a[i] = tmp[i]; } } //遞歸合併 void _MergeSort(int* a, int* tmp, int left, int right) { if (a == NULL || left >= right) { return; } int mid = left + (right - left) / 2; //每次遞歸進行找數組的左半部分 _MergeSort(a, tmp, left, mid); //每次遞歸進行找數組的右半部分 _MergeSort(a, tmp, mid + 1, right); //將得到的左右兩部分進行合併 _Merge(a, tmp, left, mid, right); } //歸併排序 void MergeSort(int* a, size_t size) { assert(a); //新建一塊size大小的空間 int* tmp = new int[size]; _MergeSort(a, tmp, 0, size - 1); delete[] tmp; } //計數排序 void CountSort(int* a, size_t size) { assert(a); int min = a[0]; int max = a[0]; for (size_t i = 0; i < size; ++i) { //找到最小值 if (a[i] < min) { min = a[i]; } //找到最大值 if (a[i] > max) { max = a[i]; } } int range = max - min + 1; //計數範圍 int* count = new int[range];//計數區間 memset(count, 0, sizeof(int)*range); for (size_t i = 0; i < size; ++i) { //統計每個元素出現的次數,放在對應位置上 //已有順序 count[a[i] - min]++; } size_t index = 0; for (int i = 0; i < range; ++i) { //可能有重複數據 while (count[i]--) { //此時在range範圍中,下標即爲需存儲的值 a[index++] = i + min; } } } //獲取最大基數 int GetMaxRadix(int* a, size_t size) { int radix = 1; int max = 10; for (size_t i = 0; i < size; ++i) { while (a[i] > max) { max *= 10; ++radix; } } return radix; } //基數排序 void LSDSort(int* a, size_t size) { assert(a); int maxRadix = GetMaxRadix(a, size); int count[10] = { 0 };//計數器 int start[10] = { 0 };//收集器 int* bucket = new int[size];//創建size個桶 int radix = 1;//基數至少爲一 for (int i = 1; i <= maxRadix; ++i)//進行maxRadix次排序 { memset(count, 0, sizeof(int)* 10);//初始化計數器 for (size_t i = 0; i < size; ++i) { int num = (a[i] / radix) % 10;//計算數據在計數器中的位置 count[num]++;//統計每個桶中的數據個數 } size_t index = 1; start[0] = 0; while (index < 10) { start[index] = start[index - 1] + count[index - 1];//收集 ++index; } for (size_t i = 0; i < size; ++i) { int num = (a[i] / radix) % 10; bucket[start[num]++] = a[i];//按照start中位置信息將數組數據依次存入桶中 } radix *= 10; memcpy(a, bucket, sizeof(int)*size);//將桶中內容拷貝到a中 } delete[] bucket; }