• 小范围排序


    已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过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;
    }
  • 相关阅读:
    数组(Array)
    js数据类型自动转化规律
    ES6-12.Symbol
    彻底搞懂prototype和__proto__
    API测试利器——Postman(1. 安装和启动)
    全国各城市的代码邮编sql(mysql版)
    SQL执行的顺序
    jQuery $.each用法
    使用maven工具对maven项目进行打包所出现的问题
    关于Notepad++中用正则表达式匹配中文的问题
  • 原文地址:https://www.cnblogs.com/omelet/p/6604251.html
Copyright © 2020-2023  润新知