for (j = i - 1; a[j] > x && j >= 0; --j) { a[j + 1] = a[j]; }
插入到寻找到的正确位置a[j - 1] = x;
1 2 3 4 5 6 7 8 9 10 11 12
//直接插入排序 不带哨兵 voidinsertSort(SqList &L){ int i, j; for (i = 0; i < L.length; ++i) { if (L.elem[i] < L.elem[i - 1]) { int x = L.elem[i]; for (j = i - 1; L.elem[j] > x && j >= 0; --j)//顺序查找找到插入的位置 L.elem[j + 1] = L.elem[j];//所有大于x的记录都将后移 L.elem[j + 1] = x;//插入元素 } } }
1 2 3 4 5 6 7 8 9 10 11 12
//直接插入排序 利用哨兵省略掉 j >= 0 的判断语句 voidinsertSort(SqList &L){ int i, j; for (i = 2; i <= L.length; ++i) { if (L.elem[i] < L.elem[i - 1]) { L.elem[0] = L.elem[i];//赋值为哨兵 for (j = i - 1; L.elem[j] > L.elem[0]; --j)//顺序查找找到插入的位置 L.elem[j + 1] = L.elem[j];//所有大于哨兵的元素记录都将后移 L.elem[j + 1] = L.elem[0];//将哨兵插入到正确的位置 } } }
//实现方案1:间隔内直接插入排序 voidshellInsert(SqList &L, int dk){ //对顺序表L进行一趟增量为dk的shell排序,其中dk为步长因子 int i, j; for (i = dk - 1; i < L.length; ++i) { if (L.elem[i] < L.elem[i - dk]) { int x = L.elem[i]; for (j = i - dk; L.elem[j] > x && j >= 0; j = j - dk)//顺序查找找到插入的位置 L.elem[j + dk] = L.elem[j];//所有大于x的记录都将后移 L.elem[j + dk] = x;//插入元素 } } } voidshellSort(SqList &L, int dlta[], int max){ //dk值依次存在dlta[t]中 //按增量序列dlta[0..L.length]对顺序表L作希尔排序 for (int k = 0; k < max; ++k) { shellInsert(L, dlta[k]);//一趟增量为dlta[k]的直接插入排序 } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
//实现方案2:间隔间切换进行直接插入排序 voidshellSort1(int A[], int n){ //A[0]只是暂存单元不是哨兵 当j<=0时插入位置已到 int dk; int i, j; for (dk = n/2; dk >= 1; dk = dk/2) {//步长变化 for (i = dk + 1; i <= n; ++i) { if (A[i] < A[i - dk]) { A[0] = A[i];//暂存在A[0] for (j = i - dk; A[j] > A[0] && j > 0; j = j - dk) A[j + dk] = A[j];//元素后移 A[j + dk] = A[0];//元素插入 } } } }
//下标易读化写法 i范围为(0 ~ n-2) 修改j范围为(0 ~ n-i-2) voidbubbleSort1(SqList &L){ int n = L.length; for (int i = 0; i < n - 1; ++i) {//需要n - 1趟 for (int j = 0; j < n - i - 1; ++j) { if (L.elem[j] > L.elem[j + 1]) swap(L.elem[j], L.elem[j + 1]);//发生逆序则进行交换 } } } //下标简化的等价写法 修改i范围为(1 ~ n-1) 则修改j的范围可简化写(0 ~ n-i-1) voidbubbleSort2(SqList &L){ int n = L.length; for (int i = 1; i < n; ++i) {//需要n - 1趟 for (int j = 0; j < n - i; ++j) { if (L.elem[j] > L.elem[j + 1]) swap(L.elem[j], L.elem[j + 1]);//发生逆序则进行交换 } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
//改进的冒泡排序算法:若发现某次遍历后已经是有序的序列,则可直接跳出循环无需再遍历 //新增flag用于标记是否发生交换 voidbubbleSort3(SqList &L){ int flag = 1; int n = L.length; for (int i = 1; i < n && flag; ++i) {//需要n - 1趟 flag = 0; for (int j = 0; j < n - i; ++j) { if (L.elem[j] > L.elem[j + 1]) { flag = 1; swap(L.elem[j], L.elem[j + 1]);//发生逆序则进行交换 } } } }
voidHeapAdjust(int R[], int x, int n){ //调整R[x]的关键字,使R[x...n]成为一个大根堆 int rc = R[x]; for (int i = 2*x; i <= n; i *= 2) {//沿较大的孩子结点向下筛选(2*x即为较大孩子) if (i < n && R[i] < R[i + 1]) i = i + 1;//对比左右孩子的大小 取key为较大的孩子节点的下标(保证有右孩子) if (rc >= R[i]) break;//若rc已经满足大根堆的要求 则筛选直接结束 eles { R[x] = R[i];//将A[i]调整到双亲结点上 x = i;//修改x值为i继续向下筛选(实现树的继续向下筛选) } } R[x] = rc;//被筛选结点的值放入最终位置 } //依次将以序号为n/2、n/2-1...1的结点为根的子树调整为堆 for (int i = n/2; i >= 1; --i) HeapAdjust(R, i, n);
//将以x为根的子树调整为大根堆 voidHeapAdjust(int R[], int x, int n){ int rc = R[x]; for (int i = 2*x; i <= n; i *= 2) {//沿较大的孩子结点向下筛选(2*x即为较大孩子) if (i < n && R[i] < R[i + 1]) i = i + 1;//对比左右孩子的大小 取key为较大的孩子节点的下标(保证有右孩子) if (rc >= R[i]) break;//若rc已经满足大根堆的要求 则筛选直接结束 eles { R[x] = R[i];//将A[i]调整到双亲结点上 x = i;//修改x值为i继续向下筛选(实现树的继续向下筛选) } } R[x] = rc;//被筛选结点的值放入最终位置 } //堆排序下标范围为 0 - length-1 voidHeapSort(int R[], int n){//对R[1]到R[n]进行堆排序 //1.建立初始堆O(n) for (int i = (n-1)/2; i >= 0; --i) HeapAdjust(R, i, n); //2.堆去顶后重构O(nlogn) for (int i = n - 1; i > 0; --i) {//去顶重构n-1次 swap(R[0], R[i]);//根与最后一个元素交换(去顶) HeapAdjust(R, 0, i - 1);//重新建堆 } } //堆排序下标范围为 1 - length voidHeapSort(int R[], int n){//对R[1]到R[n]进行堆排序 //1.建立初始堆O(n) for (int i = n/2; i >= 1; --i) HeapAdjust(R, i, n); //2.堆去顶后重构O(nlogn) for (int i = n; i > 1; --i) {//去顶重构n-1次 swap(R[1], R[i]);//根与最后一个元素交换(去顶) HeapAdjust(R, 1, i - 1);//重新建堆 } }
//[low...mid]和A[mid+1...high]各自有序 将两个部分归并 voidmerge(int A[], int n, int low, int mid, int high){ int i, j, k; int *B = (int *)malloc(n*sizeof(int));//辅助数组B for (k = low; k <= high; ++k) B[k] = A[k];//将A中的所有元素复制到B中 for (i = low, j = mid + 1, k = i; i <= mid && j <= high; ++k) {//归并操作 if (B[i] <= B[j]) A[k] = B[i++];//将较小值复制到A中 else A[k] = B[j++]; } while(i <= mid) A[k++] = B[i++];//未归并完的部分直接复制到尾部 while(j <= high) A[k++] = B[j++]; }
voidmergeSort(int A[], int n, int low, int high){ if (low < high) { int mid = (low + high)/2;//从中间划分 mergeSort(A, n, low, mid);//左半部分归并排序 mergeSort(A, n, mid + 1, high);//右半部分归并排序 merge(A, n, low, mid, high);//归并操作 } } mergeSort(L.elem, L.length, 0, L.length - 1);
归并排序时间效率为O(nlog2n)
归并排序空间效率为O(n)
归并排序是一个稳定的排序算法
注:关于2路归并的归并树(倒立的二叉树)
二叉树的第h层最多有2h-1个结点,即满足 n ≤ 2h-1 即为 h - 1 = $\lceil log_2n \rceil$