您的位置:首页 > 其它

大(小)顶堆练习:POJ 1442

2013-02-20 19:59 253 查看
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小元素

Java代码







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();

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: