输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
当数据量很大的时候为了节省空间,那就要使用堆排序
这里我自己实现了堆的调整过程
public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
//k小于input的长度
if(k > input.length || k<=0) return list;
if (k == input.length) {
for (int i = 0; i < input.length; i++) {
list.add(input[i]);
}
return list;
}
//初始化树
int[] tree = new int[k];
for (int i = 0; i < k; i++) {
tree[i] = input[i];
}
//创建大顶堆
//先获取第一个非叶子节点的位置
int begin = k / 2 - 1;
for (int i = begin; i >= 0 ; i--) {
adjustBigHeap(tree, i, k);
}
//此时tree[0]一直是4个数中最大的数
for (int i = k; i < input.length; i++) {
if(input[i] < tree[0]){
//发现当前值比树中最大值小,替换树中最大值,再进行堆排序
tree[0] = input[i];
adjustBigHeap(tree, 0, k);
}
}
for (int i = 0; i < k; i++) {
list.add(tree[i]);
}
return list;
}
/***
* 大顶堆调整函数
* 使用该方法创建大顶堆如节点个数为n,数组为tree,则第一个非叶子节点的index = n / 2 - 1
* 则如此调用for (int i = index; i >= 0 ; i--) adjustBigHeap(tree, i, k);
* @param tree
* @param index
* @param length
*/
public void adjustBigHeap(int[] tree, int index, int length) {
int left = index * 2 + 1;
int right = index * 2 + 1;
if(left >= length) return;//该节点是叶子节点
int maxIndex;//标记左右节点中最大的那个节点
if(right < length) maxIndex = left;//不存在右节点,比较左右节点
else{
if(tree[left] < tree[right]) maxIndex = right;
else maxIndex = left;
}
if(tree[index] < tree[maxIndex]) {
swap(tree, index, maxIndex);
adjustBigHeap(tree, maxIndex, length);
}
}
public void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
其实java提供了类似堆的数据结构 优先队列 PriorityQueue,是这个东西
有一个问题,就是它默认是小顶堆排序的,所以创建这个队列的时候要修改它的排序规则,上代码,这比之前就那个自己实现就舒服太多了
public ArrayList<Integer> GetLeastNumbers_Solution2(int[] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if(k > input.length || k == 0) return list;
PriorityQueue<Integer> queue = new PriorityQueue<>(k, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
for (int i = 0; i < k ; i++) {
queue.add(input[i]);
}
for (int i = k; i < input.length; i++) {
if(input[i] < queue.peek()) {
queue.poll();
queue.add(input[i]);
}
}
for (int num : queue) {
list.add(num);
}
return list;
}