1. Alguns conceitos básicos
1. Caminho : a ramificação de um nó a outro na árvore constitui o caminho entre esses dois nós.
2. Comprimento do caminho : O número de ramificações no caminho é chamado de comprimento do caminho.
3. O comprimento do caminho da árvore : a soma do comprimento do caminho desde a raiz da árvore até cada nó.
4. Direito : Uma quantidade atribuída a uma entidade é uma descrição numérica de alguns ou alguns atributos da entidade.
5. O comprimento do caminho ponderado do nó: o produto do comprimento do caminho do nó à raiz da árvore e o peso no nó.
6. O comprimento do caminho ponderado da árvore: a soma dos comprimentos do caminho ponderado de todos os nós de folha na árvore, geralmente registrados como:
7. Árvore de Huffman : Suponha que haja pesos m {w1, w2, ..., wm} , Uma árvore binária com n nós folha pode ser construída, e o peso de cada nó folha é wi. A árvore binária com o menor comprimento de caminho ponderado WPL é chamada de árvore binária ótima ou árvore de Huffman.
Nota:
(1) Uma árvore binária completa não é necessariamente uma árvore de Huffman;
(2) O nó com maior peso está mais próximo do nó raiz;
(3) A árvore de Huffman não é única, mas o comprimento do caminho ponderado da árvore é certo igual;
Em segundo lugar, construa a árvore Huffman
Estrutura do nó da árvore de Huffman:
representação de armazenamento da árvore de Huffman
typedef struct{
int weight; //结点的权值
int parent,lchild,rchild; //结点的双亲、左孩子、右孩子的下标
}HTNode,*HuffmanTree; //动态分配数组存储哈夫曼树
Número de nós da árvore Huffman:
Exemplo: Dado que w = (5,29,7,8,14,23,3,11), gere uma árvore de Huffman e calcule o comprimento do caminho ponderado da árvore. E dar o estado inicial e o estado final da estrutura de armazenamento HT durante sua construção.
【Descrição do algoritmo】
void CreateHT(HuffmanTree &HT,int n)
{
if(n<=1)return ;
m=2*n-1;
HT=new HTNode[m+1];
for(i=1;i<=m;++i) //将1-m号单元的父结点、左孩子、右孩子的下标都初始化为0
{
HT[i].parent=0;
HT[i}.lchild=0;
HT[i}.rchild=0;
}
for(i=1;i<=n;++i) //输入前n个结点的权值
{
cin>>HT[i].weight;
}
for(i=n+1;i<=m;++i)
{
//通过n-1次的选择、删除、合并来创建哈夫曼树
Select(HT,i-1,s1,s2);
//在HT[k](1<=k<=i-1)中选择两个其双亲域为0且权最小的结点,并返回他们在HT中的序号s1和s2
HT[s1}.parent=i;
HT[s2}.parent=i;
//得到新结点i,从森林中删除s1,s2,将s1和s2的双亲域由0改为1
HT[i].lchild=s1; //s1作为i的左结点
HT[i}.rchild=s2; //s2作为i的右结点
HT[i].weight=HT[s1].weight+HT[s2].weight; //i的权值为左右孩子权值之和
}
Três, codificação Huffman
Marque o ramo esquerdo da árvore como 0 e o ramo direito como 1; (esquerda 0 e direita 1)
direito | Codificação Huffman |
---|---|
5 | 0 0 0 0 |
3 | 0 0 0 1 |
11 | 0 0 1 |
23 | 0 1 |
29 | 1 0 |
14 | 1 1 1 |
7 | 1 1 0 0 |
8 | 1 1 0 1 |
Quarto, a criação da árvore Huffman
Requisitos:
1. Insira ne a probabilidade de n caracteres do teclado.
Por exemplo: Sabe-se que apenas n tipos de caracteres podem aparecer em um determinado sistema na comunicação, e suas probabilidades são, respectivamente, 0,05, 0,29, 0,07, 0,08, 0,14, 0,23, 0,03, 0,11. Tente projetar um código de Huffman para criar uma árvore Huffman.
2. Use o armazenamento sequencial.
#include<iostream>
using namespace std;
//哈夫曼树的存储结构
typedef struct {
int weight; //结点的权重
int parent, lchild, rchild; //结点的双亲、左孩子、右孩子的下标
}HTNode,*HuffmanTree;
//封装两个最小结点
typedef struct {
int s1;
int s2;
}MIN;
//选择双亲为0且结点权值最小的两个结点
MIN Select(HuffmanTree HT, int n)
{
int min, secmin,s1,s2;
min = 10000;
secmin = 10000;
MIN code;
s1 = 1; s2 = 1;
for (int i = 1; i <= n; i++)
{
if (HT[i].parent == 0 && (HT[i].weight<min))
{
min = HT[i].weight;
s1 = i;
}
}
for (int i = 1; i <= n; i++)
{
if (HT[i].parent == 0 && (HT[i].weight<secmin) && (i != s1))
{
secmin = HT[i].weight;
s2 = i;
}
}
code.s1 = s1;
code.s2 = s2;
return code;
}
//创造哈夫曼树
void CreateHuffmanTree(HuffmanTree &HT, int num)
{
int m;
m = 2 * num - 1;
HT = new HTNode[m + 1];
for (int i = 1; i <= m; i++)
{
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
cout << "请输入每个叶子结点的权值:" << endl;
for (int i = 1; i <= num; i++)
{
cin >> HT[i].weight;
}
for (int i = num + 1; i <= m; i++)
{
MIN min;
min=Select(HT,i-1);
HT[min.s1].parent = i;
HT[min.s2].parent = i;
HT[i].lchild = min.s1;
HT[i].rchild = min.s2;
HT[i].weight = HT[min.s1].weight + HT[min.s2].weight;
}
//输出哈夫曼树存储结构的末态
for (int i = 1; i <= m; i++)
{
cout << "结点序号 " << i << " 权重 " << HT[i].weight << " parent " << HT[i].parent << " lchild " << HT[i].lchild << " rchild " << HT[i].rchild << endl;
}
}
int main()
{
cout << "开始创建哈夫曼树" << endl;
int num; //结点的个数
cout << "请输入哈夫曼树叶子结点的个数:";
cin >> num;
//创造哈夫曼树
HuffmanTree HT;
CreateHuffmanTree(HT, num);
return 0;
}