堆是一个完全二叉树,每个节点的值都大于或等于左右节点的值的堆叫大顶堆,小于左右节点的值的堆叫小顶堆
堆排序
思路:先将原数列构造成一个大顶堆或小顶堆(是数列下标对应的顺序存储二叉树),然后将根节点与数列最后的节
点进行交换,再将剩余的数列构成一个堆,循环直到得到一个有序序列,一般升序用大顶堆,降序用小顶堆
构建大顶堆思路:从最后一个非叶子节点对应子树开始与其左右节点进行比较交换,依次向上比较,直到全部交换完
毕即可得到一个大顶堆
代码实现(升序)
//堆排序
public class HeapSelect {
public static void main(String[] args) {
int[] arr = new int[8];
for (int i = 0; i < 8; i++) {
arr[i] = (int) (Math.random() * 80);
}
int temp;//中间交换数
//将原数组构建成一个大顶堆
for (int i = arr.length / 2 - 1; i >= 0; i--) {
select(arr, arr.length, i);
}
//将大顶堆的顶与数组最后的数进行交换
for (int i = arr.length - 1; i > 0; i--) {
temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
select(arr, i, 0); // 将剩余数组继续构成大顶堆
}
System.out.println(Arrays.toString(arr));
}
// length 需要排序的数组的长度 i为需要构成大顶堆的数组下标
public static void select(int[] arr, int length, int i) {
int temp = arr[i];//保存原来的值
//j为此树的左子节点下标
for (int j = 2 * i + 1; j < length; j += 2 * j + 1) {
//如果左子节点小于右子节点,将j改为右子节点下标
if (j + 1 < length && arr[j] < arr[j + 1]) {
j++;
}
//如果子节点大于根节点,交换两数
if (temp < arr[j]) {
arr[i] = arr[j];
i = j;
} else {
break;
}
arr[i] = temp;
}
}
}
八千万条数据测试平均时间1s左右
哈夫曼树
给定n个权值作为n个叶子节,构成一颗二叉树,若该树的带权路径长度最小,称这样的树为最优二叉树(哈夫曼树)
带权路径长度:节点的权值与路径长度的乘积
树的带权路径:所有叶子节点的带权路径长度的和
哈夫曼树构建思路:将需要构建哈夫曼树的对应数列升序排列,取出前两个树,将其作为左右节点,她们的权值的和
构成父节点,形成一颗二叉树,将新二叉树的父节点加入数列,同时删除原来的两个数,继续循环此操作,直到所有的
数全部排完即可获得一颗哈夫曼树
代码实现
**节点类
//哈夫曼树节点
public class HuffmanTreeNode implements Comparable<HuffmanTreeNode> {
int value;//节点的权值
HuffmanTreeNode left;
HuffmanTreeNode right;
public HuffmanTreeNode(int value) {
this.value = value;
}
@Override
public int compareTo(HuffmanTreeNode o) {
return this.value - o.value;
}
public void pre() {
System.out.print(this.value + ",");
if (this.left != null) {
this.left.pre();
}
if (this.right != null) {
this.right.pre();
}
}
}
**哈夫曼树类
//哈夫曼树
public class HuffmanTree {
public static void main(String[] args) {
int[] arr = {13, 7, 8, 3, 29, 6, 1};
createHuffmanTree(arr).pre();
}
//创建哈夫曼树
public static HuffmanTreeNode createHuffmanTree(int[] arr) {
List<HuffmanTreeNode> list = new ArrayList<>();//节点集合
//将数组元素包装成节点并添加导集合
for (int value : arr) {
list.add(new HuffmanTreeNode(value));
}
while (list.size() > 1) {
Collections.sort(list);//从小到大排序
//取出最小的两个节点
HuffmanTreeNode leftNode = list.get(0);
HuffmanTreeNode rightNode = list.get(1);
//创建新的节点,加入到集合并删除原来两个节点,重新排序
HuffmanTreeNode node = new HuffmanTreeNode(leftNode.value + rightNode.value);
node.left = leftNode;
node.right = rightNode;
list.add(node);
list.remove(leftNode);
list.remove(rightNode);
Collections.sort(list);
}
return list.get(0);
}
}
哈夫曼编码:将需要编码的文件以每个字节出现的次数作为权值,字节的值作为节点存储的数据值,构成一颗哈夫曼
树,同时规定向左和向右分别为0和1,得到每个叶子节点对应得路径对应的01字符串,以此字符串代码此字节的编码
方式,以此编码方式来压缩文件,进行传输,对方再以该编码方式进行解码即可