堆排序:
一般使用大顶堆升序排列
使用小顶堆降序排列
下图为代码测试的树(数组格式)
堆降序代码实现:
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int[] arr = { 4, 6, 8, 5, 9 };
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void heapSort(int[] arr) {
int temp;
// 调整树的结构,从arr.length/2-1一直到头节点
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjust(arr, arr.length, i);
}
// 开始交换
// 交换总长度 - 1 次
for (int j = arr.length - 1; j > 0; j--) {
temp = arr[0];
arr[0] = arr[j];
arr[j] = temp;
//由于顶部数据被交换,所以从顶部开始,整棵树都需要重新调整
//由于有调整过一次的基础,树的结构没有太大改变,所以只要将顶部的数据下移,再调整一次就足够了
adjust(arr, j, 0);
}
}
/**
* 功能:完成将 i 对应的叶子结点的树调整成大顶堆 调整的时候都是从底层开始的
*
* @param arr
* @param length
*/
public static void adjust(int[] arr, int length, int i) {
// 线取出当前元素的值,保存再临时变量
int temp = arr[i];
// 开始调整
// k的值为某个结点的右子节点
for (int k = i * 2 + 1; k < length; k = 2 * k + 1) {
if (k + 1 < length && arr[k] < arr[k + 1]) {
k++;
}
if (arr[k] > temp) {// 如果子节点大于父节点
arr[i] = arr[k];// 把较大的值赋给当前结点
i = k;// !!! i指向 k,继续循环比较,
} else {
break;
}
// 当for循环后,i为父节点的树的最大值放在顶点了
arr[i] = temp;// 将temp放在最后的为止
}
}
}
哈夫曼树:
构成哈夫曼树的步骤:
构建哈夫曼树代码(使用ArrayList集合):
import java.util.ArrayList;
import java.util.Collections;
public class HuffmanTree {
public static void main(String[] args) {
int[] arr = { 13, 7, 8, 3, 29, 6, 1 };
Node node = createHuffmanTree(arr);
}
public static Node createHuffmanTree(int[] arr) {
// 第一步为了操作方便
// 1.遍历arr数组
// 2.将arr中每个元素够构成一个Node对象
// 3.使用ArrayList管理Node
ArrayList<Node> list = new ArrayList<Node>();
for (int value : arr) {
list.add(new Node(value));
}
Collections.sort(list);
while (list.size() != 1) {
// 取出最小值(不一定小就为左子树,没有要求)
Node leftNode = list.get(0);
// 取出次小值
Node rightNode = list.get(1);
// 构建新的Node结点
Node parentNode = new Node(leftNode.value + rightNode.value);
// 构建父子结点的关系
parentNode.leftNode = leftNode;
parentNode.rightNode = rightNode;
// 删除list中的最小和慈孝
list.remove(leftNode);
list.remove(rightNode);
// 加入新创建的结点
list.add(parentNode);
Collections.sort(list);
}
// System.out.println(list);
return list.get(0);
}
}
//为了让Node对象持续排序Collections集合排序
//让Node实现Comparable接口
class Node implements Comparable<Node> {
public int value;
public Node leftNode;
public Node rightNode;
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node [value=" + value + "]";
}
@Override
public int compareTo(Node o) {
// 表示从小到大排序
return this.value - o.value;
}
}
哈夫曼编码:
如何编码:
哈夫曼编码代码实现(编码和解码):
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class HuffmanCode {
public static void main(String[] args) {
String string = "i like like like java do you like a java";
byte[] zip = getHuffmanBytes(string);
byte[] decode = decode(huffmanCodes,zip);
String string2 = new String(decode);
System.out.println(string2);
}
public static byte[] decode(Map<Byte, String> huffmanCodes, byte[] huffmanBytes) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < huffmanBytes.length; i++) {
byte b = huffmanBytes[i];
// 需要一个flag来判断是否是最后一个,可能要补高位
boolean flag = (i == huffmanBytes.length - 1);
stringBuilder.append(byteToBitString(!flag, b));
}
// 将哈夫曼标的key和value颠倒过来,便于后续步骤
Map<String, Byte> map = new HashMap<String, Byte>();
for (Entry<Byte, String> entry : huffmanCodes.entrySet()) {
map.put(entry.getValue(), entry.getKey());
}
// 此时stringBuilder的值为二进制(字符串表示)
// 创建集合类,存放byte
List<Byte> list = new ArrayList<>();
// i用来扫描stringBuilder
for (int i = 0; i < stringBuilder.length();) {
int count = 1;// 计数器
boolean flag = true;// 用来控制退出循环扫描
Byte b = null; // 用来存放获取到的byte值
while (flag) {
String key = stringBuilder.substring(i, i + count);
// 试着获取
b = map.get(key);
// 说明没有匹配到
if (b == null) {
// 增加长度,继续尝试
count++;
} else {
// 匹配成功,flag设置为false
flag = false;
}
}
list.add(b);
// 更新i的值,从下一个位置开始找
i += count;
}
// 到这里为止,list中存放着所有byte
byte[] b = new byte[list.size()];
for (int i = 0; i < list.size(); i++) {
b[i] = list.get(i);
}
return b;
}
/**
* 将一个byte转成一个二进制的字符串
*
* @param flag 标志是否需要补高位如果是true,表示需要补高位,如果时false表示不补
* @param b 传入的byte
* @return 是b的二进制的字符串
*/
public static String byteToBitString(Boolean flag, byte b) {
// 使用变量保存b
int temp = b;// 将b转成int
// 如果是正数我们还存在
// 这里返回的时补码
if (flag) {
temp |= 256;
}
String string = Integer.toBinaryString(temp);
if (flag) {
return string.substring(string.length() - 8);
} else {
return string;
}
}
public static byte[] getHuffmanBytes(String string) {
byte[] bytes = string.getBytes();
List<Node2> nodes = getNodes(bytes);
Node2 root = createHuffmantree(nodes);
getCodes(root, "", stringBuilder);
byte[] zip = zip(bytes, huffmanCodes);
return zip;
}
/**
*
* @param bytes 原始的字符串对应的byte[]
* @param hufmanCodes 生成的哈夫曼编码
* @return 处理后的byte[]
*/
public static byte[] zip(byte[] bytes, Map<Byte, String> hufmanCodes) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
stringBuilder.append(hufmanCodes.get(bytes[i]));
}
// 将01字符串转为字节数组
int len;
if (stringBuilder.length() % 8 == 0) {
len = stringBuilder.length() / 8;
} else {
len = stringBuilder.length() / 8 + 1;
}
byte[] by = new byte[len];
int index = 0;
String string;
for (int i = 0; i < stringBuilder.length(); i += 8) {
if (i + 8 < stringBuilder.length()) {
string = stringBuilder.substring(i, i + 8);
} else {
string = stringBuilder.substring(i);
}
by[index++] = (byte) Integer.parseInt(string, 2);
}
return by;
}
static Map<Byte, String> huffmanCodes = new HashMap<Byte, String>();
static StringBuilder stringBuilder = new StringBuilder();
/**
* 功能:将传入的node结点时所有叶子结点时的赫夫曼树
*
* @param node 传入结点
* @param code 路径:左子节点是0 ,右子节点 1
* @param stringBuilder 用于拼接路径
*/
public static void getCodes(Node2 node, String code, StringBuilder stringBuilder) {
// 为每一个结点都创建一个StringBuilder
StringBuilder stringBuilder2 = new StringBuilder(stringBuilder);
stringBuilder2.append(code);
if (node != null) {// 如果node等于null不处理
if (node.dataByte == null) {// 非叶子结点
getCodes(node.leftNode, "0", stringBuilder2);
getCodes(node.rightNode, "1", stringBuilder2);
} else {
huffmanCodes.put(node.dataByte, stringBuilder2.toString());
}
}
}
public static List<Node2> getNodes(byte[] bytes) {
ArrayList<Node2> list = new ArrayList<Node2>();
HashMap<Byte, Integer> map = new HashMap<Byte, Integer>();
for (int i = 0; i < bytes.length; i++) {
if (!map.containsKey(bytes[i])) {
map.put(bytes[i], 1);
} else {
map.put(bytes[i], map.get(bytes[i]) + 1);
}
}
for (Entry<Byte, Integer> setMap : map.entrySet()) {
list.add(new Node2(setMap.getKey(), setMap.getValue()));
}
return list;
}
public static Node2 createHuffmantree(List<Node2> list) {
while (list.size() != 1) {
Collections.sort(list);
Node2 leftNode = list.get(0);
Node2 rightNode = list.get(1);
Node2 parentNode = new Node2(leftNode.weight + rightNode.weight);
parentNode.leftNode = leftNode;
parentNode.rightNode = rightNode;
list.remove(leftNode);
list.remove(rightNode);
list.add(parentNode);
}
return list.get(0);
}
}
class Node2 implements Comparable<Node2> {
Byte dataByte;
int weight;
Node2 rightNode;
Node2 leftNode;
public Node2(Byte dataByte, int weight) {
this.dataByte = dataByte;
this.weight = weight;
}
public Node2(int weight) {
this.weight = weight;
}
@Override
public int compareTo(Node2 o) {
// TODO Auto-generated method stub
// 从小到大排序
return this.weight - o.weight;
}
@Override
public String toString() {
return "Node [dataByte=" + dataByte + ", weight=" + weight + "]";
}
}