堆结构非常重要。因此特别记录一下有关堆结构的知识点。
1.最重要的堆排序问题:
java参考代码如下:
package chapter2;
public class P79_heapSort {
public static void heapSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 0; i < arr.length; i++) {
heapInsert(arr, i);//maxHeap
}
int size = arr.length;
swap(arr, 0, --size);
while (size > 0) {
heapify(arr, 0, size);
swap(arr, 0, --size);//从末尾开始,每次搞定一个数
}
}
public static void heapInsert(int[] arr, int index) {//maxHeap
while (arr[index] > arr[(index - 1) / 2]) {
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
public static void heapify(int[] arr, int index, int size) {//size-->heapSize
int left = index * 2 + 1;
while (left < size) {
int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;//left+1--->right
largest = arr[largest] > arr[index] ? largest : index;
if (largest == index) {
break;
}
swap(arr, largest, index);
index = largest;
left = index * 2 + 1;
}
}
public static void swap(int[] arr,int i,int j){
arr[i]=arr[i]^arr[j];
arr[j]=arr[i]^arr[j];
arr[i]=arr[i]^arr[j];
}
public static void main(String[] args) {
int[] arr={1,3,5,7,9,2,4,6,8};
heapSort(arr);
for(int num:arr){
System.out.print(num+" ");
}
}
}
2.哈夫曼问题中的小根堆。
一块金条切成两半, 是需要花费和长度数值一样的铜板的。 比如
长度为20的 金条, 不管切成长度多大的两半, 都要花费20个铜
板。 一群人想整分整块金 条, 怎么分最省铜板?
例如,给定数组{10,20,30}, 代表一共三个人, 整块金条长度为
10+20+30=60. 金条要分成10,20,30三个部分。 如果, 先把长
度60的金条分成10和50, 花费60 再把长度50的金条分成20和30,
花费50 一共花费110铜板。
但是如果, 先把长度60的金条分成30和30, 花费60 再把长度30
金条分成10和20, 花费30 一共花费90铜板。
输入一个数组, 返回分割的最小代价。
思路:
将输入的数组全部放到小根堆里面,每次取小的两个,所得的和再放入堆中,途中记录累加和,知道堆中只剩下一个。
java参考代码如下:
package zuoshen1;
import java.util.Comparator;
import java.util.PriorityQueue;
public class HuffmanTree {
public static int lessMoney(int[] arr){
if(arr==null||arr.length<1)
throw new RuntimeException("arr is null!");
PriorityQueue<Integer> pq=new PriorityQueue<>(new MinheapComparator());//可以默认,默认为小根堆
for(int i=0;i<arr.length;i++){
pq.add(arr[i]);
}
int sum=0,cur=0;
while (pq.size()>1){//==1 break
cur=pq.poll()+pq.poll();
sum+=cur;
pq.add(cur);
}
return sum;
}
public static class MinheapComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2; // < 0 o1 < o2 负数
}
}
public static class MaxheapComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1; // < o2 < o1
}
}
public static void main(String[] args) {
System.out.println(lessMoney(new int[]{10,20,30}));
}
}
3.输入: 参数1, 正数数组costs 参数2, 正数数组profits 参数3,
正数k 参数4, 正数m
costs[i]表示i号项目的花费 profits[i]表示i号项目在扣除花
费之后还能挣到的钱(利润) k表示你不能并行、 只能串行的最多
做k个项目 m表示你初始的资金
说明: 你每做完一个项目, 马上获得的收益, 可以支持你去做下
一个 项目。
输出: 你最后获得的最大钱数。
思路:
投资,你有当前资金W,你一共可以投资K次,且每次只能投一个。我们用两个堆来解决这个问题,小根堆根据项目的cost来建立,大根堆根据每个项目的profit来建立。我们将小根堆中cost小于当前W的项目放到大根堆中,再根据大根堆的构建原理,从中拿出最大收益的进行投资,直到大根堆为空,或者投资K个截止。
java参考代码如下:
package zuoshen1;
import java.util.Comparator;
import java.util.PriorityQueue;
public class FindMaximizedCapital {
public static class Node{
int c;
int p;
public Node(int c,int p){
this.c=c;
this.p=p;
}
}
public static class MinComparator implements Comparator<Node>{
@Override
public int compare(Node o1,Node o2){
return o1.c-o2.c;//min cost
}
}
public static class MaxComparator implements Comparator<Node>{
@Override
public int compare(Node o1,Node o2){
return o2.p-o1.p;//max profit
}
}
public static int findMaximizedCapital(int k,int w,int[] cost,int[] profit){
if(k<0||w<0||cost==null||profit==null||cost.length!=profit.length)
throw new RuntimeException("run exception!");
Node[] nodes=new Node[cost.length];
PriorityQueue<Node> minQ=new PriorityQueue<>(new MinComparator());
PriorityQueue<Node> maxQ=new PriorityQueue<>(new MaxComparator());
for(int i=0;i<cost.length;i++){
nodes[i]=new Node(cost[i],profit[i]);
}
for(int i=0;i<cost.length;i++){
minQ.add(nodes[i]);
}
for(int i=0;i<k;i++){
while (!minQ.isEmpty()&&minQ.peek().c<=w){//w>=cost[i]//w 是当前的资金,一直在增
maxQ.add(minQ.poll());
}
if(maxQ.isEmpty()){
return w;
}
//else maxQ is not empty!
w+=maxQ.poll().p;
}
return w;
}
public static void main(String[] args) {
int[] cost={5,6,7,8,9,20};
int[] profit={1,2,3,5,6,10};
int w=10;
int k1=4;
int k2=6;
System.out.println(findMaximizedCapital(k1,w,cost,profit));
System.out.println(findMaximizedCapital(k2,w,cost,profit));
}
}