• (堆的应用)Huffman赫夫曼树的建立


    建立Huffman树的基本思路:给定有权重的一系列数据(带权重),从中挑选最小权重的两个数据,组成一棵树,得到的父节点再插入到数据系列当中。

    开始的时候按着严老师的办法,是借助顺序表来完成Huffman树的建立;同样,在建树过程中要从顺序表中选择比较小的两个数,相加后再插入到表尾,如此往复,知道所有给出的点都插入为止。

    通过最小堆来建树也很灵活便捷。堆的性能高,排序时间复杂度为nlog(2)n,利用最小堆,就可以将很快找出最小的元素(总是在顶部)。

    下面8步立刻掌握利用最小堆来建立Huffman树。

    看图解说

    ①原图(已经是最小堆);

    ②交换堆的首元素(肯定是最小的)和最后一个元素对换;

    ③交换后删除最后一个元素(复制出来),其实也不是真正的删除,只是size-1这个操作而已;调换后就不是堆了,重新调整heap为最小堆,调整可以用递归调用,也可以用下标作为判断条件,我的代码用的是下标判断条件;

    ④继续②;

    ⑤弹出最小的,调整;将两个最小点复制出来后,组成新的父节点,调整他们之间的内部指针关系;

    ⑥调整后;

    ⑦插入新节点,调整;

    ⑧调整后。

    image

    以上做了第一遍的操作,继续做下去知道堆中只剩下最后一个元素为止,再将root指向其就可以了,下面是代码。如此下来,Huffman树就建好了。

    Huffman节点数据结构设计:

    #ifndef _HUFFMANNODE_H_
    #define _HUFFMANNODE_H_
     
    struct HuffmanNode              //Huffman节点定义
    {
    private:
        int data;
     
    public:
        //构造函数
        HuffmanNode * left,* right,* parent;
        HuffmanNode():left(NULL),right(NULL),parent(NULL),data(-1){}
        HuffmanNode(int d):left(NULL),right(NULL),parent(NULL),data(d){}
     
        //重载运算符
        HuffmanNode &operator=(const HuffmanNode& hn)
        {
            left = hn.left;
            right = hn.right;
            data = hn.data;
            return *this;
        }
     
        //数据的获取和维护
        int GetData()const{return data;}                        //获取数据
        bool SetData(int d){data = d;return true;}      //设置数据
    };
     
    #endif

     最小堆类:

    #include <iostream>
    using namespace std;
     
    #ifndef _MINHEAP_H_
    #define _MINHEAP_H_
     
    #include "HuffmanNode.h"
     
    const int DefaultSize = 100;
     
    class MinHeap
    {
        HuffmanNode * heap;
        int szCurrent;
     
    public:
        MinHeap(int sz = DefaultSize);
        ~MinHeap()
        {delete [] heap;}
     
        void CreateMinHeap(int arr[],int n);        //数组构建最小堆
        bool Insert(HuffmanNode * e);               //往堆中插入Huffman节点
        void SiftDown(int start,int m);             //下滑,重建最小堆
        void SiftUp(int start,int m);                   //上滑,在插入的时候用到
        HuffmanNode * GetMinNode();             //获取Huffman节点data值最小的节点,同时维护szCurrent
        bool SwapNode(int i,int j);                     //交换下标为i和j的Huffman节点
        void Print();                                           //打印Huffman节点
    };
     
    #endif
     
    #include <iostream>
    using namespace std;
    #include "MinHeap.h"
    #include <assert.h>
     
    MinHeap::MinHeap(int sz)
    {
        heap = new HuffmanNode[sz];
        assert(heap!=NULL);
        szCurrent = 0;
    }
     
    void MinHeap::CreateMinHeap(int arr[],int n)
    {
        this->heap = new HuffmanNode[DefaultSize];
        assert(heap!=NULL);
     
        int i;
        for(i=0; i<n; i++)
            heap[i].SetData(arr[i]);
     
        szCurrent = n;
     
        int currentpos = (szCurrent-2)/2;           //从最后一个顶点开始调整
        while(currentpos >= 0)
        {
            SiftDown(currentpos,szCurrent-1);
            currentpos -- ;
        }
    }
     
    void MinHeap::SiftDown(int start,int m)
    {
        int i = start,j = i*2+1;
        HuffmanNode temp = heap[i];
        while(j<=m) 
        {
            if(j<m && heap[j].GetData() > heap[j+1].GetData())            //j记录比较小的子节点
                j++;
     
            if(temp.GetData() <= heap[j].GetData())          //不调整
                break;
            else
            {
                heap[i] = heap[j];          //子节点上移
                i = j;
                j = 2*j+1;
            }
        }
        heap[i] = temp;
    }
     
    void MinHeap::SiftUp(int start,int m)
    {
        int j = start,              //子节点位置
            i = (start-1) / 2;  //顶点位置
        HuffmanNode temp = heap[j]; //记录子节点
        while(j > 0)
        {
            if(temp.GetData() > heap[i].GetData())           //不调整
                break;
            else
            {
                heap[j] = heap[i];          //顶点下滑
                j = i;
                i = (i-1) / 2;
            }
        }
        heap[j] = temp;
    }
     
    void MinHeap::Print()
    {
        for(int i=0; i<szCurrent; i++)
            cout << heap[i].GetData() << " ";
        cout << endl;
    }
     
    bool MinHeap::Insert(HuffmanNode * e)
    {
        szCurrent++;
        if(szCurrent > DefaultSize)
            abort();
         
        heap[szCurrent-1] = *e;
        SiftUp(szCurrent-1,0);          //调整
        return true;
    }
     
    HuffmanNode * MinHeap::GetMinNode()
    {
        if(szCurrent>0)
        {
            HuffmanNode * t;
            SwapNode(0,szCurrent-1);        //此时heap[0].data是最小的,让它跟最后一个元素调换
            szCurrent--;
            SiftDown(0,szCurrent-1);
            t = new HuffmanNode();
            * t = heap[szCurrent];
            cout << "GetMinNode()后得到的堆:";
            Print();
            return t;
        }
        return NULL;
    }
     
    bool MinHeap::SwapNode(int i,int j)
    {
        swap(heap[i],heap[j]);
        return true;
    }

    Huffman类:

    #include "MinHeap.h"
     
    #ifndef _HUFFMANTREE_H_
    #define _HUFFMANTREE_H_
     
    class Huffman
    {
        MinHeap * mh;                   //堆,协助建立Huffman树
        HuffmanNode * root;         //Huffman树的根节点
     
    public:
        Huffman():root(NULL){};
        ~Huffman()
        {
            delete mh;
            MakeEmpty(root);
        }
        void MakeEmpty(HuffmanNode * ptr)
        {
            if(ptr->left)
                MakeEmpty(ptr->left);
            if(ptr->right)
                MakeEmpty(ptr->right);
            delete ptr;
        }
         void CreateHuffmanTree(int arr[],int size);
         void Print();
    };
     
    #endif
     
     
    #include <iostream>
    using namespace std;
    #include <assert.h>
    #include "HuffmanTree.h"
    #include "MinHeap.h"
    #include <queue>
     
    void Huffman::CreateHuffmanTree(int arr[],int size)
    {
        mh = new MinHeap(size);
        mh->CreateMinHeap(arr,size);         //将数据建立最小堆
        int i;
        HuffmanNode * left;
        HuffmanNode * right;
        HuffmanNode * parent;
     
        for(i=0; i<size-1; i++)
        {
            left = mh->GetMinNode();         //较小成为左孩子
            right = mh->GetMinNode();            //较大成为右孩子
             
            //这里可以归结出一个函数来,但是有点麻烦,直观点
            parent = new HuffmanNode(left->GetData()+right->GetData());
            parent->left = left;
            parent->right = right;
            left->parent = right->parent = parent;
     
            if(!mh->Insert(parent))
                abort();
     
            cout<< "插入父节点之后的堆:";
            mh->Print();
        }
        root = parent;
    }
     
    void Huffman::Print()
    {
        queue<HuffmanNode *> q;
        q.push(root);
        HuffmanNode * p;
        while(!q.empty())
        {
            p = q.front();
            cout << p->GetData() << " ";
            if(p->left != NULL)
                q.push(p->left);
            if(p->right != NULL)
                q.push(p->right);
            q.pop();
        }
    }

    Huffman(哈弗曼,赫夫曼)在通信领域用途很大,在文件压缩技术也有所运用,做些笔记,以后有用,与大家共享,欢迎讨论:)。

    当前标签: 别说我学过C++

     
    C++对析构函数的误解 捣乱小子 2011-12-09 11:56 阅读:18 评论:0  
     
    C++虚函数和纯虚函数(2) 捣乱小子 2011-12-04 16:16 阅读:62 评论:0  
     
    C++虚函数和纯虚函数(1) 捣乱小子 2011-12-04 13:16 阅读:1062 评论:3  
     
    C++静态数据成员和静态成员函数 捣乱小子 2011-12-03 13:35 阅读:16 评论:0  
     
    sizeof运算符和strlen函数的区别 捣乱小子 2011-11-10 22:53 阅读:15 评论:0  
  • 相关阅读:
    移动端开发常遇问题解答
    CSS属性小结之--半透明处理
    jquery事件代理
    sprite图在移动端的使用
    vertical-align及IE7下的inline-block
    图片延迟加载
    iOS NSInteger/NSUInteger与int/unsigned int、long/unsigned long之间的区别!
    GCD深入理解(1)
    iOS 开发图片资源选择png格式还是jpg格式
    iOS沙盒(sandbox)机制及获取沙盒路径
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2289505.html
Copyright © 2020-2023  润新知