一.堆排序
1.将较小的值放在叶子节点
public static void adjustHeap(int arr[], int i, int length) {
int temp = arr[i];
for (int k = i * 2 + 1; k < length; k = k + 2 + 1) {
if (k + 1 < length && arr[k] < arr[k + 1]) {
k++;// 指向右子结点
}
if (arr[k] > temp) {
arr[i] = arr[k];
i = k;
} else {
break;
}
}
arr[i] = temp;
}
2.进行排序
public static void sort(int[] arr) {
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, arr.length);
}
System.out.println(Arrays.toString(arr));//得到大顶堆
for (int i = arr.length - 1; i >= 0; i--) {
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
adjustHeap(arr, 0, i);
}
System.out.println(Arrays.toString(arr));
}
二.得到哈夫曼编码
1.获得每个字符的数量
public static List<Node> getNodes(byte[] bytes) {
ArrayList<Node> nodes = new ArrayList<>();
HashMap<Byte, Integer> map = new HashMap<>();
for (byte b : bytes) {
Integer count = map.get(b);
if (count == null) {
map.put(b, 1);
} else {
map.put(b, count + 1);
}
}
for (Map.Entry<Byte, Integer> entry : map.entrySet()) {
nodes.add(new Node(entry.getKey(), entry.getValue()));
}
return nodes;
}
2.创建哈夫曼树
public static Node createHuffmanTree(List<Node> nodes) {
while (nodes.size() > 1) {
Collections.sort(nodes);
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
Node parent = new Node(null, leftNode.weight + rightNode.weight);
parent.left = leftNode;
parent.right = rightNode;
nodes.remove(leftNode);
nodes.remove(rightNode);
nodes.add(parent);
}
return nodes.get(0);
}
3.获得哈夫曼编码
public static void getCodes(Node node, String code, StringBuilder stringBuilder) {
StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
// 拼接上一轮的code
stringBuilder1.append(code);
if (node != null) {
if (node.date == null) {// 非叶子结点
// 向左递归
getCodes(node.left, "0", stringBuilder1);
// 向右递归
getCodes(node.right, "1", stringBuilder1);
} else {
huffmanCodes.put(node.date, stringBuilder1.toString());
}
}
}
4.进行压缩
public static byte[] zip(byte[] bytes, Map<Byte, String> huffmanCodes) {
StringBuilder stringBuilder = new StringBuilder();
for (byte b : bytes) {
stringBuilder.append(huffmanCodes.get(b));
}
int len;
if (stringBuilder.length() % 8 == 0) {
len = stringBuilder.length() / 8;
} else {
len = stringBuilder.length() / 8 + 1;
}
// 存储压缩后的byte数组
byte[] huffmanCodeBytes = new byte[len];
int index = 0;
for (int i = 0; i < stringBuilder.length(); i += 8) {
String strByte;
if (i + 8 > stringBuilder.length()) {
strByte = stringBuilder.substring(i);
} else {
strByte = stringBuilder.substring(i, i + 8);
}
// 将strByte 转成byte,放入到huffmanCodeBytes
huffmanCodeBytes[index] = (byte) Integer.parseInt(strByte, 2);
index++;
}
return huffmanCodeBytes;
}
二.进行解码
1.对压缩后文件进行解码
public static String byteToBitString(boolean flag,byte b){
int temp=b;
if (flag){
temp |=256;// 按位与
}
// 返回二进制补码
String str=Integer.toBinaryString(temp);
if (flag){
return str.substring(str.length()-8);
}else {
return str;
}
}
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];
boolean flag=(i== huffmanBytes.length-1);
stringBuilder.append(byteToBitString(!flag,b));
}
// 反向查询
// 将字符串按照指定哈夫曼编码进行解码
HashMap<String, Byte> map = new HashMap<>();
for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) {
map.put(entry.getValue(),entry.getKey());
}
// 存放byte
ArrayList<Byte> list = new ArrayList<>();
for (int i = 0; i < stringBuilder.length(); ) {
int count=1;
boolean flag=true;
Byte b=null;
while (flag){
String key = stringBuilder.substring(i, i + count);
b=map.get(key);
if (b==null){
count++;
}else {
flag=false;
}
}
list.add(b);
i+=count;
}
byte[] b = new byte[list.size()];
for (int i = 0; i < b.length; i++) {
b[i]=list.get(i);
}
return b;
}