数据结构和算法-11.树结构实际应用

1. 堆排序

1.1 堆排序基本介绍

  • 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,他的最好,最坏,平均时间复杂度均为O(n log n),是不稳定排序
  • 堆是具有以下性质的完全二叉树,每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆。没有要求节点的左孩子和右孩子的值的大小关系
  • 每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆
  • 一般升序采用大顶堆,降序采用小顶堆

大顶堆
小顶堆

1.2 堆排序的基本思想

  1. 将待排序序列构造成一个大顶堆
  2. 整个序列最大值就是堆顶的根节点
  3. 将其与末尾元素进行交换,此时末尾就是最大值
  4. 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复

堆排序
堆排序
堆排序
堆排序
堆排序
堆排序
堆排序
堆排序

1.3 堆排序代码实现

public class HeapSort {
   
    public static void main(String[] args) {
   
        int arr[] = {
   4, 6, 8, 5, 9, -1, 10, -99, 88};
        heapSort(arr);
    }

    public static void heapSort(int arr[]) {
   
        int temp = 0;
        System.out.println("堆排序");
//        分步完成
//        adjustHeap(arr, 1, arr.length);
//        System.out.println("第一次" + Arrays.toString(arr));
//        adjustHeap(arr, 0, arr.length);
//        System.out.println("第二次" + Arrays.toString(arr));
        //大顶堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
   
            adjustHeap(arr, i, arr.length);
        }
        //交换
        for (int j = arr.length - 1; j > 0; j--) {
   
            temp = arr[j];
            arr[j] = arr[0];
            arr[0] = temp;
            adjustHeap(arr, 0, j);
        }
        System.out.println(Arrays.toString(arr));
    }

    //将一个数组(二叉树)调整成一个大顶堆,i表示非叶子节点在数组中索引,length表示多少个元素继续调整
    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++;//k指向右子节点
            }
            if (arr[k] > temp) {
   //子节点大于父节点
                arr[i] = arr[k];//较大的值赋给当前节点
                i = k;//i指向k,继续循环比较
            } else {
   
                break;
            }
        }
        //for结束后,将以i为父节点的树的最大值放在了最顶
        arr[i] = temp;//将temp放到调整后的位置
    }
}

2. 赫夫曼树

2.1 赫夫曼树基本介绍

  • 给定n个权值作为n个叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)霍夫曼树
  • 赫夫曼树是带权路径长度最短的树,权值较大的节点离根较近

赫夫曼树

2.2 构建赫夫曼树的思想

以数组 { 13, 7, 8, 3, 29, 6, 1 } 为例,排序后的数组为 { 1, 3, 6, 7, 8, 13, 29 }

赫夫曼树
赫夫曼树
赫夫曼树
赫夫曼树
赫夫曼树

2.3 代码实现

public class HuffmanTree {
   
    public static void main(String[] args) {
   
        int arr[] = {
   13, 7, 8, 3, 29, 6, 1};
        Node root = createHuffmanTree(arr);

        preOrder(root);
    }

    //前序遍历
    public static void preOrder(Node root) {
   
        if (root != null) {
   
            root.preOrder();
        } else {
   
            System.out.println("是空树");
        }
    }

    //创建赫夫曼树的方法
    public static Node createHuffmanTree(int[] arr) {
   
        //遍历arr数组,将arr的每个元素构建成一个Node
        ArrayList<Node> nodes = new ArrayList<>();
        for (int value : arr) {
   
            nodes.add(new Node(value));
        }
        while (nodes.size() > 1) {
   

            //排序
            Collections.sort(nodes);
            System.out.println("nodes=" + nodes);

            //取出根节点权值最小的两个二叉树
            Node leftNode = nodes.get(0);
            Node rightNode = nodes.get(1);

            Node parent = new Node(leftNode.value + rightNode.value);
            parent.left = leftNode;
            parent.right = rightNode;
            //从ArrayList中删除处理过的
            nodes.remove(leftNode);
            nodes.remove(rightNode);
            //将parent加入到nodes
            nodes.add(parent);
            //System.out.println("第一次处理后" + nodes);
        }
        //返回赫夫曼树的root节点
        return nodes.get(0);
    }
}

//创建节点类
class Node implements Comparable<Node> {
   
    int value;//权值
    Node left;//左子节点
    Node right;//右子节点

    //前序遍历
    public void preOrder() {
   
        System.out.println(this);
        if (this.left != null) {
   
            this.left.preOrder();
        }
        if (this.right != null) {
   
            this.right.preOrder();
        }
    }

    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;
    }
}

3. 赫夫曼编码

3.1 赫夫曼编码基本介绍

  • 也被翻译成哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,属于一种程序算法
  • 广泛用于数据文件压缩,压缩率通常在20%-90%之间
  • 是可变字长编码(VLC)的一种,称之为最佳编码

3.2 定长编码与变长编码

定长编码

i like like like java do you like a java   

ASCII码为

105 32 108 105 107 101 32 108 105 107 101 32 108 105 107 101 32 106 97 118 97 32 100 111 32 121 111 117 32 108 105 107 101 32 97 32 106 97 118 97 //对应Ascii码
01101001 00100000 01101100 01101001 01101011 01100101 00100000 01101100 01101001 01101011 01100101 00100000 01101100 01101001 01101011 01100101 00100000 01101010 01100001 01110110 01100001 00100000 01100100 01101111 00100000 01111001 01101111 01110101 00100000 01101100 01101001 01101011 01100101 00100000 01100001 00100000 01101010 01100001 01110110 01100001   //对应的二进制 

变长编码

统计上诉字符出现的各字符出现的次数

d:1 y:1 u:1 j:2  v:2  o:2  l:4  k:4  e:4 i:5  a:5   :9  // 各个字符对应的个数

按照各个字符出现的次数进行编码,出现次数越多的,编码越小

0=  ,  1=a, 10=i, 11=e, 100=k, 101=l, 110=o, 111=v, 1000=j, 1001=u, 1010=y, 1011=d

按照上面给定各个字符编码

10010110100... 

无法进行解析,不知解析1还是10还是100

3.3 赫夫曼编码原理

  • 根据赫夫曼树,给各个字符规定编码(前缀编码),向左为0,向右为1
o: 1000   u: 10010  d: 100110  y: 100111  i: 101
a: 110    k: 1110   e: 1111    j: 0000    v: 0001
l: 001     : 01

赫夫曼树
按照上面的赫夫曼编码,字符串对应的编码为

1010100110111101111010011011110111101001101111011110100001100001110011001111000011001111000100100100110111101111011100100001100001110

长度为133,原来为359,(无损)压缩了62.9%

public class HuffmanCode {
   
    public static void main(String[] args) {
   
        String content = "i like like like java do you like a java";
        byte[] contentBytes = content.getBytes();
        System.out.println(content.length());//40

        byte[] huffmanCodesBytes = huffmanZip(contentBytes);
        System.out.println(Arrays.toString(huffmanCodesBytes));

        byte[] souceBytes = decode(huffmanCodes, huffmanCodesBytes);
        System.out.println(new String(souceBytes));

        //压缩文件
        String zipFile = "d://555.zip";
        String dstFile = 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值