哈夫曼树 构造,编码 完整代码

Haffman Tree

构造方法:
1.初始化每个叶子结点都是一棵树。
2.找最小权值的两棵树。
3.合并两树,生成新结点。
编码:
1.往左为1,右为0.
2.不等长编码。

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
​
#define MaxN 100 //最大结点个数
#define Maxbit 255 //最大编码值
#define MaxValue 9999 //最大权值
​
//树储存结构
typedef struct
{
     int weight;//权值
     int flag;//标记,flag==1则已经加入到hafftree中
     int parent;//父结点下标
     int leftChild;//左孩子结点下标
     int rightChild;//右孩子结点下标
}HaffNode;
​
//哈夫曼编码结构
typedef struct
{
     int bit[MaxN];//每个叶子结点到根节点路径所对应的哈夫曼编码
     int start;//编码起始下标
     int weight;//字符权值
}Code;
​
//建立hafftree
//叶节点数为n,权值数组为weight的hafftree*
void Haffman(int weight[], int n, HaffNode haffTree[])
{
     int i, j, m1, m2, x1, x2;
​
     //初始化hafftree
     //共有n*2+1个结点,前n个是叶子结点
     for (i = 0; i < 2 * n - 1; i++)
     {
          if (i < n)
          {
               haffTree[i].weight = weight[i];
          }
          else
          {
               haffTree[i].weight = 0;
          }
          haffTree[i].parent = 0;
          haffTree[i].flag = 0;
          haffTree[i].leftChild = -1;
          haffTree[i].rightChild = -1;
}
​
     //构造hafftree的n-1个非叶子结点
     for (i = 0; i < n-1; i++)
     {
          //找到权值最小的两颗树的下标x1,x2
          m1 = m2 = MaxValue;
          x1 = x2 = 0;
          for (j = 0; j < n + i; j++)
          {
               //先找一颗权值较小的树,再找另一颗
               if (haffTree[j].weight < m1 && haffTree[j].flag == 0)
               {
                    m2 = m1;
                    x2 = x1;
                    m1 = haffTree[j].weight;
                    x1 = j;
               }
               else if (haffTree[j].weight < m2 && haffTree[j].flag == 0)
               {
                    m2 = haffTree[j].weight;
                    x2 = j;
               }
          }
          //将找出的两棵权值最小的子树合并为一棵子树
          haffTree[x1].parent = n + i;
          haffTree[x2].parent = n + i;
          haffTree[x1].flag = 1;//表示都已经加入hafftree
          haffTree[x2].flag = 1;
          haffTree[n + i].weight = haffTree[x1].weight + haffTree[x2].weight;
          haffTree[n + i].leftChild = x1;
          haffTree[n + i].rightChild = x2;
     }
}
​
//构造哈夫曼编码
//结点为n
void HaffmanCode(HaffNode haffTree[], int n, Code haffCode[])
{
     Code* cd = (Code*)malloc(sizeof(Code));
     int i, j, child, parent;
​
     //求n个叶节点的哈夫曼编码
     for (i = 0; i < n; i++)
     {
          cd->start = n - 1;
          cd->weight = haffTree[i].weight;
          child = i;
          parent = haffTree[child].parent;
          //由叶结点向上直到根结点
          while (parent != 0)
          {
               if (haffTree[parent].leftChild == child)//如果是左孩子
               {
                    cd->bit[cd->start] = 0;//左孩子分支编码
               }
               else//如果是右孩子
               {
                    cd->bit[cd->start] = 1;//右孩子分支编码
               }
               cd->start--;
               child = parent;
               parent = haffTree[child].parent;
          }
          for (j = cd->start + 1; j < n; j++)
          {
               haffCode[i].bit[j] = cd->bit[j];//保存每个叶节点的编码
          }
          haffCode[i].start = cd->start;//保存不等长编码的起始位
          haffCode[i].weight = cd->weight;//保存相应字符的权值
     }
}
​
void OutPut(int n, Code haffCode[])
{
     int i, j;
     for (i = 0; i < n; i++)
     {
          printf("weight=%d   Code=", haffCode[i].weight);
          for (j = haffCode[i].start + 1; j < n; j++)
          {
               printf("%6d", haffCode[i].bit[j]);
          }
          printf("\n");
     }
}
​
int main()
{
     int i, j, n;
     printf("请输入叶结点个数:");
     scanf("%d", &n);
     int weight[MaxN];
     printf("\n请输入各结点权值:");
     for (i = 0; i < n; i++)
     {
          scanf("%d", &weight[i]);
     }
     HaffNode* myHaffTree = (HaffNode*)malloc(sizeof(HaffNode) * (2 * n + 1));
     Code* myHaffCode = (Code*)malloc(sizeof(Code) * n);
     Haffman(weight, n, myHaffTree);
     HaffmanCode(myHaffTree, n, myHaffCode);
     OutPut(n, myHaffCode);
     return 0;
}

  • 8
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
构造是一种经典的编码方法,主要用于数据压缩和编码领域。构造的过程主要分为以下几个步骤: 1. 统计字符出现频率:首先需要统计待编码文本中每个字符出现的频率,可以通过遍历文本字符来实现。将字符频率存储于一个数组或者字典中。 2. 构建哈:基于字符频率,可以选择合适的数据结构来存储和构建哈。在构建过程中,首先将每个字符频率作为一个独立的叶子节点,然后再通过合并最小频率的节点来构造。 3. 分配编码:根据构建好的哈,给每个字符分配一个唯一的编码。从根节点开始,标记左子为0,右子为1,遍历哈至叶子节点,即可得到每个字符的编码。为了方便查找和使用编码,可以使用数组或者字典来存储字符和其编码的对应关系。 4. 编写编码代码:根据步骤3中得到的字符和编码的对应关系,编写编码函数来实现文本编码编码函数接受待编码的文本作为输入,然后将文本中的每个字符替换为其对应的编码。 下面是一个简单的C代码示例来演示哈的构建和编码过程: ```c #include <stdio.h> #include <stdlib.h> typedef struct Node { char character; int frequency; struct Node* left; struct Node* right; } Node; // 构建哈 Node* buildHuffmanTree(char* characters, int* frequencies, int n) { Node** nodes = (Node**)malloc(sizeof(Node*) * n); for(int i = 0; i < n; i++) { nodes[i] = (Node*)malloc(sizeof(Node)); nodes[i]->character = characters[i]; nodes[i]->frequency = frequencies[i]; nodes[i]->left = NULL; nodes[i]->right = NULL; } // 构建哈 while(n > 1) { Node* min1 = nodes[0]; int min1Index = 0; for(int i = 1; i < n; i++) { if(nodes[i]->frequency < min1->frequency) { min1 = nodes[i]; min1Index = i; } } Node* min2 = nodes[0 == min1Index ? 1 : 0]; int min2Index = 0 == min1Index ? 1 : 0; for(int i = 0; i < n; i++) { if(i != min1Index && nodes[i]->frequency < min2->frequency) { min2 = nodes[i]; min2Index = i; } } Node* parent = (Node*)malloc(sizeof(Node)); parent->character = '\0'; parent->frequency = min1->frequency + min2->frequency; parent->left = min1; parent->right = min2; nodes[min1Index] = parent; for(int i = min2Index; i < n - 2; i++) { nodes[i] = nodes[i + 1]; } nodes[n - 2] = parent; n--; } return nodes[0]; } // 分配编码 void assignCode(Node* tree, char** codes, char* code, int depth) { if(tree->left == NULL && tree->right == NULL) { codes[tree->character] = code; return; } code[depth] = '0'; code[depth + 1] = '\0'; assignCode(tree->left, codes, code, depth + 1); code[depth] = '1'; code[depth + 1] = '\0'; assignCode(tree->right, codes, code, depth + 1); } // 编码函数 char* encodeText(char* text, char** codes) { int textSize = strlen(text); int totalCodeLength = 0; char* encodedText = (char*)malloc(sizeof(char) * (textSize * 8 + 1)); for(int i = 0; i < textSize; i++) { char* code = codes[text[i]]; int codeLength = strlen(code); for(int j = 0; j < codeLength; j++) { encodedText[totalCodeLength] = code[j]; totalCodeLength++; } } encodedText[totalCodeLength] = '\0'; return encodedText; } int main() { // 示例数据 char characters[] = {'A', 'B', 'C', 'D', 'E'}; int frequencies[] = {2, 3, 4, 6, 8}; int n = sizeof(characters) / sizeof(char); // 构建哈 Node* huffmanTree = buildHuffmanTree(characters, frequencies, n); // 分配编码 char* codes[256]; char* code = (char*)malloc(sizeof(char) * 256); assignCode(huffmanTree, codes, code, 0); // 编码文本 char* text = "ABCDAEBD"; char* encodedText = encodeText(text, codes); printf("原始文本:%s\n", text); printf("编码后的文本:%s\n", encodedText); return 0; } ``` 注意,这只是一个简单的示例代码,实际应用中可能还需要考虑更多的边界条件和错误处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值