7.8 赫夫曼树应用解析(跟结点到叶子求每个字符的赫夫曼编码)

其他部分同 7.7赫夫曼树应用解析(叶子到根逆向求每个字符的赫夫曼编码)的编码,只更改HuffmanCoding函数来实现:如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/************************************************************************/
// 求解赫夫曼编码
/************************************************************************/

void HuffmanTreeCoding(HuffmanTree &HT, HuffmanCode &HC,  int* w,  int n)
// w存放n个字符的权值(均>0), 构造赫夫曼树,求出n个字符的赫夫曼编码HC
     if (n <=  1)
         return;

     int nNodes;      // 总结点和
     int nodeIndex;   // 根结点序号
    nNodes =   2 * n -  1;    

    HT = (HuffmanTree)malloc(  sizeof(HTNode) * (nNodes+ 1) );         // 0号单元未用

    HuffmanTree pTree;
    pTree = HT+ 1;
     for (nodeIndex= 1; nodeIndex <= n; ++nodeIndex,++pTree, ++w)
    {
        pTree->weight = *w;
        pTree->parent =  0;
        pTree->lchild =  0;
        pTree->rchild =  0;
    }

     for ( ; nodeIndex <= nNodes; ++nodeIndex, ++pTree)
        (*pTree).parent =  0;

     // 创建赫夫曼树
     int minIndex1, minIndex2;
     for (nodeIndex = n+ 1; nodeIndex <= nNodes; nodeIndex++)  // 循环n-1次
    {  // 在HT[1~nodeIndexs-1]中选择parent为0且weight最小的两个结点,其序号分别为minIndex1,minIndex2
        Select(HT, nodeIndex- 1, minIndex1, minIndex2);
        HT[minIndex1].parent = HT[minIndex2].parent = nodeIndex;
        HT[nodeIndex].lchild = minIndex1;
        HT[nodeIndex].rchild = minIndex2;
        HT[nodeIndex].weight = HT[minIndex1].weight + HT[minIndex2].weight;
    }

    HC = (HuffmanCode)malloc( (n+ 1)* sizeof( char*));
     
     // 分配n个字符编码的头指针向量([0]不用)
     char* codingSize;
    codingSize = ( char*)malloc( sizeof( char) * n);    // 分配求编码的工作空间
    
     unsigned  int c,  cdlen;
    c       =  nNodes;
    cdlen   =  0;
     for ( int i= 1; i <= nNodes; i++)
        HT[i].weight =  0;        // 遍历赫夫曼时用作结点标识

     while (c)
    {
         if (HT[c].weight ==  0)
        {  // 向左
            HT[c].weight =  1;
             if (HT[c].lchild !=  0)
            {
                c = HT[c].lchild;
                codingSize[cdlen++] =  '0';
            }
             else  if (HT[c].rchild ==  0)
            {    // 登记叶子结点的字符编码
                HC[c] = ( char*)malloc((cdlen+ 1) *  sizeof( char));
                codingSize[cdlen] =  '\0';
                strcpy(HC[c], codingSize);       // 复制编码(串)
            }
        }
         else  if (HT[c].weight ==  1)
        {    // 向右
            HT[c].weight =  2;
             if (HT[c].rchild !=  0)
            {
                c = HT[c].rchild;
                codingSize[cdlen++] =  '1';
            }
        }
         else
        {    // HT[c].weight = 2, 退回
            HT[c].weight =  0;
            c = HT[c].parent;
            --cdlen;         // 退到父结点,编码长度减1
        }
    }


//  // 从叶子到根逆向求每个字符的赫夫曼编码
//  HC = (HuffmanCode)malloc( (n+1)*sizeof(char*));
// 
//  // 分配n个字符编码的头指针向量([0]不用)
//  char* codingSize;
//  codingSize = (char*)malloc(sizeof(char) * n);   // 分配求编码的工作空间
//  codingSize[n-1] = '\0';     // 编码结束符
// 
//  for (nodeIndex = 1; nodeIndex <= n; nodeIndex++)
//  { // 逐个字符求赫夫曼编码
//      int pos;
//      unsigned int c, f;
//      pos = n - 1;        // 编码结束位置
// 
//      for (c=nodeIndex, f=HT[nodeIndex].parent; f != 0; c=f, f = HT[f].parent)
//      {   // 从叶子到根逆向求编码
//          if (HT[f].lchild == c)
//              codingSize[--pos] = '0';
//          else
//              codingSize[--pos] = '1';
//          
//          HC[nodeIndex] = (char*)malloc((n - pos) * sizeof(char));
//          // 为第i个字符编码分配空间
//          strcpy(HC[nodeIndex], &codingSize[pos]);  // 从codingSize复制编码串到HC
//      }
//  }
                        
    free(codingSize);    // 释放工作区间

     return;
}

输出结果:

你可能感兴趣的:(赫夫曼树,赫夫曼编码)