数组构建堆结构(以大根堆为例)
package com.zzf.algorithm;
/**
* @author zzf
* @date 2022-01-28
*/
public class Heap {
public static class MyMaxHeap{
private int[] heap;
private final int limit;
private int heapSize;
public MyMaxHeap(int limit){
heap = new int[limit];
this.limit = limit;
heapSize = 0;
}
public boolean isEmpty(){
return heapSize == 0;
}
public boolean isFull(){
return heapSize == limit;
}
public void push(int value){
if(heapSize == limit){
throw new RuntimeException("堆满");
}
heap[heapSize] = value;
heapInsert(heap,heapSize++);
}
public int pop(){
int ans = heap[0];
swap(heap,0,--heapSize);//最后位置和起始位置交换
heapfy(heap,0,heapSize);//不断下沉大根堆调整
return ans;
}
//堆排序
public void heapSort(int[] heap){
if(heap == null || heap.length < 2){
return;
}
//构建堆结构
//第一种,一个一个加入构建,从上往下O(N*logN)
/*for (int i = 0;i < heap.length-1;i++){
heapInsert(heap,i);
}*/
//第二种,直接在有数据的情况下,从底层到上层依次构建O(N)
for (int i = heap.length-1; i >= 0; i--) {
heapfy(heap,i,heap.length);
}
//不断交换并构建堆结构,大的值被放到后面
int heapSize = heap.length;
swap(heap,0,--heapSize);
while (heapSize > 0){
heapfy(heap,0,heapSize);
swap(heap,0,--heapSize);
}
}
private void heapfy(int[] heap, int index, int heapSize) {
int left = index * 2 + 1;
//有左孩子的前提下
while (left < heapSize){
//保留较大孩子的下标
int largest = left+1 < heapSize && heap[left+1] > heap[left] ? left + 1 : left;
//当前位置和较大位置比较
largest = heap[largest] > heap[index] ? largest : index;
if(largest == index){ //当前位置就是最大的了,不用调整
break;
}
swap(heap,largest,index);//交换调整
index = largest;
left = index * 2 + 1;
}
}
//新加入的值,放在index位置,然后向上移动调整为大根堆
private void heapInsert(int[] heap, int index) {
//不断向上调整,直到index为0或干不过父结点
while (heap[index] > heap[(index - 1) / 2]){
swap(heap,index,(index - 1) / 2);
index = (index - 1) / 2;
}
}
private void swap(int[] heap, int a, int b) {
int tmp = heap[a];
heap[a] = heap[b];
heap[b] = tmp;
}
}
}
利用堆完成的条件排序
思路:构建一个小根堆,保证里面最多放k个数(要注意数组大小和k的大小),先把0-k-1位置的数放进去,依次弹出一个最小值,放到0位置,然后再加入k位置的数,然后循环。直到没有数可以加了,而且堆中还有数的话,就依次弹出放到相应位置,这样就保证每个数排序前后移动距离不超过k
package com.zzf.algorithm;
import java.util.PriorityQueue;
/**
* @author zzf
* @date 2022-01-29
*/
public class SortArrayDistanceLessK {
//对一个数组排序,让数在排序前后移动距离不超过k
public static void sortedArrDistanceLessK(int[] arr, int k){
if(k == 0)
{
return;
}
//小根堆
PriorityQueue<Integer> heap = new PriorityQueue<>();
int index = 0;
//把前k个数加入小根堆
for(;index <= Math.min(arr.length - 1, k - 1);index++){
heap.add(arr[index]);
}
int i = 0;
for(;index < arr.length;i++,index++){
//弹出一个数,放到i位置
arr[i] = heap.poll();
heap.add(arr[index]);//加入下一个数
}
//没有数可以加了,就把堆中剩余的数弹出放到i位置
while (!heap.isEmpty()){
arr[i++] = heap.poll();
}
}
}
堆优化,针对非基础类型,堆中元素的内容会动态变化,以小根堆为例
package com.zzf.algorithm;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
/**
* @author zzf
* @date 2022-01-29
*/
public class HeapGreater<T> {
private ArrayList<T> heap;
private HashMap<T,Integer> indexMap;
private int heapSize;
private Comparator<? super T> comp;
public HeapGreater(Comparator<T> c){
heap = new ArrayList<>();
indexMap = new HashMap<>();
heapSize = 0;
comp = c;
}
public boolean isEmpty(){
return heapSize == 0;
}
public int size(){
return heapSize;
}
//判断堆中是否包含某个值
public boolean contains(T obj){
return indexMap.containsKey(obj);
}
public T peek(){
return heap.get(0);
}
public void push(T obj){
heap.add(obj);
indexMap.put(obj,heapSize);//记录值在堆中的位置
heapInsert(heapSize++);
}
public T pop(){
T ans = heap.get(0);
swap(0,heapSize - 1);
indexMap.remove(ans);
heap.remove(--heapSize);
heapify(0); //调整堆
return ans;
}
//移除堆中某个元素
public void remove(T obj){
//先保存起最后一个结点值
T replace = heap.get(heapSize - 1);
//map中把该结点删除
int index = indexMap.get(obj);
indexMap.remove(obj);
//heap把最后结点移除
heap.remove(--heapSize);
if(obj != replace){
//相当于最后结点和要移除的结点交换了
heap.set(index,replace);
indexMap.put(replace,index);
//调整堆
resign(replace);
}
}
//更新内容后要做的调整操作
public void resign(T obj){
int index = indexMap.get(obj);
heapInsert(index);
heapify(index);
}
private void heapify(int index) {
int left = index * 2 + 1;
while (left < heapSize){
int best = left + 1 < heapSize &&
comp.compare(heap.get(left + 1),heap.get(left)) < 0 ? (left + 1) : left;
best = comp.compare(heap.get(index),heap.get(best)) < 0 ? best : index;
if(best == index){
break;
}
swap(best,index);
index = best;
left = index * 2 + 1;
}
}
private void heapInsert(int index) {
while(comp.compare(heap.get(index),heap.get((index - 1) / 2)) < 0){
swap(index,(index - 1) / 2);
index = (index - 1) / 2;
}
}
private void swap(int i, int j) {
T o1 = heap.get(i);
T o2 = heap.get(j);
//修改对应位置的值
heap.set(i,o2);
heap.set(j,o1);
//更新map信息
indexMap.put(o2,i);
indexMap.put(o1,j);
}
}