【C++】排序算法小结
1、计数排序
如果给定上下界,并且区间不大的话,最适用。
比如对于英文字母数组进行排序。
时间复杂度O(n),空间复杂度O(n)
void countSort(int A[], int n, int low, int high) { int size = high-low+1; vector<int> count(size, 0); //count[i] represents low+i appears count[i] times in A for(int i = 0; i < n; i ++) { count[A[i]-low] ++; } int ind = 0; for(int i = 0; i < size; i ++) { while(count[i]) { A[ind ++] = low+i; count[i] --; } } }
2、冒泡排序(基础版)
最基础的排序算法,相邻元素两两比较并交换。
时间复杂度O(n2),空间复杂度O(1)。稳定排序。
void bubbleSort(int A[], int n) { for(int i = 0; i < n; i ++) { for(int j = 0; j < n-i-1; j ++) { if(A[j] > A[j+1]) swap(A[j], A[j+1]); } } }
3、冒泡排序(加速版)
如果中间结果已经有序,即一次遍历过程中不存在需要交换的相邻元素,则结束返回。
时间复杂度O(n2),空间复杂度O(1)。稳定排序。
void bubbleSortAc(int A[], int n) { bool exchange; for(int i = 0; i < n; i ++) { exchange = false; for(int j = 0; j < n-i-1; j ++) { if(A[j] > A[j+1]) { exchange = true; swap(A[j], A[j+1]); } } if(exchange == false) return; } }
4、选择排序
遍历过程中选择最大元素,与末尾元素交换。
时间复杂度O(n2),空间复杂度O(1)。不稳定排序。
void selectSort(int A[], int n) { for(int i = n-1; i >= 0; i --) { int max = A[0]; int ind = 0; for(int j = 1; j <= i; j ++) { if(A[j] > max) { max = A[j]; ind = j; } } if(ind != i) swap(A[ind], A[i]); } }
5、插入排序
将当前元素插入局部有序的数组中。
时间复杂度O(n2),空间复杂度O(1)。稳定排序。
void insertSort(int A[], int n) { for(int i = 1; i < n; i ++) {//insert A[i] into the right place int cur = i-1; int value = A[i]; while(cur >= 0 && A[cur] > value) { A[cur+1] = A[cur]; cur --; } A[cur+1] = value; } }
6、快速排序
最常用的排序,使用pivot将数组分成大小两段,递归完成排序。
时间复杂度平均O(nlogn),最坏情况(已排序或逆序)O(n2),空间复杂度O(1)。不稳定排序。
int partition(int A[], int low, int high) { int pivot = A[low]; int vacant = low; while(low < high) { while(high > low && A[high] >= pivot) high --; //A[high] < pivot if(high > low) { A[vacant] = A[high]; vacant = high; } else break; while(low < high && A[low] <= pivot) low ++; //A[low] > pivot if(low < high) { A[vacant] = A[low]; vacant = low; } else break; } A[low] = pivot; return low; } void quickSort(int A[], int low, int high) { if(low < high) { int pos = partition(A, low, high); quickSort(A, low, pos-1); quickSort(A, pos+1, high); } }
7、堆排序
分为建堆与交换两个过程。
通常用于数组中寻找最大/小的k个元素。
时间复杂度O(nlogn),空间复杂度O(1)。不稳定排序。
void siftDown(int A[], int start, int end) { int temp = A[start]; int i = start; int j = 2*i + 1; //left child while(j <= end) { if(j+1 <= end && A[j]<A[j+1]) j = j+1; //choose the bigger if(temp >= A[j]) break; else { A[i] = A[j]; i = j; j = 2*i + 1; } } A[i] = temp; } void heapSort(int A[], int n) { //build max heap for(int i = (n-2)/2; i >= 0; i --) siftDown(A, i, n-1); //sort for(int i = n-1; i >= 0; i --) { swap(A[0], A[i]); siftDown(A, 0, i-1); //not include the i_th node } }
8、归并排序
分为局部排序与有序归并。
通常用于内存不足,需要与硬盘交互的排序。
时间复杂度O(nlogn),空间复杂度O(n)。稳定排序。
void merge(int A[], int start, int mid, int end) { int size1 = mid-start+1; int* L = new int[size1]; for(int i = 0; i < size1; i ++) L[i] = A[start+i]; int size2 = end-mid; int* R = new int[size2]; for(int i = 0; i < size2; i ++) R[i] = A[mid+1+i]; int i = 0; int j = 0; int ind = start; while(i < size1 && j < size2) { if(L[i] <= R[j]) { A[ind] = L[i]; ind ++; i ++; } else { A[ind] = R[j]; ind ++; j ++; } } while(i < size1) { A[ind] = L[i]; ind ++; i ++; } while(j < size2) { A[ind] = R[j]; ind ++; j ++; } } void mergeSort(int A[], int start, int end) { if(start < end) { int mid = (start+end)/2; mergeSort(A, start, mid); mergeSort(A, mid+1, end); merge(A, start, mid, end); } }