java升序排列20个数字_有20个数组,每个数组里面有500个数,升序排列,求出这10000个数中的最大500个数。并求复杂度。【百度2012年的一道算法题】...

package wheels;

/**

* 最大堆的简单实现

* 类比最小堆,在此主要是锻炼自己迅速写各式各样的轮子,再写一遍

* @author XZP

* 一组测试数据: 12 45 -11 69 1 95 9 78 64 21

*/

public class MaxHeap {

private int INF = -9999999; // 认为规定的最小值

private int[] arr;

public MaxHeap (int size) {

arr = new int[size + 1]; // 下标从1开始

for (int i = 0; i <= size; i++) { // 牺牲空间和一定时间来保证数组能存零值

arr[i] = INF;

}

}

/**

* 向最大堆中插入一个元素使其任然满足最大堆

* @param data 待插入数据

* @return 成功为true,失败将打印异常栈

*/

public boolean push(int data) {

int index = this.index();

try {

this.arr[index] = data;

siftup(index); // 插入数组末尾之后需要向上调整使其满足最大堆

} catch (IndexOutOfBoundsException e) {

e.printStackTrace();

}

return true;

}

/**

* @return 数组能存储的最大size

*/

public int size() {

return arr.length - 1;

}

/**

* 获取当前能插入值得数组下标

* @return 数组中已有值长度 + 1

*/

private int index() {

int usedLength = 0;

for (int i = 1; i <= this.size(); i++) {

if (this.arr[i] != INF) {

usedLength++;

}

}

return usedLength + 1;

}

/**

* 从最小堆中取最小的那个元素,并调整使其一直满足最小堆

* @return 数组不为空则返回最小的元素,否则返回人为规定的INF值

*/

public int pop() {

if (!isLegal(1)) { // 每次取第一个元素(下标值为1,而不是0)

return INF;

}

int value = this.arr[1];

int end = this.index() - 1; // 数组中最后一个有效元素

if (!isLegal(end)) { // 这个元素不合法说明此时数组中只有索引为1这个值有效

this.arr[1] = INF;

return value;

}

this.arr[1] = this.arr[end]; // 将末尾有效值(层数最深最右边的叶子结点)置为根节点并向下调整

this.arr[end] = INF;

siftdown(1);

return value;

}

/**

* 向上调整的方法

* @param i 待调整的孩子节点

*/

private void siftup(int i) {

if (i <= 1) {

return; // 1 左移一位是0了

}

int parent = i >> 1;

boolean flag = true; // 是否需要调整

while (parent >= 1 && flag) {

if (this.arr[parent] < this.arr[i]) {

swap(parent, i);

siftup(parent);

parent = parent >> 1;

} else {

flag = false;

}

}

}

/**

* 向下调整的方法

* @param i 待调整的节点下标

*/

private void siftdown (int i) {

int parent = i;

int left = this.left(i);

int right = this.right(i);

int max = this.getMax(left, right);

boolean flag = true;

while (parent <= this.size() / 2 && flag && isLegal(max)) {

if (this.arr[max] > this.arr[i]) {

swap(max, i);

parent = max;

siftdown(parent);

} else {

flag = false;

}

}

}

/**

* 获取根节点左孩子的下标值

* @param i

* @return

*/

private int left(int i) {

return i << 1; //左孩子的坐标为右移一位

}

/**

* 获取根节点右孩子的的下标值

* @param i

* @return

*/

private int right(int i) {

return (i << 1) + 1; // 右孩子为右移一位 + 1

}

/**

* 获取值较大的下标值

* @param i 左孩子下标值

* @param j 右孩子下标值

* @return 如果有下标值有一个没有越界,返回较大的那个。如果都越界,则返回无效索引值0

*/

private int getMax(int i, int j) {

if (isLegal(i) && isLegal(j)) { // 如果两个都没有越界,返回较小的下标值

return this.arr[i] > this.arr[j] ? i : j;

} else if (isLegal(i)) { // 返回左孩子下标

return i;

} else if (isLegal(j)) { // 返回右孩子下标

return j;

} else { // 返回备用索引0

return 0;

}

}

/**

* 交换两下标对应的值

* @param i

* @param j

*/

private void swap(int i, int j) {

int temp = this.arr[i];

this.arr[i] = this.arr[j];

this.arr[j] = temp;

}

/**

* 检查一个下标是否魏越界或者是否存储了实际值

* @param i

* @return 在数组范围内返回true,越界返回false

*/

private boolean isLegal(int i) {

return 1 <= i && i <= this.size() ? this.arr[i] != INF ? true : false : false; // 首先判断数组下标越界与否,在没有越界的基础上还需要判断是否是有效值

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值