1. 程式人生 > >赫夫曼樹-Huffman編碼

赫夫曼樹-Huffman編碼

首先感嘆,Huffman真牛逼!!

儘量把檔案壓縮到最小

通過最優排序,大資料把人們最常用的字元放到樹前面,以實現最小編碼。

大致說一下原理,貼一下程式碼

1:使用者提供常用字元,建立一棵最優樹

2:得到每一個字元的編碼code

3:使用者輸入0和1,通過遍歷最優樹實現解碼

說起來很容易,編碼設計到佇列和二叉樹,確實不容易敲出來

接下來敲一下程式碼:/*注:沒使用標頭檔案,分檔案寫,考慮看家看的明白*/

/*還有就是頭節點應該和普通節點不一樣的,但是Debug時候出現不同struct型別不能賦值,所以乾脆使用同一個struct了,比較佔用空間,各位看官知道就行,當然可以優化*/

/*
輸入文字,建立佇列
生成huffman 樹
輸入編碼,輸出字元文字
*/
#include <malloc.h>
#include <iostream>
using namespace std;
typedef  struct  ht_node//huffman樹節點
{
	char  data;
	struct   ht_node  *left,*right;
}*TYPE;

typedef  struct  quene_node//佇列節點
{
	TYPE  val;//樹型別
	unsigned int size;
	unsigned  int  priority;//優先順序
	struct  quene_node  *next;//後繼
}*Q_node;


typedef  struct  table_node
{
	char symbol;//字元存放
	char *code;
	struct  table_node *next;
}Table_node;


typedef  struct  table
{
	Table_node *first,*next;
}*Table;


void add_quene(Q_node &hufquene,TYPE &aux,unsigned  int  priority)//引數:佇列頭節點,樹節點,優先順序
{
	if(hufquene->size==256)
	{
		cout<<"Quene is full !!";
		return;
	}//否則建立佇列節點
	Q_node temp=(Q_node)malloc(sizeof(quene_node));
	temp->priority=priority;
	temp->val=aux;

///////////////////////DEBUG/////////////////////////////////
	if(hufquene->size==0||hufquene->next==NULL)//只有頭節點
	{
		//把元素插入佇列
		temp->next=NULL;
		hufquene->next=temp;
		hufquene->size++;
	}else
	{
		
		//要進行比較後按順序優先順序從小到大排列
		Q_node  itertor=hufquene;//建立迭代節點,指向第一個節點


		while(itertor->next!=NULL)//佇列中存在元素
		{
			if(priority<=itertor->next->priority)//從第二個節點開始比較
			{
				hufquene->size++;
				temp->next=itertor->next;
				itertor->next=temp;//頭插法
				return;
			}
			
			itertor=itertor->next;
		}
		if(itertor->next==NULL)
		{
			temp->next=NULL;
			itertor->next=temp;
			hufquene->size++;
			return;
		}
		

	}

}


TYPE  getquene(Q_node &hufquene)
{
	TYPE  returnvalue;
	if(hufquene->size>0)
	{
		Q_node tree_node= hufquene->next;
		returnvalue=tree_node->val;
		hufquene->next=tree_node->next;
		hufquene->size--;
	}else
	{
		cout<<"Empty!!";
	}
	return  returnvalue;//返回樹節點

}
TYPE buildtree(char *inputstring)
{
	int *probablity=(int *)malloc(sizeof(int)*256);//分配地址
	for(int i=0;i<256;i++)
		probablity[i]=0;//初始化
	for(int j=0;inputstring[j]!='\0';j++)
	{
		probablity[(inputstring[j])]++;
	}//統計字元出現次數
	Q_node hufquene;//定義一個頭節點

	//////初始化頭節點
	hufquene=(Q_node)malloc(sizeof(quene_node));
	hufquene->next=NULL;
	hufquene->size=0;
	///////////
	//生成佇列
	for(int k=0;k<256;k++)
	{
		if(probablity[k]!=0)//存在字元
		{
			TYPE  aux=(TYPE)malloc(sizeof(ht_node));
			aux->data=(char)k;
			aux->left=NULL;
			aux->right=NULL;//為每一個字元分配一個樹節點
			//插入佇列
			add_quene(hufquene,aux,probablity[k]);
		}

	}
	//生成Huffman樹
	while(hufquene->size!=1)
	{
		Q_node  tyust=hufquene->next;
		unsigned int num=tyust->priority;
		num+=tyust->next->priority;
		TYPE left=getquene(hufquene);
		TYPE right=getquene(hufquene);
		TYPE huff_tree=(TYPE)malloc(sizeof(ht_node));
		huff_tree->left=left;
		huff_tree->right=right;
		add_quene(hufquene,huff_tree,num);//再次插入
	}
	TYPE  root=(TYPE)malloc(sizeof(ht_node));
	root=getquene(hufquene);
	return root;
}
void  travertree(TYPE tree_node,Table &link,int k,char code[256])
{
	if(tree_node->left==NULL&&tree_node->right==NULL)//葉子
	{
		code[k]='\0';//新增結束
		Table_node  *aux=(Table_node*)malloc(sizeof(Table_node));
		aux->code=(char*)malloc(sizeof(char)*(strlen(code)+1));
		strcpy(aux->code,code);
		aux->symbol=tree_node->data;
		aux->next=NULL;
		if(link->first==NULL)
		{
			link->first=link->next=aux;
		}else
		{
			link->next->next=aux;
			link->next=aux;
		}		

	}
	if(tree_node->left!=NULL)//左子樹不為0
	{
		code[k]='0';
		travertree(tree_node->left,link,k+1,code);
	}
	if(tree_node->right!=NULL)
	{
		code[k]='1';
		travertree(tree_node->right,link,k+1,code);
	}
}
Table build_table(TYPE tree_node)//建立
{
	Table  tytable=(Table)malloc(sizeof(table));
	tytable->first=NULL;
	tytable->next=NULL;
	char code[256];
	int k=0;
	travertree(tree_node,tytable,k,code);
	return tytable;

}
void  decode(TYPE root,char *str)//解碼
{
	TYPE temp=root;
	for(int i=0;str[i]!='\0';i++)
	{
		if(temp->left==NULL&&temp->right==NULL)
		{
			cout<<temp->data;
			temp=root;//碰到葉子後從根重新開始
		}
		if(str[i]=='0')
		{
			temp=temp->left;//0向左走
		}
		if(str[i]=='1')
		{
			temp=temp->right;
		}	
	}
}
void  main()
{
	TYPE  root=buildtree("Hello world I am CPP");//根據大資料生成最優樹
	Table mark_table=build_table(root);//返回生成的最優排列
	decode(root,"00011101111101");//還沒找到對應編碼多出的捨棄不要
	cout<<endl;
}