1. 程式人生 > >DS二叉樹——Huffman編碼與解碼

DS二叉樹——Huffman編碼與解碼

題目描述

1、問題描述

給定n個字元及其對應的權值,構造Huffman樹,並進行huffman編碼和譯(解)碼。

構造Huffman樹時,要求左子樹根的權值小於、等於右子樹根的權值。

進行Huffman編碼時,假定Huffman樹的左分支上編碼為‘0’,右分支上編碼為‘1’。

2、演算法

構造Huffman樹演算法:

⑴ 根據給定的n個權值(w1, w2, …, wn)構成n棵二叉樹的集合F={T1, T2, …, Tn},其中每棵二叉樹Ti中只有一個權值為wi的根結點。

⑵ 在F中選取兩棵根結點的權值最小的樹,作為左、右子樹構造一棵新的二叉樹,且置其根結點的權值為其左、右子樹權值之和。

⑶ 在F中刪除這兩棵樹,同時將新得到的二叉樹加入F中。

(4) 重複⑵, ⑶,直到F只含一棵樹為止。

3、Huffman編碼演算法:

⑴ 從Huffman樹的每一個葉子結點開始。

⑵ 依次沿結點到根的路徑,判斷該結點是父親結點的左孩子還是右孩子,如果是左孩子則得到編碼‘0’,否則得到編碼‘1’,先得到的編碼放在後面。

⑶ 直到到達根結點,編碼序列即為該葉子結點對應的Huffman編碼。

4、Huffman譯(解)碼演算法:

⑴ 指標指向Huffman樹的根結點,取第一個Huffman碼。

⑵ 如果Huffman碼為‘0’,將指標指向當前結點的左子樹的根結點;如果Huffman碼為‘1’,將指標指向當前結點的右子樹的根結點。

⑶ 如果指標指向的當前結點為葉子結點,則輸出葉子結點對應的字元;否則,取下一個Huffman碼,並返回⑵。

⑷ 如果Huffman碼序列未結束,則返回⑴繼續譯碼。

輸入

第一行測試次數

第2行:第一組測試資料的字元個數n,後跟n個字元

第3行:第一組測試資料的字元權重

待編碼的字串s1

編碼串s2

其它組測試資料類推

輸出

第一行~第n行,第一組測試資料各字元編碼值

第n+1行,串s1的編碼值

第n+2行,串s2的解碼值,若解碼不成功,輸出error!

其它組測試資料類推

樣例輸入

2 5 A B C D E 15 4 4 3 2 ABDEC 00000101100 4 A B C D 7 5 2 4 ABAD 1110110

樣例輸出

A :1 B :010 C :011 D :001 E :000 1010001000011 error! A :0 B :10 C :110 D :111 0100111 DAC

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

const int maxw = 9999;

class HuffNode{
public:
	int weight;
	int parent;
	int leftchild;
	int rightchile;
};

class HuffMan{
private:
	void MakeTree()
	{
		int i, s1, s2;
		for (i = lnum + 1; i <= len; i++)
		{
			SelectMin(i - 1, &s1, &s2);
			hufftree[s1].parent = i;
			hufftree[s2].parent = i;
			hufftree[i].leftchild = s1;
			hufftree[i].rightchile = s2;
			hufftree[i].weight = hufftree[s1].weight + hufftree[s2].weight;
		}
	}
	void SelectMin(int pos, int *s1, int *s2)
	{
		int w1, w2, i;
		w1 = w2 = maxw;
		*s1 = *s2 = 0;
		for (i = 1; i <= pos; i++)
		{
			if (hufftree[i].weight < w1 && hufftree[i].parent == 0)
			{
				*s2 = *s1;
				w2 = w1;
				w1 = hufftree[i].weight;
				*s1 = i;
			}
			else if (hufftree[i].weight < w2 && hufftree[i].parent == 0)
			{
				w2 = hufftree[i].weight;
				*s2 = i;
			}
		}
	}
public:
	int len;
	int lnum;
	HuffNode *hufftree;
	string *huffCode;
	char *message;
	void MakeTree(int n, int wt[], char c[])
	{
		int i;
		lnum = n;
		len = 2 * n - 1;
		hufftree = new HuffNode[2 * n];
		huffCode = new string[lnum + 1];
		message = new char[lnum + 1];
		for (i = 1; i <= n; i++) 
            hufftree[i].weight = wt[i - 1];
		for (i = 1; i <= n; i++)
            message[i] = c[i - 1];
		for (i = 1; i <= len; i++)
		{
			if (i > n)
                hufftree[i].weight = 0;
			hufftree[i].parent = 0;
			hufftree[i].leftchild = 0;
			hufftree[i].rightchile = 0;
		}
		MakeTree();
	}
	void Coiding()
	{
		char *cd = new char[lnum];
		int i, c, f, start;
		cd[lnum - 1] = '\0';
		for (i = 1; i <= lnum; i++)
		{
			start = lnum - 1;
			for (c = i, f = hufftree[i].parent; f != 0; c = f, f = hufftree[f].parent)
			{
				if (hufftree[f].leftchild == c)
					cd[--start] = '0';
				else
					cd[--start] = '1';
			}
			huffCode[i].assign(&cd[start]);
		}
	}
	void Destory()
	{
		len = 0;
		lnum = 0;
		delete[]hufftree;
		delete[]huffCode;
	}
	int Decode(const string codestr, string &teststr){
		int i, k, c;
		char ch;
		c = len;
		k = 0;
		string a = "";
		for (i = 0; i < codestr.length(); i++)
		{
			ch = codestr[i];
			a += ch;
			if (ch == '0') c = hufftree[c].leftchild;
			else
                if (ch == '1') 
                    c = hufftree[c].rightchile;
                else 
                    return 0;
			if (hufftree[c].leftchild == 0 && hufftree[c].rightchile == 0)
			{
				for (int j = 1; j <= lnum; j++)
					if (hufftree[c].weight == hufftree[j].weight && a == huffCode[j])
						teststr += message[j];
				c = len;
				a = "";
			}
			else ch = '\0';
		}
		if (ch == '\0') return 0;
		return 1;
	}
};

int main()
{
	int t, n, i, j;
	int wt[800];
	char c[800];
	string teststr = "";
	string codestr;
	HuffMan huff;
	cin >> t;
	while (t--)
	{
		cin >> n;
		for (i = 0; i < n; i++) cin >> c[i];
		for (i = 0; i < n; i++) cin >> wt[i];
		huff.MakeTree(n, wt, c);
		huff.Coiding();
		for (i = 1; i <= n; i++)
		{
			cout << c[i - 1] << " :" << huff.huffCode[i] << endl;
		}
		cin >> codestr;
		for (i = 0; i < codestr.length(); i++)
		{
			for (j = 1; j <= n; j++)
				if (codestr[i] == c[j - 1]) cout << huff.huffCode[j];
		}
		cout << endl;
		cin >> codestr;
		if (huff.Decode(codestr, teststr)) cout << teststr << endl;
		else cout << "error!" << endl;
		teststr = "";
		huff.Destory();
	}
	return 0;
}

相關推薦

DS——Huffman編碼解碼

題目描述 1、問題描述 給定n個字元及其對應的權值,構造Huffman樹,並進行huffman編碼和譯(解)碼。 構造Huffman樹時,要求左子樹根的權值小於、等於右子樹根的權值。 進行Huffman編碼時,假定Huffman樹的左分支上編碼為‘0’,右

DS--赫夫曼的構建編碼

題目描述 給定n個權值,根據這些權值構造huffman樹,並進行huffman編碼 參考課本演算法,注意陣列訪問是從位置1開始 要求:赫夫曼的構建中,預設左孩子權值不大於右孩子權值 輸入 第一行輸入t,表示有t個測試例項 第二行先輸入n,表示第1個例項有n個權

DS--赫夫曼解碼

題目描述 已知赫夫曼編碼演算法和程式,在此基礎上進行赫夫曼解碼 在赫夫曼樹的類定義中增加了一個公有方法: int Decode(const string codestr, char txtstr[]); //輸入編碼串codestr,輸出解碼串txtstr

【數據結構算法】遞歸非遞歸遍歷(附完整源碼)(轉)

style stack gravity text 一個 eat 遞歸遍歷 deb 雙向 轉自:http://blog.csdn.net/ns_code/article/details/12977901 二叉樹是一種非常重要的數據結構,很多其他數據機構都是基於二叉樹的基礎

[javaSE] 數據結構-遍歷查找

ngx quest wan ase ngs san http zhong ros %E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%80%9D%E7%BB%B4%E9%80%BB%E8%BE%91%2018%

(性質存儲)

tco img 分享圖片 pos 技術 master blog lee mar 二叉樹的性質及存儲如下 二叉樹(性質與存儲)

【資料結構】的建立遍歷(遞迴)

該程式全是使用遞迴的操作 執行環境是:Dev-C++ #include <stdio.h> #include <stdlib.h> typedef struct node{ char data; struct node *lchild,*rchild; }bi

(建立訪問)(先序,中序,後序)

二叉樹的建立(先序建立) 二叉樹的訪問(遞迴與非遞迴 先序)(遞迴與非遞迴中序)(遞迴與非遞迴 後序) #include<iostream> #include<stack> using namespace std; struct Tree_Node ///結點的

第六章--Huffman-計算機17級

解析在下面,有什麼問題歡迎各位大佬指正   p1-1: 這個主要得看懂題,其實就是在考你哈夫曼樹的構造:每次把權值最小的兩顆二叉樹合併 ,越往下肯定權值越小,所以這句話肯定是對的 x2-1: d肯定不一定啊 x2-2: x2-3:

第六章--Huffman

1-1 對N(≥2)個權值均不相同的字元構造哈夫曼樹,則樹中任一非葉結點的權值一定不小於下一層任一結點的權值。 (2分) T  2-1 對N(N≥2)個權值均不相同的字元構造哈夫曼樹。下列關於該哈夫曼樹的敘述中,錯誤的是: (2分) 樹中一

(0)——的實現的遍歷

0.二叉樹的實現(C++) 未完,待補充 #include <iostream> #include<iostream> #include<queue> #include<stack> using namespace std; //二叉樹結點的

資料結構——的建立遞迴遍歷

#include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct Node{ //二叉樹的鏈式儲存結點 char data; struct Node *Lch

的建立遍歷(先序,中序,後序,層次)

#include<stdio.h> #include<stdlib.h> typedef struct BitNode { char data; struct BitNode *lchild,*rchild; }BitNode; BitNode* Crea

資料結構 筆記:的比較相加

二叉樹的克隆操作 -SharedPointer<BTree<T>> clone() const ·克隆當前樹的一份拷貝 ·返回值為堆空間中的一棵新二叉樹(與當前樹相等) 二叉樹的克隆 -定義功能:clone(node) ·拷貝node為根節點的二叉樹(

學習筆記 c++ (用類來實現的建立遍歷)

       程式碼: #include<iostream> #include<stdio.h> using namespace std; class BiTree { public:     char data;     BiTree *

【資料結構週週練】010 遞迴演算法實現的建立遍歷

一、前言 上兩篇週週練部落格講了二叉樹的建立與遍歷,建立時,通過建立棧來存放結點,方便二叉樹的建立,這種建立二叉樹的方式採用了非遞迴演算法,本次內容採用遞迴的方式來建立二叉樹,大家可以通過對比程式碼量,感受一下遞迴的魅力。同時遍歷過程也是通過遞迴演算法。 如果大家第一次看

的建立實現

#include <iostream> #include<cstdio> #include<cstdlib> using namespace std; typedef int TelemType;//TelemType代替int ty

1. 的建立基本操作

1. 二叉樹的建立與基本操作 成績 10 開啟時間 2018年10月28日 星期日 18:00 折扣 0.8 折扣時間 2018年11月18日 星期日 23:55

的建立遍歷

#include<iostream> #include<cstring> #include<conio.h> #include<cstdlib> #define OK 1 #define ERROR 0 #define OVER

哈夫曼編碼解碼

#include<stdio.h> #include<stdlib.h> #include<iostream> #include<string> using namespace std; #define MAXSIZE 30