CS-Notes/docs/notes/算法 - 其它.md

146 lines
5.7 KiB
Java
Raw Normal View History

2019-04-21 10:36:08 +08:00
<!-- GFM-TOC -->
2019-03-27 20:57:37 +08:00
* [汉诺塔](#汉诺塔)
* [哈夫曼编码](#哈夫曼编码)
2019-04-21 10:36:08 +08:00
<!-- GFM-TOC -->
2019-03-08 23:06:28 +08:00
2019-03-27 20:57:37 +08:00
# 汉诺塔
2019-04-25 18:43:33 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/69d6c38d-1dec-4f72-ae60-60dbc10e9d15.png" width="300"/> </div><br>
2019-03-27 20:57:37 +08:00
有三个柱子分别为 frombufferto需要将 from 上的圆盘全部移动到 to 并且要保证小圆盘始终在大圆盘上
2019-03-08 23:06:28 +08:00
这是一个经典的递归问题分为三步求解
2019-03-27 20:57:37 +08:00
n-1 个圆盘从 from -> buffer
2019-03-08 23:06:28 +08:00
2019-04-25 18:43:33 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f9240aa1-8d48-4959-b28a-7ca45c3e4d91.png" width="300"/> </div><br>
2019-03-08 23:06:28 +08:00
2019-03-27 20:57:37 +08:00
1 个圆盘从 from -> to
2019-03-08 23:06:28 +08:00
2019-04-25 18:43:33 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f579cab0-3d49-4d00-8e14-e9e1669d0f9f.png" width="300"/> </div><br>
2019-03-08 23:06:28 +08:00
2019-03-27 20:57:37 +08:00
n-1 个圆盘从 buffer -> to
2019-03-08 23:06:28 +08:00
2019-04-25 18:43:33 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/d02f74dd-8e33-4f3c-bf29-53203a06695a.png" width="300"/> </div><br>
2019-03-08 23:06:28 +08:00
如果只有一个圆盘那么只需要进行一次移动操作
2019-03-27 20:57:37 +08:00
从上面的讨论可以知道a<sub>n</sub> = 2 * a<sub>n-1</sub> + 1显然 a<sub>n</sub> = 2<sup>n</sup> - 1n 个圆盘需要移动 2<sup>n</sup> - 1
2019-03-08 23:06:28 +08:00
```java
2019-03-27 20:57:37 +08:00
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");
}
2019-03-08 23:06:28 +08:00
}
```
```html
2019-03-27 20:57:37 +08:00
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
2019-03-08 23:06:28 +08:00
```
2019-03-27 20:57:37 +08:00
# 哈夫曼编码
2019-03-08 23:06:28 +08:00
根据数据出现的频率对数据进行编码从而压缩原始数据
例如对于一个文本文件其中各种字符出现的次数如下
2019-03-27 20:57:37 +08:00
- a : 10
- b : 20
- c : 40
- d : 80
2019-03-08 23:06:28 +08:00
2019-03-27 20:57:37 +08:00
可以将每种字符转换成二进制编码例如将 a 转换为 00b 转换为 01c 转换为 10d 转换为 11这是最简单的一种编码方式没有考虑各个字符的权值出现频率而哈夫曼编码采用了贪心策略使出现频率最高的字符的编码最短从而保证整体的编码长度最短
2019-03-08 23:06:28 +08:00
首先生成一颗哈夫曼树每次生成过程中选取频率最少的两个节点生成一个新节点作为它们的父节点并且新节点的频率为两个节点的和选取频率最少的原因是生成过程使得先选取的节点位于树的更低层那么需要的编码长度更长频率更少可以使得总编码长度更少
2019-03-27 20:57:37 +08:00
生成编码时从根节点出发向左遍历则添加二进制位 0向右则添加二进制位 1直到遍历到叶子节点叶子节点代表的字符的编码就是这个路径编码
2019-03-08 23:06:28 +08:00
2019-04-25 18:43:33 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8edc5164-810b-4cc5-bda8-2a2c98556377.jpg" width="300"/> </div><br>
2019-03-08 23:06:28 +08:00
```java
2019-03-27 20:57:37 +08:00
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);
}
2019-03-08 23:06:28 +08:00
}
```
2019-03-27 20:57:37 +08:00
2019-06-13 13:31:54 +08:00
# 微信公众号
2019-06-10 11:23:18 +08:00
2019-06-18 00:57:23 +08:00
更多精彩内容将发布在微信公众号 CyC2018 你也可以在公众号后台和我交流学习和求职相关的问题另外公众号提供了该项目的 PDF 等离线阅读版本后台回复 "下载" 即可领取公众号也提供了一份技术面试复习大纲不仅系统整理了面试知识点而且标注了各个知识点的重要程度从而帮你理清多而杂的面试知识点后台回复 "大纲" 即可领取我基本是按照这个大纲来进行复习的对我拿到了 BAT 头条等 Offer 起到很大的帮助你们完全可以和我一样根据大纲上列的知识点来进行复习就不用看很多不重要的内容也可以知道哪些内容很重要从而多安排一些复习时间
2019-06-10 11:23:18 +08:00
2019-10-24 02:09:52 +08:00
<div align="center"><img width="350px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码.png"></img></div>