大(小)顶堆练习:POJ 1442

POJ1442题意:
   ADD(a)表示向集合中增加元素a,get表示取出第k小元素,k根据get出现的次数不断变化,出现多少次取第几小数。
样例:

Sample Input

7 4
3 1 -4 2 8 -1000 2
1 2 6 6
Sample Output

3
3
1
2

解释:
输入 n = 7 m =4,然后第一行输入n个数,然后另一行输入m个数

index = 1

1:输出n个数中前1个数中的第Index(1)小值

index=2

2:输出n个数中前2个数中的第index(2)小值

index=3

6:输出n个数中前6个数中的第index(3)小值

index=4

6:输出n个数中前6个数中的第index(4)小值


输入保证m个数单调递增

题解:每次取第k小元素,k不断更新。使用两个堆,来完成。 小顶堆负责,选出最小的元素,大顶堆负责,选出k个元素中最大的元素,即第k小元素


import java.util.Scanner;

  public class Main{
   int tree1[];//大顶堆   
   int k1;  
   int tree2[];//小顶堆   
   int k2;  
   int M, N;  
   int A[];  
  
  public Main(){
   }

  //tree:大顶堆
  void build1(int[] tree, int k)  //从下标k开始,大堆向上调整到根
  {  
    int p = k;  
    while(p != 1)  
    {  
        if(tree[p] > tree[p / 2])  //如果大于父亲
        {  
            int temp = tree[p];  //交换
            tree[p] = tree[p / 2];  
            tree[p / 2] = temp;  
        }  
        p = p / 2;  //指向父亲
    }  
}  
  //tree:小顶堆
void build2(int[] tree, int k)  //从k开始,小堆向上调整
{  
    int p = k;  
    while(p != 1)  
    {  
        if(tree[p] < tree[p / 2])  //如果小于交亲
        {  
            int temp = tree[p];  //交换
            tree[p] = tree[p / 2];  
            tree[p / 2] = temp;  
        }  
        p = p / 2;  //指向父亲
    }  
}  
  
//tree:大顶堆
void update1(int[] tree, int k){//向下调整大顶堆的根.  
    int p = 1;  //指向根
    while(2 * p <= k)  
    {  
        int son;  
        if(2 * p == k || tree[2 * p] > tree[2 * p + 1])  
            son = 2 * p;  
        else  
            son = 2 * p + 1;  
        if(tree[p] < tree[son])  //如果父节点的值小于左右儿子中最大者,交换
        {  
            int temp = tree[p];  
            tree[p] = tree[son];  
            tree[son] = temp;  
        }  
        p = son;  //指向儿子节点
    }  
}  
  
//tree:小顶堆
void update2(int[] tree, int k)  //向下调整小顶堆的根,直到k
{  
    int p = 1;  
    while(2 * p <= k)  
    {  
        int son;  
        if(2 * p == k || tree[2 * p] < tree[2 * p + 1])  //取左右儿子中的较小者
            son = 2 * p;  
        else  
            son = 2 * p + 1;  
        if(tree[p] > tree[son])  //如果父节点的值大于左右儿子中最大者,交换
        {  
            int temp = tree[p];  
            tree[p] = tree[son];  
            tree[son] = temp;  
        }  
        p = son;  
    }  
}  
  
  public void  go(){  
   Scanner in=new Scanner(System.in);
    while(in.hasNext())  
    {  
     M=in.nextInt();
     N=in.nextInt();

     A=new int[M+1];
     tree1=new int[M+1];
     tree2=new int[M+1];
     for(int i = 1; i <= M; ++ i)  
            A[i]=in.nextInt();//将M个元素全部读入A
  
        int pre = 0;  
        k1 = k2 = 0;  
        for(int i = 1; i <= N; ++ i)  //共N轮
        {  
            int a=in.nextInt();  
            for(int j = pre + 1; j <= a; ++ j)  //从A中读入前a个元素到tree2
            {  
                tree2[++k2] = A[j];  //读一个,调整一个
                build2(tree2, k2);  //构建tree2使之成为最小堆
                  
            }  
            pre = a;  
            tree1[++ k1] = tree2[1];  //将最小堆的堆顶元素放入tree1中
            build1(tree1, k1);  //构建tree1使之成为最大堆
            tree2[1] = tree2[k2 --];  //删除最小堆的堆顶元素,最小堆的最后一个元素放到堆顶
            update2(tree2, k2);  //调整,使tree2成为小顶堆
            while(k2 != 0 && tree1[1] > tree2[1])  
            {  
                int temp = tree1[1];  
                tree1[1] = tree2[1];  
                tree2[1] = temp;  
                update1(tree1, k1);  //调整,使tree1成为大顶堆
                update2(tree2, k2);  //调整,使tree2成为小顶堆
            }  
            System.out.printf("%d\n", tree1[1]);  
        }         
    }
  }  
    
  public static void main(String args[]){
       Main ma=new Main();
       ma.go();
  }
}

你可能感兴趣的:(java,数据结构,编程,算法)