小范围排序

    xiaoxiao2021-03-25  41

    题目描述

    已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。 请选择一个合适的排序算法针对这个数据进行排序。 给定一个int数组A,同时给定A的大小n和题意中的k,请返回排序后的数组。 测试样例:[2,1,4,3,6,5,8,7,10,9],10,2 返回:[1,2,3,4,5,6,7,8,9,10]

    思路

    因为元素移动距离不超过k,所以可以构造k项最小堆(在0-k的范围内必然可以找到正确的最小值),然后将最小堆的堆首(最小值)弹出,压入后一个值,反复进行这个过程即可得到有序数组,因为构建堆是常数时间,遍历数组时间复杂度是O(N),每次进行的下沉操作时间复杂度是O(lgK),所以整个算法的时间复杂度是O(N*lgK)。这道题花了我将近一天的时间(醉了),原因是最后一个元素移入k项堆后的情况搞错了,详见代码。

    class ScaleSort { public: //建立最小堆 void min_heap(vector<int> &A, int begin, int end){ int c = begin; int left = 2 * c + 1; int tmp = A[c]; while (left <= end){ if (left < end && A[left] > A[left + 1]) left++; if (A[c] < A[left]) break; else{ A[c] = A[left]; A[left] = tmp; } c = left; left = left * 2 + 1; } } vector<int> sortElement(vector<int> A, int n, int k) { // write code here for (int i = k / 2 - 1; i >= 0; i--){ min_heap(A, i, k); } int m = 0; for (int j = 0; j < n; j++){ if (j < n - k - 1){ res[j] = A[0]; A[0] = A[k + j+1]; min_heap(A, 0, k); } else{ //当最后几个元素都压入k项堆后,注意此时最后的k的元素所在的范围是A[0]-A[k],并且弹出A[0]后需要把A[k]移到A[0]处, res[j] = A[0]; A[0] = A[k - m]; min_heap(A, 0 , k-m); m++; } } return res; } }; 另附上一篇讲解堆排序的文章,是我目前见过写得最好的文章: http://wangkuiwu.github.io/2013/05/06/heap-sort/
    转载请注明原文地址: https://ju.6miu.com/read-26006.html

    最新回复(0)