原理请参考《算法导论》
一、插入式排序算法实现:
void insertion_sort(int *A, int length) { int i, key; for (int j = 1; j < length; j++) {//从第二个开始判断,保证前面有序 key = A[j]; i = j - 1; while (i >= 0 && A[i] > key) { A[i + 1] = A[i]; i--; } A[i + 1] = key;//插入 } }
二、递归实现分治,merge函数实现合并算法实现:
void merge(int *A, int p, int q, int r) {//q属于[q, r] //分治保证L, R数组是有序的 int n1, n2, *L, *R, i, j; n1 = q - p + 1;//[p, q] n2 = r - q;//(q, r] L = new int[n1]; R = new int[n2]; for (i = 0; i < n1; i++) L[i] = A[p + i]; for (j = 0; j < n2; j++) R[j] = A[q + 1 + j]; i = j = 0; for (int k = p; k <= r; k++) { if (j == n2)//任意一边选完了,直接进去 A[k] = L[i++]; else if (i == n1) A[k] = R[j++]; else { if (L[i] < R[j]) A[k] = L[i++]; else A[k] = R[j++]; } } delete[] L; delete[] R; }
void merge_sort(int *A, int p, int r) {//p=0, r=n-1 if (p < r) { //递归实现分治,和二叉树一样,p<r自动实现过滤没有用的节点 merge_sort(A, p, (p + r) / 2); merge_sort(A, (p + r) / 2 + 1, r); merge(A, p, (p + r) / 2, r);//此函数实现合并 } }
三、冒泡算法实现:
void bubble_sort(int *A, int length) { int mid; for (int i = 0; i < length; i++) { for (int j = length - 1; j > i; j--) if (A[j] < A[j - 1]) {//双双相比 mid = A[j]; A[j] = A[j - 1]; A[j - 1] = mid; } } }
四、堆栈排序算法实现(实质上是数组和二叉树之间的映射):
定义数组: A[0]表示堆栈大小,即数组元素个数;所以数组中数据的下标是1开始到n
元素交换:
void swap(int &a, int &b) { int mid = a; a = b; b = mid; }
父子节点获取:
int parent(int i) {//子节点 return i / 2; }
int left(int i) {//i 此时是父节点的index return i * 2; } int right(int i) { return i * 2 + 1; }
针对指定父节点开始,进行堆栈最大化,从沿着不满足的子节点继续:
void max_heapify(int *A, int i) {//i是父节点 int l, r, largest; l = left(i); r = right(i); if (l <= A[0] && A[l] > A[i])//左节点和父节点比较 largest = l; else largest = i; if (r <= A[0] && A[r] > A[largest]) largest = r; if (largest != i) {//若父节点不是最大 swap(A[i], A[largest]); max_heapify(A, largest); } }
从最高处的父节点至最底处的根节点,每一个父节点都要进行堆栈最大化:
void build_max_heapify(int *A) { //从最高处的父节点开始(相对于根节点) for (int i = A[0] / 2; i >= 1; i--) max_heapify(A, i); }
把已经是堆栈最大化(但可能有部分节点不满足左子叶小于右子叶,但不影响排序)的数组进行以下操作
1. 根节点和最高处的子节点交换
2. 缩小堆栈大小
3. 从根节点开始,再次进行堆栈最大化
void sort_max_heapify(int *A) { //满足最大堆时,从把最高处末子节点和根节点交换,再进行最大堆构建,并且缩小堆大小 int heapsizeback = A[0]; build_max_heapify(A); for (int i = A[0]; i >= 2; i--) { swap(A[1], A[i]); A[0]--; max_heapify(A, 1);//始终从根节点开始构造 } A[0] = heapsizeback; }
五、快速排序算法实现:
patrition函数(把比特定值小的放到左边,把比特定值大的放右边,然后把特定值放中间的分割线处)
int patrition(int *A, int p, int r) { int x = A[r], i = p; for (int j = p; j < r; j++) { if (A[j] < x) {// swap(A[j], A[i]); i++; } } swap(A[i], A[r]);//特定值放分界处 return i; }
主函数
void quick_sort(int *A, int p, int r) {//p=0, r=n-1 if (p < r) { int q = patrition(A, p, r);//i左边全是小于特定值,i+1到j全是大于特定值 quick_sort(A, p, q - 1);//跳过特定值 quick_sort(A, q + 1, r); } }
六、stooge快速排序算法实现:
void stooge_sort(int *A, int p, int r) {//p=0, r=n-1 int k; if (A[p] > A[r]) swap(A[p], A[r]); if (p + 1 == r) return;//已经到了最后一个则停止 k = (r - p + 1) / 3; stooge_sort(A, p, r - k);//前2/3 stooge_sort(A, p + k, r);//后2/3 stooge_sort(A, p, r - k);//再次前2/3 }
七、基数排序算法实现:
这种算法一定是建立在另一种稳定算法的基础上,按位比较。这里随便找了一个stooge快速排序,并且改编。
注意:此算法针对等长的数据很精确,变长的数据不稳定。并没有仔细研究这个算法,初步推测是跟改编的算法有关。
在数据中,找出最大位数
int radix_maximum(int *A, int length) { int max = A[0], d=1; for (int i = 1; i < length; i++) if (A[i] > max) max = A[i]; while (max % (int)pow(10, d) != max) d++; return d; }
改编stooge算法,使其满足基数排序
void radix_stooge_sort(int *A, int p, int r, int d) { int k; if (A[r] % d == A[r] && A[p] % d != A[p])//前大后小 swap(A[p], A[r]); else if (A[p] % d == A[p] && A[r] % d != A[r]) {//前小后长 //什么都不用做 } else if (A[p] % d == A[p] && A[r] % d == A[r]) {//两者都不满足 //什么都不做 } else if ((A[p] / d % 10) == (A[r] / d % 10)) { //再多判断一位,radix采用任何算法的相等处,需要特殊处理 if (d != 1 && A[p] / (d / 10) % 10 > (A[r] / (d / 10) % 10)) swap(A[p], A[r]); } else if ((A[p] / d % 10) > (A[r] / d % 10)) swap(A[p], A[r]); if (p + 1 == r) return;//已经到了最后一个则停止 k = (r - p + 1) / 3; radix_stooge_sort(A, p, r - k, d);//前2/3 radix_stooge_sort(A, p + k, r, d);//后2/3 radix_stooge_sort(A, p, r - k, d);//再次前2/3 }
基数排序实现(必须建立在另一种稳定算法上)
void radix_sort(int *A, int length) { for (int d = 0; d < radix_maximum(A, length); d++) radix_stooge_sort(A, 0, length - 1, pow(10, d));//可采用任何改编的稳定排序算法 }
所有代码均经过测试,结果正确。