算法01-贪心算法
1.贪心算法-装箱问题
- 有一批礼物,体积为n1...n2。现在需要将这一批礼物装到体积为V的盒子中,计算最少需要多少个盒子?
- 算法实现思路,将礼物直接装到盒子中,如果盒子的剩余体积不够就直接打开新的盒子去装礼物。
- 代码实现。
/**
* 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.贪心算法-哈弗曼编码
- 将一堆无需的文本字符串转换为01码,进行网络传输,然后再接受端在将01码转换为无序的字符串,要求使用最少的01进行网络传输。
- 算法思路。
- 根据文本中相同字符串的个数构建哈夫曼树。构建的哈夫曼树的特定,文本中出现最多的字符串对应的01的长度越小。
- 根据哈夫曼树将字符串压缩。
- 代码实现。
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));
}
}