好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

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

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

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

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

看图解说

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

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

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

④继续②;

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

⑥调整后;

⑦插入新节点,调整;

⑧调整后。

以上做了第一遍的操作,继续做下去知道堆中只剩下最后一个元素为止,再将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   

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于(堆的应用)Huffman赫夫曼树的建立的详细内容...

  阅读:44次