对接近有序的数组排序

给定一个数组,数组内每一个元素的位置和其最终排序好的位置 的 距离相差在 k 以内,怎么有效的对其排序?要求时间复杂度为 O(n log k)

例如:当k=2时,如果一个元素的位置为 7,那么再最终的排序数组中该元素的位置在 5-9 之间。

方法一 插入排序

比较每个排序算法的特点,会发现插入排序对于这种情况可能会比较好,因为插入元素时,比较的次数不会超过k。

01 /* 插入排序 */
02 void insertionSort(int A[], int size)
03 {
04    int i, key, j;
05    for (i = 1; i < size; i++)
06    {
07        key = A[i];
08        j = i-1;
09  
10        /* 插入一个元素,对于大的后移。最多比较k次 */
11        while (j >= 0 && A[j] > key)
12        {
13            A[j+1] = A[j];
14            j = j-1;
15        }
16        A[j+1] = key;
17    }
18 }

最多需要k次比较和k个元素后移,因此复杂度为 O(nk)

方法二为堆排序

依然没有达到要求 O(n log k) ,可以使用 堆来继续优化。详细步骤如下:

1 1) 用最开始的k+1个元素 创建一个大小为k+1的小顶堆。时间为 O(k)
2 2) 依次从小顶堆中取出最小元素放到结果数组中,然后从剩下的待排序数组中添加新的元素到堆中

从堆中取出一个元素并加入新的元素,为花费 O(Log k )的时间。所以总共的时间复杂度为 O(k) + O((n-k)*logK)

代码实现:

001 #include<iostream>
002 using namespace std;
003 void swap(int *x, int *y);
004  
005 //小顶堆类
006 class MinHeap
007 {
008     int *harr; // 堆中的元素数组
009     int heap_size; // 堆的大小
010 public:
011     // 构造函数
012     MinHeap(int a[], int size);
013  
014     // 从给定的下标开始调整堆
015     void MinHeapify(int );
016  
017     //i的左孩子的下标
018     int left(int i) { return (2*i + 1); }
019  
020     // i的右孩子的下标
021     int right(int i) { return (2*i + 2); }
022  
023     //取走最小值(或者说是 root), 并添加新的元素x
024     int replaceMin(int x);
025  
026     // 取最小值
027     int extractMin();
028 };
029  
030 // k为每个元素的当前位置和排序数组位置相差的范围
031 int sortK(int arr[], int n, int k)
032 {
033     // 用前 (k+1) 个元素创建最小堆
034     int *harr = new int[k+1];
035     for (int i = 0; i<=k && i<n; i++) // i < n 防止 k>n的情况
036         harr[i] = arr[i];
037     MinHeap hp(harr, k+1);
038  
039     for(int i = k+1, ti = 0; ti < n; i++, ti++)
040     {
041         //如果有剩余元素,就替换掉堆顶
042         if (i < n)
043             arr[ti] = hp.replaceMin(arr[i]);
044         // 否则就依次取走堆顶的元素,
045         else
046             arr[ti] = hp.extractMin();
047     }
048 }
049  
050 // 以下是标准的小顶堆的实现
051 MinHeap::MinHeap(int a[], int size)
052 {
053     heap_size = size;
054     harr = a; 
055     int i = (heap_size - 1)/2;
056     while (i >= 0)
057     {
058         MinHeapify(i);//构建初始堆
059         i--;
060     }
061 }
062  
063 //从小顶堆中移除堆顶元素
064 int MinHeap::extractMin()
065 {
066     int root = harr[0];
067     if (heap_size > 1)
068     {
069         harr[0] = harr[heap_size-1];
070         heap_size--;
071         MinHeapify(0);
072     }
073     return root;
074 }
075  
076 // 替换root和给定的x
077 int MinHeap::replaceMin(int x)
078 {
079     int root = harr[0];
080     harr[0] = x;
081     if (root < x)
082         MinHeapify(0);
083     return root;
084 }
085  
086 // 调整小顶堆(递归的方法)
087 void MinHeap::MinHeapify(int i)
088 {
089     int l = left(i);
090     int r = right(i);
091     int smallest = i;
092     if (l < heap_size && harr[l] < harr[i])
093         smallest = l;
094     if (r < heap_size && harr[r] < harr[smallest])
095         smallest = r;
096     if (smallest != i)
097     {
098         swap(&harr[i], &harr[smallest]);
099         MinHeapify(smallest);
100     }
101 }
102  
103 // 交换
104 void swap(int *x, int *y)
105 {
106     int temp = *x;
107     *x = *y;
108     *y = temp;
109 }
110  
111 //打印数组
112 void printArray(int arr[], int size)
113 {
114    for (int i=0; i < size; i++)
115        cout << arr[i] << " ";
116    cout << endl;
117 }
118  
119 // 测试
120 int main()
121 {
122     int k = 3;
123     int arr[] = {2, 6, 3, 12, 56, 8};
124     int n = sizeof(arr)/sizeof(arr[0]);
125     sortK(arr, n, k);
126  
127     cout << "Following is sorted array\n";
128     printArray (arr, n);
129  
130     return 0;
131 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值