二叉树应用之哈夫曼树、哈夫曼编码(C++实现)

哈夫曼相关定义及解释

代码如下:

#include<iostream>
#include<cstring>
using namespace std;

typedef struct{
	int weight;
	int parent,lchild,rchild;
}HTNode,*HuffmanTree;

typedef char **HuffmanCode;//动态分配数组存储哈夫曼编码

void select(HuffmanTree &a,int n, int &s1, int &s2)
{
    for (int i = 1; i = n; i++)
    {
        if (a[i].parent == 0)// 初始化s1,s1的双亲为0
        {
            s1 = i;
            break;         
		}
    }
    for (int i = 1; i <= n; i++)// s1为权值最小的下标
    {
        if (a[i].parent == 0 && a[s1].weight > a[i].weight)
            s1 = i;
    }
    for (int j = 1; j <= n; j++)
    {
        if (a[j].parent == 0&&j!=s1)// 初始化s2,s2的双亲为0
        {
            s2 = j;
            break;
        }
    }
    for (int j = 1; j <= n; j++)// s2为另一个权值最小的结点
    {
        if (a[j].parent == 0 && a[s2].weight > a[j].weight&&j != s1)   s2 = j;
    }
}


void CreateHuffmanTree(HuffmanTree &HT,int n)//构造哈夫曼树HT
{
	if(n<=1) return;
	m = 2*n - 1; //数组共2n-1个元素 
	HT = new HTNode[2*n];  //0号单元未用,HT[m]表示根结点 
	for(int i = 1; i <= m; ++i)  //将2n-1个元素的 lch、rch、parent置为0 
	{
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	for(int i =1; i <= n ; ++i) //输入前n个元素的weight值 
	{
		cin >> HT[i].weight;
	}
	/* ---初始化结束,下面开始建立哈夫曼树---  */ 
	for(int i = n + 1; i <= m; ++i)  //合并产生n-1个结点——构造Huffman树 
	{
		int s1,s2;
		select(HT,i-1, s1, s2);  //在HT[k](1≤k ≤i-1)中选择两个其双亲域为0,
		                         //且权值最小的结点,并返回它们在HT中的序号s1和s2							 
		HT[s1].parent = i;      
		HT[s2].parent = i;      //表示从F中删除s1,s2
		HT[i].lchild = s1;
		HT[i].rchild = s2;      //s1,s2分别作为i的左右孩子 
		HT[i].weight = HT[s1].weight + HT[s2].weight;	//i的权值为左右孩子权值之和 
	}	
}

void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)
{  //从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中 
	HC = new char*[n+1];         //分配n个字符编码的头指针矢量 
	char *cd = new char[n];      //分配临时存放的编码的动态数组空间 
	cd[n-1]='\0';                //编码结束符 
	for(int i = 1;i <= n ;++i)   //逐个字符求哈夫曼编码 
	{
		int start = n-1;
		int c =i;
		int f = HT[i].parent;    //f即为当前的双亲结点 
		while(f!=0)              //从叶子节点开始向上回溯,直到根结点 
		{
			--start;             //回溯一次start向前一个位置 
			if(HT[f].lchild == c) cd[start] ='0';  //结点c是f的左孩子,则生成代码0 
			else cd[start] ='1';    //结点c是f的右孩子,则生成代码1 
			c = f;f =HT[f].parent;  //继续向上回溯 
		}                           //求出第i个字符的编码 
		HC[i] =new char[n-start];   //为第i个字符串编码分配空间 
		strcpy(HC[i], &cd[start]);  // 将求得的编码从临时空间cd复制到HC的当前中 
	}
	delete cd;                      //释放临时空间 
}


void print(HuffmanTree HT,int n) // 打印哈夫曼树
{
    cout << "index weight parent lChild rChild" << endl;
    for (int i = 1; i <= n; ++i) 
    {
    	printf("%5d %6d %6d %6d %6d\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
    }
}

int main()
{
	cout << "二叉树的应用——实现哈夫曼树以及哈夫曼编码" << endl << endl; 
//	int x[] = { 5,29,7,8,14,23,3,11 };        
	
	int n;
	cout << "请输入叶子结点的个数为:";
	cin >> n; 
	HTNode *HT= new HTNode[2*8];    // 动态创建数组
	CreateHuffmanTree(HT, n);
	cout << "哈夫曼树表达:" << endl; 
    print(HT,2*n-1);
    
    HuffmanCode HC = NULL;//初始化编码表为空表
    CreatHuffmanCode(HT,HC,n);
    cout << "哈夫曼编码为:" << endl; 
    cout << "结点i"<<"\t"<< "权值" << "\t" << "编码" << endl;
	for (int i = 1; i <= n; i++)
    {
        cout << i << "\t"<< HT[i].weight << "\t" << HC[i] << endl;
    }
          cout << endl;
    
    
	system("pause");
		
	return 0;
} 
原创文章 50 获赞 139 访问量 2万+

猜你喜欢

转载自blog.csdn.net/diviner_s/article/details/106015262