zoukankan      html  css  js  c++  java
  • 索引优先队列 超大文件如何排序?

    //索引优先队列 ,类似 带有键值对  key:index value:obj
    //二叉堆实现
    public class IndexMinPQ<T extends Comparable<T>> {
        int[] pqueue;       //索引优先队列  N->k , 从1开始 ,1为堆顶(最小)
        int[] k2n;          //k->N  ,从1开始,0是哨兵
        T items[];          //k->Item   ,从1开始,0是哨兵
        final int maxN;     //最大索引数
        int N;              //当前数据个数
    
        public IndexMinPQ(int maxN) {
            this.maxN = maxN;
            pqueue = new int[maxN + 1];
            k2n = new int[maxN + 1];
            items = (T[]) new Comparable[maxN + 1];
    
            for (int i = 0; i < maxN + 1; i++) {
                k2n[i] = -1;
            }
        }
    
        public int getMaxN() {
            return maxN;
        }
    
        public boolean contain(int k) {
            return k2n[k] != -1;
        }
    
        //k 自定义索引, k = [1 ~ maxN] ,下标从1开始
        //item 数据对象
        public void insert(int k, T item) {
            if (k < 1 || k > maxN)
                throw new RuntimeException("k=[1,maxN] K:" + k);
            if (contain(k)) {
                throw new RuntimeException("already contain K:" + k + " item:" + items[pqueue[k]]);
    //            return;
            }
            N++;
            k2n[k] = N;         //k->N
            pqueue[N] = k;      //N->k
            items[k] = item;
            swimUp(N);
        }
    
        public void change(int k, T item) {
            items[k] = item;
            swimUp(k2n[k]);
            sinkDown(k2n[k]);
        }
    
        public T top() {
            if (N > 0)
                return items[pqueue[1]];
            return null;
        }
    
        public T delTop() {
            if (N < 1)
                return null;
            T top = items[pqueue[1]];   //保留删除的最顶
            exch(1, N);                 //最低的换到最顶,做sink
            items[pqueue[N]] = null;    //删掉换到最低的最顶
            k2n[pqueue[N]] = -1;
            pqueue[N] = 0;
            N--;
            sinkDown(1);
            return top;
        }
    
        public T del(int k) {
            if (k2n[k] == -1)
                return null;
            T tDel = items[k];
            pqueue[k2n[k]] = pqueue[N]; //最低的换到当前
            N--;
            swimUp(k2n[k]);             //将换过来的做 swim,sink ,堆有序化
            sinkDown(k2n[k]);
            k2n[k] = -1;                //删除目标k对应的n
            items[k] = null;
            return tDel;
        }
    
        public int topIndex() {
            if (N > 0)
                return pqueue[1];
            return -1;
        }
    
        public boolean isEmpty() {
            return N < 1;
        }
    
        public int size() {
            return N;
        }
    
        private void swimUp(int n) {
            int child = n;
            int parent = child / 2;
            while (parent > 0) {
                T pt = items[pqueue[parent]];
                T ct = items[pqueue[child]];
                if (pt.compareTo(ct) < 0)
                    break;
                exch(parent, child);
                child = parent;
                parent = child / 2;
            }
        }
    
        private void sinkDown(int n) {
            int parent = n;
            int lchild = parent * 2;
            int rchild = lchild + 1;
            int targetChild;
            while (lchild <= N || rchild <= N) {
                T pt = items[pqueue[parent]];
                T tc = null;
                targetChild = lchild;       //默认用left child,当 lchild == rchild value 的时候,或不存在rchild的时候
                if (rchild < N) {           //targetChild ,找到2个child中更小的那个
                    int rcmpl = items[pqueue[rchild]].compareTo(items[pqueue[lchild]]);
                    if (rcmpl < 0)          //若 rchild 更小
                        targetChild = rchild;
                }
                tc = items[pqueue[targetChild]];
                if (pt.compareTo(tc) < 0)
                    break;
                exch(parent, targetChild);
                parent = targetChild;
                lchild = parent * 2;
                rchild = lchild + 1;
            }
        }
    
        private void exch(int n1, int n2) {
            int tmp = pqueue[n1];       //[n]->k
            pqueue[n1] = pqueue[n2];
            pqueue[n2] = tmp;
            tmp = k2n[pqueue[n1]];      //[k]->n
            k2n[pqueue[n1]] = k2n[pqueue[n2]];
            k2n[pqueue[n2]] = tmp;
        }
    
        @Override
        public String toString() {
            return "IndexMinPQ{" +
                    "pqueue[N]=k =" + Arrays.toString(pqueue) +
                    ", 
    k2n[k]=N =" + Arrays.toString(k2n) +
                    ", 
    items[k]=O =" + Arrays.toString(items) +
                    ", 
    maxN=" + maxN +
                    ", 
    N=" + N +
                    '}';
        }
    
        public static void main(String[] args) {
            IndexMinPQ<Integer> ipq = new IndexMinPQ<>(10);
            ipq.insert(2, 22);
            ipq.insert(6, 66);
            ipq.insert(1, 11);
            ipq.insert(4, 44);
            System.out.println(ipq);
    
            ipq.change(1, 111);
            System.out.println(ipq);
    
            System.out.println("ipq.contain(2) :" + ipq.contain(2));
    
            System.out.println("ipq.top() :" + ipq.top()); //2
            System.out.println("ipq.topIndex() :" + ipq.topIndex()); //2
            System.out.println("ipq.delTop() :" + ipq.delTop());
            System.out.println(ipq);
    
            ipq.insert(10, 1);
    //        ipq.insert(0, 1);
            System.out.println(ipq);
    
            while (!ipq.isEmpty()) {
                System.out.println("k: " + ipq.topIndex() + " v:" + ipq.delTop());
            }
    
            System.out.println("====");
            Random r = new Random(123);
            while (ipq.size() < ipq.getMaxN()) {
                ipq.insert(ipq.size() + 1, r.nextInt(100));
            }
            while (!ipq.isEmpty()) {
                System.out.println("k: " + ipq.topIndex() + " v:" + ipq.delTop());
            }
        }
    }

    带索引号的优先队列

    key,索引号 用于找对应value

    value, 任意可比较对象,优先队列根据对象的大小排序

    优先队列中存储 key,根据key 值,找到在 item[] 中的对象,根据对象比较结果,进行排序(堆有序化,上浮,下沉)

    也可以用change(k,item) 对堆中已存在的某个 key值对应的对象经行更新,更新后再次对该对象进行堆有序化处理

    应用:

    比如有1000个已经排序好的(从小达到)大文件,每个1G,文件内单条数据1M,而机器上的内存只有1G内存(单个文件比内存还大,无法完整载入内存),如何将这1000个文件排序并输出到1个文件中?

    用这个 索引优先队列就可以完成,申请一个 1000个元素的索引优先队列,并同时打开这1000个文件,给文件按照从1-1000 编号,每个文件一次只读取1条数据到 索引优先队列,并且key值对应文件编号。

    当1000个文件的1000条数据读入后,从索引优先队列中取出最小值,然后单独打开一个输出文件,将最小值输出,并再次从刚才读取最小值的文件编号的文件中再次读取下一跳数据,再插入到优先队列中。

    如此反复,直到单个文件的所有数据读取并处理完成后,不再对这个文件进行处理,直到所有的这1000个文件都处理完成后,就可以完成有序合并。

  • 相关阅读:
    [Baltic2013]ballmachine BZOJ3133
    [Jxoi2012]奇怪的道路 BZOJ3195 状压DP
    [Baltic 2011]Lamp BZOJ2346
    可并堆
    [Jsoi2016]最佳团体 BZOJ4753 01分数规划+树形背包/dfs序
    点分治
    J2EE WEB应用架构分析
    {经典}springmvc+mybatis+restful+webservice Jeesz分布式架构
    深入Spring Boot:那些注入不了的 Spring 占位符 ( ${} 表达式 )
    G1 垃圾收集器之对象分配过程
  • 原文地址:https://www.cnblogs.com/cyy12/p/11979216.html
Copyright © 2011-2022 走看看