用java实现最小堆,并且实现以下2个题目:
- 实现堆排序
- 实现保留数据流中最大的5个数
堆排序任何情况下的时间复杂度都是O(nlgn),空间复杂度为O(1)
是不稳定的
代码如下:
import java.util.Arrays;
public class MinHeapTest {
public static void main(String[] args) {
System.out.println("第一题排序");
double[] a = new double[] {9.1,1.2,2.5,6,8,3};
MinHeap mh1 = new MinHeap(a);
mh1.heapSort();
System.out.println(Arrays.toString(a));
System.out.println("第二题保留最大的五个数");
MinHeap mh2 = new MinHeap(5);
double[] b = new double[] {100,2,5,6,120,43,23,658,250,890};
for(double i : b)
mh2.add(i);
System.out.println(mh2);
}
}
class MinHeap{
private double[] data;
private int size;//size是必须有的,因为堆得尺寸在变,数组的长度是永远不变的,在第二题中size始终等于现有数个数
public MinHeap(double[] data) {
this.data = data;
size = data.length;
}
public MinHeap(int n) {
data = new double[n];
size = 0;
}
public String toString() {
return Arrays.toString(data);
}
public void add(double x) {
if(size < data.length)
minHeapInsert(x);//下面size加过1了;
else if(x > data[0]) {
data[0] = x;
minHeapify(0);
}
}
public void minHeapInsert(double x) {
data[size++] = Double.POSITIVE_INFINITY;
minHeapInsertKey(size - 1, x);
}
public void minHeapInsertKey(int i, double x) {
data[i] = x;
while(i > 0 && data[(i-1)/2] > data[i]){//注意是while循环,i>0因为找的是父节点(不论是左还是右,(i-1)/2都是父节点下标),子不能为0
double e = data[(i-1)/2];
data[(i-1)/2] = data[i];
data[i] = e;
i = (i - 1) / 2;//迭代条件
}
}
public void heapSort() {
buildMinHeap();
for(int i = data.length-1; i > 0; i--){//0不用操作,因为留一个不用取
double e = data[0];
data[0] = data[i];
data[i] = e;
size--;
minHeapify(0);
}
}
public void buildMinHeap() {
for(int i = data.length/2; i >= 0; i--)
minHeapify(i);
}
public void minHeapify(int i) {
int l = 2 * i + 1;
int r = 2 * (i + 1);
int min = i;
if(l < size && data[l] < data[min])//必须是小于size,取不到size下标
min = l;
if(r < size && data[r] < data[min])
min = r;
if(min != i){
double e = data[i];
data[i] = data[min];
data[min] = e;
minHeapify(min);//别写到if外面了,有变动才需要最小化堆
}
}
}