题目
已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。
给定一个int数组A,同时给定A的大小n和题意中的k,请返回排序后的数组。
思路
时间复杂度 O(n)的. 桶排序: 由于数组大小和区别无法确定, 最好别用
时间复杂度 O(nlogn)的: 堆排序: 已经每个元素最多移动k个距离, 那么最下的那个数移动到数组第一个位置距离最多为k, 可以建立长度为k的小根堆, 并且弹出堆顶, 接着小根堆向后移动一位, 再次进行排序, 弹出堆顶, 再次后移.... 这样就可以了. 只需改进一下堆排序
public static void main (String[] args) { int []A={3,2,7,1,8,6,4,5,12,10,15,9,13,14,11,20,16,17,18,19}; sortElement(A, 5); } public static void sortElement(int[] A, int k) { if (A == null || A.length == 0) return; int len = A.length; int i, j; for (i = 0; i < len; i++) { if(i + k <= len) { // 运算到后面的时候, 小根堆偏移会超出数组长度, 这里需要进行判定 for (j = k / 2 - 1; j >= 0; j--) { adjustHeapSmall(A, i + j, i, k - 1); } } else { for (j = (len - i)/2 - 1; j >= 0; j--) { // 修改 j adjustHeapSmall(A, i + j, i, len - i - 1); } } } for (i = 0; i < len; i++) { System.out.print(A[i] + " "); } } /** * @param A 数组 * @param i 非叶子节点下标 * @param m 偏移量 * @param len 长度 */ public static void adjustHeapSmall(int[] A, int i, int m, int len) { int j, k, temp = A[i]; // 把 j = 2 * i + 1 改了一下 j = 2*(i-m)+1; for (j = 2 * i + 1 -2 * m; j <= len; j = j * 2 + 1) { k = m + j; // 非叶子节点的左子节点下标 if (j < len && A[k] > A[k+1]) k++; if (A[k] > temp) break; A[i] = A[k]; i = k; } A[i] = temp; }
运行结果: