小范围排序

这是我的第一篇技术博客,从一个小算法题写起。

小范围排序:已知一个几乎有序的数组,几乎有序指的是如果把数组排好序,每个元素移动距离不超过k,且k相对于原数组大小来说很小。比如一个数组[3,1,2,5,6,4,8,7,9]大小为9,我们可以发现每个元素移动不需要超过k=3就可以完成从小到大的排序,我们要选择一个合适的排序算法来对数据进行排序

考虑时间复杂度,我们使用改进后的堆排序,即有一组数组A[0],A[1]...A[k-1]...A[n-1]。

首先根据A[0]...A[k-1]建立从小到大排序的小根堆B[k],将堆的第一个元素(最小)弹出,放在位置A[0]。

再根据A[1]...A[k]建立从小到大排序的小根堆B[k],将堆的第一个元素(第二小)弹出,放在位置A[1]。

.

.

.

这样依次弹出,直到弹出N-k个数,我们再对结尾的最后k个数进行一次堆排序并将其插入到原数组A中的最后几位就好了。

我们每得到一个数,时间复杂度为O(logK),总共有N个数,所以此算法的时间复杂度为O(N*logK)。

附代码:


import java.util.Scanner;

public class Sort {
    public static int[] sortElement(int[] A, int n, int k) {
        // write code herep
        int[] B = new int[k];
        int flag = 0;
        for (int p = 0; p <= n-k; p++) {
            for (int i = 0; i < k; i++) {
                B[i] = A[i + p];//建立小根堆
            }
            B = buildHeap(B);
            for(int i = p;i < p+k; i++){
                if(A[i] ==  B[0]){//将堆顶弹出,放在数组A中
                    flag = i;//对每一个堆处理,标记弹出数在A中位置
                }
            }
            int tem = A[p];//每运行一轮,B[0]弹出插入到A[p]位置上,我们需要将A中弹出的数A[flag]填上原本在A[p]位置上的数
            A[p] = B[0];
            A[flag] = tem;
        }
        for(int i=k-1;i>0;i--){//对最后k个数进行堆排序,从大到小
            int t = B[0];
            B[0] = B[i];
            B[i] = t;
            adjustHeap(B,0,i);
        }
        for(int i=0;i<k;i++) {//将最后K个数反序插入到原数组A中
            A[n - k + i ] = B[k - i - 1];
        }
        return A;
    }

    private static int[] buildHeap(int[] A) { //建立堆
        for (int i = A.length - 1; i >= 0; i--) {
            adjustHeap(A, i, A.length);
        }
        return A;
    }

    private static void adjustHeap(int[] A, int k, int len) {//对堆的数字进行调整
        int tem = A[k];
        for (int i = 2 * k + 1; i < len; i = 2 * i + 1) {
            if (i != len - 1 && A[i] > A[i + 1]) {
                i++;//如果左子树大于右子树,那么取右子树
            }
            if (tem < A[i]) {//将子树与树根比较
                break;
            } else {
                A[k] = A[i];
                k = i;//修改K值,以方便下调
            }
        }
        A[k] = tem;
    }

    public static void main(String[] args) {
        Scanner read = new Scanner(System.in); 
        int n; //元素个数
        System.out.println("请输入数组元素个数");
        n = read.nextInt(); 
        int[] arr;
        arr = new int[n];
        int i, k;
        for (i = 0; i < arr.length; i++) {  
            arr[i] = read.nextInt(); 
        }
        System.out.println("请输入移动距离");
        k = read.nextInt();
        arr = sortElement(arr,n,k);
        for (i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值