数据结构算法爬坑日记十三

堆排序,哈夫曼树


堆是一个完全二叉树,每个节点的值都大于或等于左右节点的值的堆叫大顶堆,小于左右节点的值的堆叫小顶堆

堆排序

思路:先将原数列构造成一个大顶堆或小顶堆(是数列下标对应的顺序存储二叉树),然后将根节点与数列最后的节
点进行交换,再将剩余的数列构成一个堆,循环直到得到一个有序序列,一般升序用大顶堆,降序用小顶堆

构建大顶堆思路:从最后一个非叶子节点对应子树开始与其左右节点进行比较交换,依次向上比较,直到全部交换完
毕即可得到一个大顶堆

代码实现(升序)
//堆排序
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);
    }
}

哈夫曼编码:将需要编码的文件以每个字节出现的次数作为权值,字节的值作为节点存储的数据值,构成一颗哈夫曼
树,同时规定向左和向右分别为01,得到每个叶子节点对应得路径对应的01字符串,以此字符串代码此字节的编码
方式,以此编码方式来压缩文件,进行传输,对方再以该编码方式进行解码即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值