金条分割+最小堆实现

金条分割问题:

采用优先级队列实现的,这里的优先级队列默认按照最小堆生成。所以可以不用定义比较器。等价--如注释

如果需要大根堆的话,就需要定义比较器。

package day5;

import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;


/*
 * 一块金条切两块,需要花费和长度数值一样的铜板。怎么分最省铜板。
 * eg:    给定数组{10,20,30}代表三个人,整块金条长度就是10+20+30=60,
 *         分成数组中的10,20,30三个部分。最优解是先分30+40 再分10+20共需90个铜板
 * 
 * 实质是哈夫曼编码,每次取出两个最小的相加相加放回数组,依次进行到数组元素只剩下一个
 * 此时就是最小代价
 * 
 * 知道但是不会编码,就很尬了
 * 
 * !!!!!!!知识点:!!!!!!!!!!!
 * 这种在数组中取最大、最小再放回的,考虑堆结构。
 * 当总和可以表示成分的和或者乘的时候,考虑哈弗曼编码
 * 
 */
public class Code03_GoldBarSegmentation {

    public static void main(String[] args) {
        int arr[] = {10,20,30};
        System.out.println(Hoffmann(arr ));
    }


    public static class minHeapComparator implements Comparator<Integer>{

        @Override
        public int compare(Integer arg0, Integer arg1) {
            return arg0 - arg1;
        }
        
    }
    public static int Hoffmann(int arr []) {
        //PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        PriorityQueue<Integer> minHeap = new PriorityQueue<>(new minHeapComparator());
        for(int i = 0 ; i <arr.length ;i ++) {
            minHeap.add(arr[i]);
        }
        int sum =0;
        while(minHeap.size() >1) {
            int cur = minHeap.poll()+minHeap.poll();
            sum += cur;
            minHeap.add(cur);
        }
        return sum;
    }
    

    
}

最小堆实现:

  

// 自己堆快忘了,手写一个,复习

// 从小到大排序,需要大根堆实现
// 从大到小排序,用小根堆实现

/*
* 小根堆: 
* hoopinsert:加入一个新节点,调整(向上)
* heapify:一个数变大之后往下调,往下调,往下调 
* 1.左右孩子是否存在?
* 2、找到左右孩子中最小的那个,跟当前节点比较,若小就交换,否在停止 heapSort
*/

public static class MyHeap {        

        public static  void swap(int arr[], int i, int j) {
            int temp = arr[j];
            arr[j] = arr[i];
            arr[i] = temp;
        }

        public static  void heapify(int arr[], int size, int index) {
            int left = index * 2 + 1;
            while (left < size) {// 保证孩子存在
                // 保证右孩子存在的情况下
                int childmin = (left + 1 < size && arr[left + 1] < arr[left]) ? left + 1 : left;
                childmin = arr[childmin] < arr[index] ? childmin : index;
                if (childmin == index)
                    break;
                swap(arr, childmin, index);
                index = childmin;
                left = index * 2 + 1;
            }
        }

        public static  void hoopinsert(int arr[], int index) {
            int father = (index - 1) / 2;
            while (arr[father] > arr[index]) {
                swap(arr, father, index);
                index = father;
                father = (index - 1) / 2;
            }
        }

        public static  void heapSort(int arr[]) {
            if (arr == null || arr.length < 2)
                return;
            // 建立小根堆
            for (int i = 0; i < arr.length; i++) {
                hoopinsert(arr, i);
            }
            // 排序,需要从小根堆中每次取堆顶,然后跟最后一个数交换。size-1,重新排一遍。
            //将size = arr.length-1 ,        --size换成--size,跑出来结果是错的。
            //没弄明白
            
            int size = arr.length;
            swap(arr, --size, 0);
            while (size > 0) {
                heapify(arr, size, 0);
                swap(arr, --size, 0);
            }

        }

        // for test
        public static int[] generateRandomArray(int maxSize, int maxValue) {

            int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
            for (int i = 0; i < arr.length; i++) {
                arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
            }

            return arr;
        }

        public static int[] copyArray(int arr[]) {
            if (arr == null) {
                return null;
            }
            int[] res = new int[arr.length];
            for (int i = 0; i < arr.length; i++) {
                res[i] = arr[i];
            }
            return res;

        }

        public static void print(int arr[]) {
            for (int i = 0; i < arr.length; i++) {
                System.out.print(arr[i] + " ");
            }
            System.out.println();

        }
        
        public static void comparator(int arr[]) {
            Arrays.sort(arr);
            for (int i = 0 ; i <arr.length/2;i ++) {
                swap(arr,i,arr.length-1-i);
            }
        }

        public static boolean isEqual(int arr[], int res[]) {
            if ((arr == null && res != null) || (arr != null && res == null))
                return false;
            if (arr == null && res == null)
                return true;
            if (arr.length != res.length)
                return false;
            for (int i = 0; i < arr.length; i++) {
                if (arr[i] != res[i])
                    return false;
            }
            return true;
        }

        public static void main(String[] args) {

            int maxSize = 30;
            int maxValue = 100;
            int testTime = 1000;
            boolean suceed = true;
            //int arr[] = { 6, 12, 3, 8, 4, 1, 2, 9 };
            //heapSort(arr);
            //print(arr);

            for (int i = 0; i < testTime; i++) {
                int[] arr1 = generateRandomArray(maxSize, maxValue);
                int[] arr2 = copyArray(arr1);

                heapSort(arr1);
                comparator(arr2);
                if (!isEqual(arr1, arr2)) {
                    suceed = false;
                    // System.out.println("********************");
                    print(arr1);
                    print(arr2);
                    break;

                }

            }
            System.out.println(suceed ? "Nice!" : "Flucking Fucked !");
        }
    }
    
 

遇到一个问题:

我本来想将自己写的堆放到金条分隔中使用,于是就直接把  MyHeap类 放进了GoldBarSegmentation类 里面,没写GoldBarSegmentation类 的主函数,运行MyHeap类成功后写了删掉 MyHeap类主函数,写GoldBarSegmentation类 主函数之后提示“找不到或无法加载主类 ”。即后写的主函数不被识别,即使是删掉MyHeap类,用自带的优先级队列也不行。

方法:

应该是eclipse在第一运行程序的时候记住了一些东西。通过  菜单栏 ——> run  ——>run Configurations 打开后在左侧找到对应的程序名,右击delect。

再次重新运行就可以了。

 

posted @ 2019-09-08 20:44  白清欢  阅读(530)  评论(0编辑  收藏  举报