首页 > 代码库 > 小范围排序

小范围排序

已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过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]

根据题意,最小值一定在A的前k(0~k-1)个元素内、次小值一定在A的第二组k(1~k)个元素内,以此类推,每次取原数组A的k个元素进行堆排序,然后把堆顶元素放入A的已排序序列中,(0~k-1)排序的堆顶赋值给A[0],(1~k)排序的堆顶赋值给A[1],以此类推。最后剩下A中最后的k个元素(k-n~n-1),进行标准的堆排序,第一次是K个元素的堆,排序后将堆顶赋值给A[n-k],紧接着把堆尾元素赋值给堆顶,再排序,此时只是k-1个元素的堆,依次类推,每次把堆顶元素放入A中已排序序列后,都把堆尾元素赋值到堆顶,同时堆的元素个数减1,直到堆的元素个数为1,整个排序结束。

技术分享

 

 

 

 

 

 

 

 

 

#include <iostream>
#include <algorithm>
#include "string.h"
#include "stdio.h"
#include <vector>
#include <deque>
#include<stack>
#include <assert.h>
using namespace std;

class Sort {
public:
    int *data;
    int count;//堆中存在的节点数
    int capacity;

    int* heapSort(int* A, int n,int k) {
        data = new int[k+1];
        capacity = n;

        for( int i = 0 ; i < k ; i ++ )
        {
            data[i+1] = A[i];//使堆的结点存入data数组中时下标是从1开始
        }
        count = k;
        //构造堆
        for( int i = count/2 ; i >= 1 ; i -- )//从树中第一个不是叶子结点的索引开始
            shiftDown(i);
        
        for (int i = 0; i <n - k; i++){
            A[i] = data[1];//取堆顶元素,即最小值放入原数组中
            data[1] = A[i + k];//放入未处理的结点
            shiftDown(1);//调整最小堆
        }
        //剩下A中最后的k个元素(k-n~n-1),进行标准的堆排序
        for( int i = 0 ; i <k ; i++ )
            A[i+n-k] = extractMax();

        return A;
    }

    int extractMax()
    {
         assert(count>0);
         int ret = data[1];//堆中最大的结点
         swap( data[1] , data[count] );//令最大节点与最后一个节点交换
         count --;//删除最大节点
         shiftDown(1);//对刚刚交换上去的节点进行调整,使其符合最大堆的形式
         return ret;
    }
    void shiftUp(int k){
        while( k > 1 && data[k/2] < data[k] ){
            swap( data[k/2], data[k] );
            k /= 2;
        }
    }

    void shiftDown(int k){
        while( 2*k <= count )//如果该节点有左孩子
        {
            int j = 2*k;//左孩子的索引值
            if( j+1 <= count && data[j+1] < data[j])//如果该节点有右孩子,并且右孩子的值小于左孩子
                j ++;//更新为右孩子的索引值
            if( data[k] <= data[j])//如果该结点小于他的孩子结点
                break;
            swap(data[k],data[j]);//否则使该节点与孩子中最小的结点交换
            k = j;
        }
    }
};

int main()
{
    int array[]={3,2,1,6,5,4,9,8,7,11,10};
    Sort sort;
    int len = sizeof(array)/sizeof(array[0]);
    int* arr = sort.heapSort(array,len,3);
    for(int i=0;i<len;i++)
    {
        cout<<arr[i]<<" ";
    }
    cout<<endl;
    return 0;
}

 

小范围排序