数据结构-树-哈夫曼树

概念

路径和路径长度

在一棵树中,从一个节点往下可以达到的孩子或孙子节点之间的通过,称为路径。通路中分支的数目称为路径长度。若规定根节点的层数为1,则从根节点到第L层节点的路径长度为L-1

节点的权及带权路径长度

若将树中节点赋给一个有着某种意义的数值,则这个数值称为该结点的权,节点的带权路径长度为:从根节点到该结点之间的路径长度与该结点的权的乘积

树的带权路径长度

树的带权路径长度规定为所有叶子节点的带权路径长度和,记为WPL(weighted path length),权值越大的节点离根节点越近的二叉树才是最优二叉树

WPL最小的树就是哈夫曼树

生成哈夫曼树流程

1 从小到大排序,将每个数据看成一个节点,每个节点可以看为一个最简单二叉树来处理

2 找出根节点权值最小的两个数

3 组成一颗新的二叉树,该新的二叉树的权值是组成的二叉树的权值的和

4 继续循环,知道所有数据处理完毕

Huffman编码

 

 

代码实现-huffman树

 

  1 #define _CRT_SECURE_NO_WARNINGS
  2 #include<iostream>
  3 #include<stdio.h>
  4 using namespace std;
  5 #define MAXNODENUM 100    //假设最多节点为100个
  6 #define MAXCODENUM 100    //假设编码最多100位
  7 typedef struct BinaryNode
  8 {
  9     int value;
 10     int flag;
 11     struct BinaryNode* parent;
 12     struct BinaryNode* lchild;
 13     struct BinaryNode* rchild;
 14 }HF_NODE,*PHF_NODE;
 15 typedef struct
 16 {
 17     int HuffmanCode[MAXCODENUM];
 18     int start;
 19 }huffcode,*phuffcode;
 20 void PreOrderTraverse(PHF_NODE a)
 21 {
 22     if (a == NULL)
 23         return;
 24     printf("%d\n", a->value);
 25     PreOrderTraverse(a->lchild);
 26     PreOrderTraverse(a->rchild);
 27 }
 28 void InitHuffmanTree(PHF_NODE head, int SumNumNode)
 29 {
 30     PHF_NODE Min_Location1=NULL, Min_Location2=NULL;//定义最小的两个节点的指针
 31     int    Min1=0, Min2=0;//定义最小的两个数的标志
 32     //一共还要初始化n-1个节点
 33     for (int i = SumNumNode; i < 2*SumNumNode - 1; i++)
 34     {
 35         //找出最小的第一颗树
 36         for (int j = 0; j < 2 * SumNumNode-1; j++)
 37         {
 38             if (head[j].value == 0)
 39             {
 40                 continue;//如果权值为0直接略过
 41             }
 42             if (head[j].flag == 1)
 43             {
 44                 continue;//如果flag位为1也直接略过
 45             }
 46             //用不是空,且flag=0的节点来假设为最小节点
 47             Min_Location1 = head + j;
 48             Min1 = Min_Location1->value;
 49             for (int t = 0; t < 2 * SumNumNode - 1; t++)//找出最小的第一颗树
 50             {
 51                 if (head[t].value == 0)
 52                 {
 53                     continue;//如果权值为0直接略过
 54                 }
 55                 if (head[t].flag == 1)
 56                 {
 57                     continue;//如果flag位为1也直接略过
 58                 }
 59                 if (head[t].value < Min1)
 60                 {
 61                     Min_Location1 = head + t;
 62                     Min1 = head[t].value;
 63                 }
 64             }
 65             Min_Location1->flag = 1;
 66             break;
 67         }
 68         //找出最小的第二颗树
 69         for (int j = 0; j < 2 * SumNumNode - 1; j++)//找出最小的第一颗树
 70         {
 71             if (head[j].value == 0)
 72             {
 73                 continue;//如果权值为0直接略过
 74             }
 75             if (head[j].flag == 1)
 76             {
 77                 continue;//如果flag位为1也直接略过
 78             }
 79             //用不是空,且flag=0的节点来假设为最小节点
 80             Min_Location2 = head + j;
 81             Min2 = Min_Location2->value;
 82             for (int t = 0; t < 2 * SumNumNode - 1; t++)//找出最小的第二颗树
 83             {
 84                 if (head[t].value == 0)
 85                 {
 86                     continue;//如果权值为0直接略过
 87                 }
 88                 if (head[t].flag == 1)
 89                 {
 90                     continue;//如果flag位为1也直接略过
 91                 }
 92                 if (head[t].value < Min1)
 93                 {
 94                     Min_Location2 = head + t;
 95                     Min2 = head[t].value;
 96                 }
 97             }
 98             Min_Location2->flag = 1;
 99             break;
100         }
101 
102         if (Min_Location1 == NULL || Min_Location2 == NULL)
103         {
104             return;
105         }
106         //建立新节点联系上
107         head[i].lchild = Min_Location1;
108         head[i].rchild = Min_Location2;
109         head[i].value = Min1 + Min2;
110         
111         Min_Location1->parent = head + i;
112         Min_Location2->parent = head + i;
113 
114         Min_Location1 = NULL;
115         Min_Location2 = NULL;
116         Min1 = 0;
117         Min2 = 0;
118     }
119 }
120 PHF_NODE GetRootNode(PHF_NODE head, int SumNumNode)
121 {
122     for (int i = 0; i < 2 * SumNumNode - 1; i++)
123     {
124         if (head[i].parent == NULL)
125         {
126             return head + i;
127         }
128     }
129     return NULL;
130 }
131 
132 void HuffmanTree()
133 {
134     HF_NODE hf_node[MAXNODENUM];//定义最大节点数
135 
136     printf("please input node's num,最多为50个\n");
137     int SumNumNode;
138     scanf("%d", &SumNumNode);
139     for (int i = 0; i < SumNumNode * 2 - 1; i++)//初始化所有节点数
140     {
141         hf_node[i].value = 0;
142         hf_node[i].flag = 0;
143         hf_node[i].parent = NULL;
144         hf_node[i].lchild = NULL;
145         hf_node[i].rchild = NULL;
146     }
147     printf("please input leaf node value\n");
148     //输入初始化节点的value
149     for (int i = 0; i < SumNumNode; i++)
150     {
151         scanf("%d",&(hf_node[i].value));
152     }
153     //创建huffman树
154     InitHuffmanTree(hf_node, SumNumNode);
155     PHF_NODE root = GetRootNode(hf_node,SumNumNode);
156     PreOrderTraverse(root);
157     HuffmanCode(hf_node, SumNumNode * 2 - 1);
158 }
159 
160 
161 
162 
163 int main()
164 {
165     HuffmanTree();
166     return 0;
167 }