zoukankan      html  css  js  c++  java
  • 数据结构-并查集和堆、哈夫曼树

    一、并查集的定义

    1. 并查集是一种维护集合的数据结构,它的名字中“并”、“查”、“集”。分别取自Union(合并)、Find(查找)、Set(集合)。
    • 合并:就是合并两个集合
    • 查找:判断两个元素是否在一个集合
    • 那么并查集是用什么实现的,就是一个数组,
    • 对于同一个集合来说只存在一个根结点,且将其作为所属集合的标识。

    二、并查集的基本操作

    1. 初始化,每个元素都是一个独立的集合,因此需要令所有的father[i] = i;
    for(int i = 1; i <= N; i++){
        father[i] = i;
    }
    
    1. 查找,就是查找反复寻找父亲结点。
    int findFather(int x){
        while(x != father){
            x = father[x];
        }
        return x;
    }
    
    int findFather(int x){
        if(x == father[x]) return x;
        else return findFather(father[x]);
    }
    
    1. 合并,就是把两个集合合并成一个集合。
    void Union(int a, int b){
        int faA = findFather(a);
        int faB = findFather(b);
        if(faA != faB){
            father[faA] = faB;
        }
    }
    

    三、路径压缩

    • 把当前查询结点的路径上的所有结点的父亲都指向根结点。
    int findFather(int x){
        //由于x在下面的while中会变成根结点,因此先把原先的x保存一下
        int a = x;
        while(x != father[x]){
            x = father[x];
        }
        //到这里,x存放的是根结点,下面把路径上所有的结点的father都改成根结点
        while(a != father[a]){
            int z = a;
            a = father[a];//a回溯父亲结点
            father[z] = x;//把原来的结点a的父亲改为根结点
        }
        return x;//返回根结点
    }
    

    四、堆的定义

    1. 堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子结点的值。
    2. 如果父亲结点的值大于或等于孩子结点的值,那么称这样的堆为大顶堆,反之为小顶堆。
    3. 堆一般用于优先队列的实现,而优先队列默认情况下使用大顶堆。

    五、堆的基本操作

    1. 建堆向下调整
    //对于heap数组在[low, high]的范围进行向下调整
    //其中low为欲调整结点的数组下标,high一般为堆的最后一个元素的数组下标
    void downAdjust(int low, int high){
        int i = low, j = i * 2;
        while(j <= high){
            if(j+1 <= high && heap[j+1] > heap[j]){
                j = j + 1;
            }
            if((heap[j] > heap[i]){
                swap(heap[j], heap[i]);
                i = j;
                j = i * 2;
            }else{
                break;
            }
        }
    }
    
    2. 建堆
    • 假设序列中元素的个数为n,根据完全二叉树的特性,知道叶子结点个数为n/2个,因此数组下标在[1, n/2]的范围内是非叶子结点。于是可以从n/2号位开始倒着枚举结点,对每个遍历到结点i进行[i, n]范围的调整。
    void createHeap(){
        for(int i = n / 2; i >= 1; i--){
            downAdjust(i, n);
        }
    }
    
    3. 删除堆中最大元素
    • 只需要最后一个元素覆盖堆顶元素,然后对根结点进行调整。
    void deleteTop(){
        heap[1] = heap[n--];
        downAdjust(1, n);
    }
    
    4. 添加元素
    • 也就是把添加的元素放在数组的最后一个位置,然后进行上调操作。
    //对于heap数组在[low, high]的范围进行向上调整
    //其中low为欲调整结点的数组下标设置为1,high一般为堆的最后一个元素的数组下标
    void upAdjust(int low, int high){
        int i = high, j = i / 2;//i为欲调整结点,j为其父亲
        while(j >= low){
            if(heap[j] < heap[i]){
                swap(heap[j], heap[i]);
                i = j;
                j = i / 2;
            }else{
                break;
            }
        }
    }
    
    //添加元素
    void insert(int x){
        heap[++n] = x;//让元素个数加1,然后将数组末尾赋值为x
        upAdjust(1, n);//向上调整新加入的结点n
    }
    
    5. 堆排序
    • 是使用堆结构对一个序列进行排序。
    void heapSort(){
        createHeap();
        for(int i = n; i > 1; i--){
            swap(heap[i], heap[1]);
            downAdjust(1, i - 1);
        }
    }
    

    六、哈夫曼树的相关定义

    1. 其中叶子结点的路径长度是指从根结点出发到达结点的边数。
    2. 把叶子结点的权值乘以其路径长度的结果称为这个叶子结点的带权路径长度。
    3. 树的带权路径长度(WPL)等于它所有叶子结点带权路径的长度之和。
    4. 带权路径长度最小的就是称为哈夫曼树(最优二叉树),显然对于同一组叶子结点来说,哈夫曼树可以是不唯一的,但是带权路径长度一定是唯一的。

    七、哈夫曼编码

    1. 对于任何一个叶子结点,其编码一定不会成为其任何一个结点编码前缀。
    2. 其中任何一个字节编码都不是另一个字符编码的前缀,同时满足这种方式的编码方式称为前缀编码,意义不产生混淆。
    3. 哈夫曼编码,就是使得字符串编码成01串后长度最短的前缀编码。
    4. 哈法曼编码是针对于特定的字符串来讲的。
    作者:睿晞
    身处这个阶段的时候,一定要好好珍惜,这是我们唯一能做的,求学,钻研,为人,处事,交友……无一不是如此。
    劝君莫惜金缕衣,劝君惜取少年时。花开堪折直须折,莫待无花空折枝。
    曾有一个业界大牛说过这样一段话,送给大家:   “华人在计算机视觉领域的研究水平越来越高,这是非常振奋人心的事。我们中国错过了工业革命,错过了电气革命,信息革命也只是跟随状态。但人工智能的革命,我们跟世界上的领先国家是并肩往前跑的。能身处这个时代浪潮之中,做一番伟大的事业,经常激动的夜不能寐。”
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    goland 安装包激活码
    go目录文件
    php 单表数据转化为json格式
    thinkphp分页查询,后台处理怎么做
    用js 获取url 参数 页面跳转 ? 后的参数
    约瑟夫问题
    openstack配置
    Python数据结构
    Python常用排序算法
    scrapy使用
  • 原文地址:https://www.cnblogs.com/tsruixi/p/12347871.html
Copyright © 2011-2022 走看看