Skip to content
百科百科
操作系统
设计模式
算法
题解
java
leetcode
  • 算法
    • /算法/算法.md
      • 算法 - 其它
        • 汉诺塔
          • 哈夫曼编码
          • 算法 - 并查集
            • 算法 - 排序
              • 算法 - 栈和队列
                • 算法 - 符号表
                  • 算法 - 算法分析
                    • 算法目录

                      算法 - 其它

                      2022年5月21日大约 3 分钟

                      此页内容
                      • 汉诺塔
                      • 哈夫曼编码

                      # 算法 - 其它

                      # 汉诺塔

                      ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/69d6c38d-1dec-4f72-ae60-60dbc10e9d15.png" width="300)

                      有三个柱子,分别为 from、buffer、to。需要将 from 上的圆盘全部移动到 to 上,并且要保证小圆盘始终在大圆盘上。

                      这是一个经典的递归问题,分为三步求解:

                      ① 将 n-1 个圆盘从 from -> buffer

                      ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f9240aa1-8d48-4959-b28a-7ca45c3e4d91.png" width="300)

                      ② 将 1 个圆盘从 from -> to

                      ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f579cab0-3d49-4d00-8e14-e9e1669d0f9f.png" width="300)

                      ③ 将 n-1 个圆盘从 buffer -> to

                      ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/d02f74dd-8e33-4f3c-bf29-53203a06695a.png" width="300)

                      如果只有一个圆盘,那么只需要进行一次移动操作。

                      从上面的讨论可以知道,an = 2 * an-1 + 1,显然 an = 2n - 1,n 个圆盘需要移动 2n - 1 次。

                      public class Hanoi {
                          public static void move(int n, String from, String buffer, String to) {
                              if (n == 1) {
                                  System.out.println("from " + from + " to " + to);
                                  return;
                              }
                              move(n - 1, from, to, buffer);
                              move(1, from, buffer, to);
                              move(n - 1, buffer, from, to);
                          }
                      
                          public static void main(String[] args) {
                              Hanoi.move(3, "H1", "H2", "H3");
                          }
                      }
                      
                      from H1 to H3
                      from H1 to H2
                      from H3 to H2
                      from H1 to H3
                      from H2 to H1
                      from H2 to H3
                      from H1 to H3
                      

                      # 哈夫曼编码

                      根据数据出现的频率对数据进行编码,从而压缩原始数据。

                      例如对于一个文本文件,其中各种字符出现的次数如下:

                      • a : 10
                      • b : 20
                      • c : 40
                      • d : 80

                      可以将每种字符转换成二进制编码,例如将 a 转换为 00,b 转换为 01,c 转换为 10,d 转换为 11。这是最简单的一种编码方式,没有考虑各个字符的权值(出现频率)。而哈夫曼编码采用了贪心策略,使出现频率最高的字符的编码最短,从而保证整体的编码长度最短。

                      首先生成一颗哈夫曼树,每次生成过程中选取频率最少的两个节点,生成一个新节点作为它们的父节点,并且新节点的频率为两个节点的和。选取频率最少的原因是,生成过程使得先选取的节点位于树的更低层,那么需要的编码长度更长,频率更少可以使得总编码长度更少。

                      生成编码时,从根节点出发,向左遍历则添加二进制位 0,向右则添加二进制位 1,直到遍历到叶子节点,叶子节点代表的字符的编码就是这个路径编码。

                      ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8edc5164-810b-4cc5-bda8-2a2c98556377.jpg" width="300)

                      public class Huffman {
                      
                          private class Node implements Comparable<Node> {
                              char ch;
                              int freq;
                              boolean isLeaf;
                              Node left, right;
                      
                              public Node(char ch, int freq) {
                                  this.ch = ch;
                                  this.freq = freq;
                                  isLeaf = true;
                              }
                      
                              public Node(Node left, Node right, int freq) {
                                  this.left = left;
                                  this.right = right;
                                  this.freq = freq;
                                  isLeaf = false;
                              }
                      
                              @Override
                              public int compareTo(Node o) {
                                  return this.freq - o.freq;
                              }
                          }
                      
                          public Map<Character, String> encode(Map<Character, Integer> frequencyForChar) {
                              PriorityQueue<Node> priorityQueue = new PriorityQueue<>();
                              for (Character c : frequencyForChar.keySet()) {
                                  priorityQueue.add(new Node(c, frequencyForChar.get(c)));
                              }
                              while (priorityQueue.size() != 1) {
                                  Node node1 = priorityQueue.poll();
                                  Node node2 = priorityQueue.poll();
                                  priorityQueue.add(new Node(node1, node2, node1.freq + node2.freq));
                              }
                              return encode(priorityQueue.poll());
                          }
                      
                          private Map<Character, String> encode(Node root) {
                              Map<Character, String> encodingForChar = new HashMap<>();
                              encode(root, "", encodingForChar);
                              return encodingForChar;
                          }
                      
                          private void encode(Node node, String encoding, Map<Character, String> encodingForChar) {
                              if (node.isLeaf) {
                                  encodingForChar.put(node.ch, encoding);
                                  return;
                              }
                              encode(node.left, encoding + '0', encodingForChar);
                              encode(node.right, encoding + '1', encodingForChar);
                          }
                      }
                      
                      编辑此页open in new window
                      上次编辑于: 2022/5/21 13:08:59
                      贡献者: yzqdev
                      上一页
                      /算法/算法.md
                      下一页
                      算法 - 并查集
                      powered by vuepress-theme-home