算法01-贪心算法

算法01-贪心算法

1.贪心算法-装箱问题

  1. 有一批礼物,体积为n1...n2。现在需要将这一批礼物装到体积为V的盒子中,计算最少需要多少个盒子?
  2. 算法实现思路,将礼物直接装到盒子中,如果盒子的剩余体积不够就直接打开新的盒子去装礼物。
  3. 代码实现。
/**
 * box volume is five
 * goods volume is one,two,three,four,five
 * box number that load all goods
 */
public class Boxing {

    class Box {
        int volume;
        List<Goods> goodsList;
        Box next;

        Box(int volume, List<Goods> goodsList) {
            this.volume = volume;
            this.goodsList = goodsList;
        }
    }

    class Goods {
        int volume;

        Goods(int volume) {
            this.volume = volume;
        }

        @Override
        public String toString() {
            return volume + "";
        }
    }

    public Box boxing(List<Integer> goods) {
        return boxing(goods, 5);
    }

    public Box boxing(List<Integer> goodsVolume, Integer boxVolume) {
        Box head = null;
        for (Integer volume : goodsVolume) {
            if (volume > boxVolume) {
                head = null; // GC
                throw new RuntimeException("goods volume gt box volume");
            }

            // find can user box
            Box tail = head; // cat optimization that box volume is {@link boxVolume}
            Box tailPrev = null; // use tailPrev avoid tail is null, lost box pointer
            while (tail != null && tail.volume < volume) {
                tailPrev = tail;
                tail = tail.next;
            }

            Goods goods = new Goods(volume);
            if (head == null) {
                // create first box node
                Box box = new Box(boxVolume - volume, new ArrayList<>());
                box.goodsList.add(goods);

                head = box;
            } else if (tail == null) {
                // already create box not can load goods, have to create new box
                Box box = new Box(boxVolume - volume, new ArrayList<>());
                box.goodsList.add(goods);

                tailPrev.next = box;
            } else {
                // current box node can load goods
                tail.volume -= volume;
                tail.goodsList.add(goods);
            }

        }

        return head;
    }

    public void printBox(Box head) {
        while (head != null) {
            System.out.println(head.goodsList);
            head = head.next;
        }
    }

    public static void main(String[] args) {
        Integer[] arr = {5, 4, 3, 2, 1, 4, 4, 2, 1};
        List<Integer> goodsVolume = Arrays.asList(arr);

        Boxing boxing = new Boxing();
        Box head = boxing.boxing(goodsVolume);

        boxing.printBox(head);
    }
}

2.贪心算法-哈弗曼编码

  1. 将一堆无需的文本字符串转换为01码,进行网络传输,然后再接受端在将01码转换为无序的字符串,要求使用最少的01进行网络传输。
  2. 算法思路。
    1. 根据文本中相同字符串的个数构建哈夫曼树。构建的哈夫曼树的特定,文本中出现最多的字符串对应的01的长度越小。
    2. 根据哈夫曼树将字符串压缩。
  3. 代码实现。
public class HuffmanCoding {

    static class HuffmanNode implements Comparable<HuffmanNode> {
        String str;
        int count;
        HuffmanNode left;
        HuffmanNode right;

        public HuffmanNode(String str, int count) {
            this.str = str;
            this.count = count;
        }

        public HuffmanNode(String str, int count, HuffmanNode left, HuffmanNode right) {
            this.str = str;
            this.count = count;
            this.left = left;
            this.right = right;
        }

        @Override
        public int compareTo(HuffmanNode huffmanNode) {
            return this.count - huffmanNode.count;
        }

        @Override
        public String toString() {
            return "HuffmanNode{" +
                    "str='" + str + '\'' +
                    ", count=" + count +
                    '}';
        }
    }

    public void printTree(HuffmanNode head) {
        // middle iterator
        if (head != null) {
            System.out.println(head);
            printTree(head.left);
            printTree(head.right);
        }
    }

    public Map<String, HuffmanNode> statisticsCharCount(String str) {
        Map<String, HuffmanNode> map = new HashMap<>();

        if (str == null || str.isEmpty() || !str.matches("[a-zA-Z]+"))
            throw new RuntimeException("str is null or str not match a-zA-Z");

        for (int i = 0;i < str.length();i++) {
            String s = str.substring(i, i + 1);

            if (map.containsKey(s))
                // reference add 1
                map.get(s).count += 1;
            else
                map.put(s, new HuffmanNode(s, 1));
        }
        return map;
    }

    public HuffmanNode createHuffmanTree(Map<String, HuffmanNode> charCount) {
        if (charCount == null || charCount.isEmpty())
            throw new RuntimeException("statistics char count error");

        // sort, map.values() not {@link List} instance,
        // and it is instance that {@link Values extends AbstractCollection},
        // map.values() can use Arrays.sort() sort
        Collection<HuffmanNode> collectionHuffman = charCount.values();

        // more delete and sort,so use {@link LinkedList}.
        // use {@link LinkedList} as queue that {@link HuffmanNode.count} count from small to big
        List<HuffmanNode> huffmanNodes = new LinkedList<>(collectionHuffman);
        Collections.sort(huffmanNodes);

        if (huffmanNodes.size() == 1)
            return huffmanNodes.get(0);

        int size = huffmanNodes.size();
        HuffmanNode head = null;
        while (--size > 0) {
            HuffmanNode left = huffmanNodes.get(0);
            HuffmanNode right = huffmanNodes.get(1);

            // create tree, use left add right as head
            head = new HuffmanNode("-1", left.count + right.count, left, right);

            huffmanNodes.remove(0);
            huffmanNodes.remove(0);

            // tree insert into queue head, sort faster
            huffmanNodes.add(0, head);

            // resort
            Collections.sort(huffmanNodes);
        }
        return head;
    }

    public Map<String, String> generateCoding(HuffmanNode head) {
        Map<String, String> map = new HashMap<>();
        // left use 0, right use 1
        generateCoding(head, new StringBuffer(), map);
        return map;
    }

    public void generateCoding(HuffmanNode head, StringBuffer sb, Map<String, String> map) {
        if (head != null) {
            sb.append("0"); // left add 0
            generateCoding(head.left, sb, map);
            // left delete 0 and handle leaf node, back tracking
            sb.deleteCharAt(sb.length() - 1);

            // not head note, add map that {@link node.str} and {@link node.coding(101)}
            if (!"-1".equals(head.str))
                map.put(head.str, sb.toString());

            sb.append("1"); // right add 1
            generateCoding(head.right, sb, map);
            // right delete 1 and handle leaf node, back tracking
            sb.deleteCharAt(sb.length() - 1);
        }
    }

    public String unzipString(String str) {
        int dataAndRuleDelimiter = str.indexOf("+");
        if (dataAndRuleDelimiter < 0)
            throw new RuntimeException("data or rule error");

        String data = str.substring(0, dataAndRuleDelimiter);
        String ruleString = str.substring(dataAndRuleDelimiter + 1);

        // parsing rule, map key is compression rule and map value is value
        Map<String, String> ruleMap = new HashMap<>();
        String[] splitRule = ruleString.split(";");
        for (String s : splitRule) {
            String[] rule = s.split(":");
            ruleMap.put(rule[1], rule[0]);
        }

        // paring data
        StringBuilder temp = new StringBuilder();
        StringBuilder result = new StringBuilder();
        for (int i = 0;i < data.length();i++) {
            temp.append(data.charAt(i));
            if (ruleMap.containsKey(temp.toString())) {
                result.append(ruleMap.get(temp.toString()));
                temp.delete(0, temp.length());
            }
        }
        return result.toString();
    }

    public String stringCompression(String str) {
        Map<String, HuffmanNode> charCount = statisticsCharCount(str);

        HuffmanNode head = createHuffmanTree(charCount);
        Map<String, String> coding = generateCoding(head);

        // compression data
        StringBuilder sb = new StringBuilder();
        for (int i = 0;i < str.length();i++) {
            String key = str.substring(i, i + 1);
            if (coding.containsKey(key))
                sb.append(coding.get(key));
            else
                throw new RuntimeException("data error");
        }

        // add compression rule
        // separation data and rule
        sb.append("+");
        for (String key : coding.keySet())
            sb.append(key).append(":").append(coding.get(key)).append(";");

        return sb.toString();
    }

    public static void main(String[] args) {
        HuffmanCoding huffmanCoding = new HuffmanCoding();
        String s = "aacabcabcd";

        // compression data
        String compression = huffmanCoding.stringCompression(s);
        System.out.println(compression);

        // parsing data
        String unzipString = huffmanCoding.unzipString(compression);
        System.out.println(unzipString);
        System.out.println(unzipString.equals(s));
    }
}
posted @ 2022-05-28 15:56  行稳致远方  阅读(37)  评论(0)    收藏  举报