Chinaunix

标题: 关于中序遍历HuffmanTree的问题 [打印本页]

作者: holyzfy    时间: 2007-05-31 13:15
标题: 关于中序遍历HuffmanTree的问题
InOrderTraverse(HT2+HT->lchild,HT2); //什么意思啊?


  1. /*中序遍历HuffmanTree,输出其结点值,并对内部结点作标记*/
  2. void InOrderTraverse(HuffmanTree HT,HuffmanTree HT2)
  3. {
  4.         if(HT->lchild!=0)
  5.                 InOrderTraverse(HT2+HT->lchild,HT2); //什么意思啊?
  6.         {//如果某个结点有孩子,显然它是内结点,应将其标记出来
  7.                 if(HT->lchild!=0)
  8.                         cout<<","<<HT->weight<<"(内点)";
  9.                 else
  10.                         cout<<","<<HT->weight;
  11.         }
  12.         if(HT->rchild!=0)
  13.                 InOrderTraverse(HT2+HT->rchild,HT2);
  14. }

  15. //附HuffmanTree的存储结构
  16. typedef struct
  17. {  
  18.         char letter;
  19.         int weight;
  20.         int parent;
  21.         int lchild;
  22.         int rchild;
  23. }HTNode,*HuffmanTree;
复制代码

[ 本帖最后由 holyzfy 于 2007-5-31 13:35 编辑 ]
作者: MMMIX    时间: 2007-05-31 13:52
原帖由 holyzfy 于 2007-5-31 13:15 发表
InOrderTraverse(HT2+HT->lchild,HT2); //什么意思啊?

[code]
/*中序遍历HuffmanTree,输出其结点值,并对内部结点作标记*/
void InOrderTraverse(HuffmanTree HT,Huf ...

What's your question?
作者: channelV    时间: 2007-05-31 14:38
递归处理,但参数没看明白
作者: holyzfy    时间: 2007-05-31 16:05
这是别人的一段程序,能正确执行,由于没有注释,我也看不明白,又不能联系他本人,只能求助大家了,
递归调用很好理解,只是这句“InOrderTraverse(HT2+HT->lchild,HT2);”里的 参数搞不懂,
如果不用这段程序,还能否用其他的途径实现?

作者: MMMIX    时间: 2007-05-31 16:48
原帖由 holyzfy 于 2007-5-31 16:05 发表
这是别人的一段程序,能正确执行,由于没有注释,我也看不明白,又不能联系他本人,只能求助大家了,
递归调用很好理解,只是这句“InOrderTraverse(HT2+HT->lchild,HT2);”里的 参数搞不 ...

理解算法(晦涩代码)的不二法门:几大张白纸 + 铅笔。
作者: kf701    时间: 2007-05-31 16:48
从每个叶子节点往根遍历不就生成了  huffman code 了嘛

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct{
        unsigned long weight;
        int parent, lchild, rchild;
} HTNode, *HuffmanTree;

typedef char** HuffmanCode;

//HuffmanCode HC;

void Select(HuffmanTree HT, int n, int *s1, int *s2);

struct wandc{
        int w;
        int c;
        char *cd;
};

void HuffmanCoding(struct wandc *wc, int n)
{
        int i;
        if( n<=1 ) return;
        int m = 2*n - 1;
        HuffmanTree p;
        HuffmanTree HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode));
        memset(HT, 0, sizeof(HTNode) * (m+1));
        for( p=HT,i=1; i<=n; ++i,++p )
        {
                HT[i].weight = wc[i].w;
        }
        int s1=0, s2=0;
        for( i=n+1; i<=m; ++i )
        {
                Select(HT, i-1, &s1, &s2);
                HT[s1].parent = i; HT[s2].parent = i;
                HT[i].lchild = s1; HT[i].rchild = s2;
                HT[i].weight = HT[s1].weight + HT[s2].weight;
        }

        //HC = (HuffmanCode)malloc((n+1)*sizeof(char*));
        char *cd = (char*)malloc(n*sizeof(char));
        cd[n-1] = 0;
        int start;
        unsigned long f;
        for( i=1; i<=n; ++i )
        {
                start = n - 1;
                int c;
                for( c=i, f=HT[i].parent; f!=0; c=f, f=HT[f].parent )
                {
                        if( HT[f].lchild == c ) cd[--start] = '0';
                        else cd[--start] = '1';
                }

                wc[i].cd = (char*)malloc((n-start)*sizeof(char));
                strcpy(wc[i].cd, &cd[start]);
        }
        free( HT );
}

void Select(HuffmanTree HT, int n, int *s1, int *s2)
{
        int i;
        HT[0].weight = (unsigned long)(-1l);
        *s1 = *s2 = 0;
        for( i=1; i<=n; i++ )
                if( HT[i].parent == 0 )
                {
                        if( HT[i].weight < HT[*s1].weight )
                        {
                                *s2 = *s1;
                                *s1 = i;
                        }
                        else if( HT[i].weight < HT[*s2].weight )
                        {
                                *s2 = i;
                        }
                }
}

int main()
{
        char buf[128];
        fgets(buf, sizeof(buf), stdin);
        int len = strlen(buf);
        buf[len-1] = 0;
        len--;
        unsigned long weight[256];
        memset( weight, 0, sizeof(weight));
        int i;
        for(i=0; i<len; i++)
        {
                weight[buf[i]]++;
        }

        int n = 0;
        for(i=0; i<256; i++)
                if( weight[i] )
                        n++;

        printf("num of char = %d\n", n);

        struct wandc *array = (struct wandc*)malloc(sizeof(struct wandc)*(n+1));
        int j =1;
        for(i=0; i<256; i++)
                if( weight[i] )
                {
                        array[j].w = weight[i];
                        array[j].c = i;
                        j++;
                }

        HuffmanCoding( array, n );

        printf("\n");
        for(i=1; i<=n; i++)
                printf("char=%c,w=%d: %s\n", array[i].c,array[i].w,array[i].cd);

        printf("\n");
        for(i=0; i<len; i++)
        {
                for(j=0; j<n; j++)
                        if( buf[i] == array[j].c )
                                break;
                printf("%s",array[j].cd);
        }
        printf("\n");

        return 0;
}
作者: holyzfy    时间: 2007-05-31 17:23
原帖由 MMMIX 于 2007-5-31 16:48 发表
理解算法(晦涩代码)的不二法门:几大张白纸 + 铅笔。

呵呵,我也知道“大白纸 + 铅笔”,可也得先有个思路吧,我最想知道的是具体的解释,或者,一个说下算法思想也可以啊,~
诚恳求教


[ 本帖最后由 holyzfy 于 2007-5-31 17:30 编辑 ]
作者: MMMIX    时间: 2007-05-31 17:35
原帖由 holyzfy 于 2007-5-31 17:23 发表

呵呵,我也知道“大白纸 + 铅笔”,可也得先有个思路吧,我最想知道的是具体的解释,或者,一个说下算法思想也可以啊,~
诚恳求教

老实说,说了也白说!许多东西别人是无法代替你的,例如说学习;同时许多东西也是无法速成的,例如基础;另外还有许多东西是需要积累的,例如经验。
作者: windaoo    时间: 2007-05-31 17:44
原帖由 MMMIX 于 2007-5-31 17:35 发表

许多东西别人是无法代替你的,例如说学习;同时许多东西也是无法速成的,例如基础;另外还有许多东西是需要积累的,例如经验。


说得好
作者: lenovo    时间: 2007-05-31 17:52
希望楼主能贴一个完整的代码出来。
作者: xiaxueyi    时间: 2007-05-31 18:20
原帖由 holyzfy 于 2007-5-31 13:15 发表
InOrderTraverse(HT2+HT->lchild,HT2); //什么意思啊?

[code]
/*中序遍历HuffmanTree,输出其结点值,并对内部结点作标记*/
void InOrderTraverse(HuffmanTree HT,Huf ...



我估计,程序用的是一个结构体数组来存储树的信息,HT2是该数组的首地址,HT是当前节点的结构体地址,lchild和rchild都是左右孩子结构体在该数组中的索引,大体上可以解释通  
作者: holyzfy    时间: 2007-05-31 18:56

  1. /****************************************************************************
  2. 文件名:Huffman.cpp
  3. 修改历史:
  4.          1.函数Output(HT,HC,n)的输出表示增加了制表位
  5.          2.修改Select(HuffmanTree &HT,int i,int &s1,int &s2),
  6.            具体为:for(j = 1; j <= i; j++)之处为把j<i改成j<=i
  7. 尚存在的问题:中序遍历??
  8. 最后修改日期:2007,5,30
  9. *****************************************************************************/
  10. #include <stdlib.h>
  11. #include <iostream.h>
  12. #include <string.h>

  13. #define MAX_SIZE 50
  14. #define  OVERFLOW -1

  15. typedef struct
  16. {  
  17.         char letter;
  18.         int weight;
  19.         int parent;
  20.         int lchild;
  21.         int rchild;
  22. }HTNode,*HuffmanTree;

  23. typedef char * *HuffmanCode;

  24. /***************************************************************************
  25. 函数名称:void Select(HuffmanTree &HT,int i,int &s1,int &s2)
  26. 功能描述:在HT[1...i]选择parent为空且weight最小的两个结点,其下标分别为s1,s2
  27. 具体实现:先把输入的第一个字符的权值的下标赋给s1,然后把每个字符的权值与 HT[s1].weight比较,
  28.           直至遍历输入的所有字符,把权值最小的下标赋给s1;用同样的方法再找到s2
  29. ****************************************************************************/
  30. void Select(HuffmanTree &HT,int i,int &s1,int &s2)
  31. {
  32.         int j, k;

  33.         for(k = 1; k < i; k++)
  34.         {
  35.                 if(HT[k].parent != NULL)
  36.                         continue;
  37.                 s1 = k; //初始化s1
  38.                 break;
  39.         }

  40.         for(j = 1; j <= i; j++)
  41.         {
  42.                 if(HT[j].parent != NULL)
  43.                         continue;
  44.                 if(HT[j].weight < HT[s1].weight)
  45.                         s1 = j;
  46.         }

  47.         for(k = 1; k <= i; k++)
  48.         {
  49.                 if(HT[k].parent != NULL || k == s1)
  50.                         continue;
  51.                 s2 = k;
  52.                 break;
  53.         }
  54.        
  55.         for(j = 1; j <= i; j++)
  56.         {
  57.                 if(HT[j].parent != NULL)
  58.                         continue;
  59.                 if(HT[j].weight <= HT[s2].weight && j != s1)
  60.                         s2 = j;
  61.         }
  62.        
  63. } //end of void Select(HuffmanTree &HT,int i,int &s1,int &s2)


  64. /*根据输入的字符及其权值建立哈夫曼树*/
  65. void Creat_HuffmanTree(HuffmanTree &HT,HuffmanCode &HC,char *zifu,int *w,int n)
  66. {
  67.         HuffmanTree p;
  68.         int m,s1,s2;
  69.         for(int i=0;i<n;i++) //输入字符
  70.         {
  71.                 cout<<"请输入第"<<i+1<<"个字符:";
  72.                 cin>>zifu[i];
  73.         }

  74.         for(i=0;i<n;i++) //输入字符对应的权值
  75.         {
  76.                 cout<<"请输入字符"<<zifu[i]<<"的权值:";
  77.                 cin>>w[i];
  78.         }
  79.        
  80.         if(n <= 1)
  81.                 return;
  82.         m = 2*n-1;
  83.         if(!(HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode))))
  84.                 exit(OVERFLOW);
  85.         for(p=HT+1,i=1;i<=n;++i,++zifu,++p,++w)
  86.         {
  87.                 /*生成独立的森林*/
  88.                 p->parent = NULL;
  89.                 p->letter = *zifu;
  90.                 p->lchild = NULL;
  91.                 p->rchild = NULL;
  92.                 p->weight = *w;
  93.         }
  94.        
  95.         for(;i<=m;++i,++p)
  96.         {
  97.                 (*p).weight=0;
  98.                 (*p).parent=0;
  99.                 (*p).lchild=0;
  100.                 (*p).rchild=0;
  101.         }
  102.        
  103.         for(i=n+1;i<=m;++i)
  104.         {
  105.                 Select(HT,i-1,s1,s2);
  106.                 HT[s1].parent=i;
  107.                 HT[s2].parent=i;
  108.                 HT[i].lchild=s1;
  109.                 HT[i].rchild=s2;
  110.                 HT[i].weight=HT[s1].weight+HT[s2].weight;
  111.         }
  112. }

  113. /*从叶子到根求每个字符的编码*/
  114. void  HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,char *zifu,int *w,int n)
  115. {
  116.     int c,f;
  117.         char *cd;
  118.         int start = 1;
  119.         HC=(HuffmanCode)malloc((n+1)*sizeof(char *));
  120.         cd=(char*)malloc(n*sizeof(char));/*临时的code存储*/
  121.         cd[n-1]='\0'; //编码结束符

  122.         for(int i=1;i<=n;++i)
  123.         {
  124.                 start = n - 1; //编码结束符位置

  125.         //从叶子到根逆向求编码
  126.                 for(c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
  127.                         if(HT[f].lchild == c)
  128.                                 cd[--start] = '0'; //树中的左分支表示字符'0'
  129.                         else
  130.                                 cd[--start] = '1'; //树中的右分支表示字符'1'
  131.                         HC[i] = (char *)malloc((n - start) * sizeof(char));
  132.                         strcpy(HC[i], &cd[start]);        //从cd复制编码(串)到HC       
  133.         }
  134.         free(cd);
  135. }

  136. /*中序遍历HuffmanTree,输出其结点值,并对内部结点作标记*/
  137. void InOrderTraverse(HuffmanTree HT,HuffmanTree HT2)
  138. {
  139.         if(HT->lchild!=0)
  140.                 InOrderTraverse(HT2+HT->lchild,HT2);
  141.         {//如果某个结点有孩子,显然它是内结点,应将其标记出来
  142.                 if(HT->lchild!=0)
  143.                         cout<<","<<HT->weight<<"(内点)";
  144.                 else
  145.                         cout<<","<<HT->weight;
  146.         }
  147.         if(HT->rchild!=0)
  148.                 InOrderTraverse(HT2+HT->rchild,HT2);
  149. } //end of void InOrderTraverse(HuffmanTree HT,HuffmanTree HT2,int n)

  150. /*输出各字符的哈夫曼编码*/
  151. void Output_HuffmanTree(HuffmanTree &HT,HuffmanCode &HC,int n)
  152. {
  153.         cout<<"\nchar"<<"\tweight"<<"\thuffmancode\n";
  154.     for(int i=1;i<=n;i++)
  155.         cout<<HT[i].letter<<"\t"<<HT[i].weight<<"\t"<<HC[i]<<endl;
  156. } //end of void Output_HuffmanTree(HuffmanTree &HT,HuffmanCode &HC,int n)

  157. void main()
  158. {
  159.         HuffmanTree HT;
  160.         HuffmanCode HC;
  161.         int i=0;
  162.         char zifu[MAX_SIZE]; //zifu[]为存放字符的数组
  163.         int n=0,w[MAX_SIZE]; //w[]为存放权值的数组
  164.         cout<<"请输入字符的个数:";
  165.         cin>>n;
  166.         if(n<=0 || n>MAX_SIZE)
  167.         {
  168.                 cerr<<"字符个数必须为不大于50的自然数!\n";
  169.                 exit(1);
  170.         }
  171.     Creat_HuffmanTree(HT,HC,zifu,w,n);
  172.         HuffmanCoding(HT,HC,zifu,w,n);
  173.     Output_HuffmanTree(HT,HC,n);

  174.         {//这个花括号内的功能为中序遍历HuffmanTree
  175.     while(HT[i].parent!=0) i++; //确定HuffmanTree的所有结点数i
  176.     cout<<"\n中序遍历HuffmanTree结果如下:\n";
  177.         InOrderTraverse(HT+i,HT);
  178.         cout<<endl;
  179.         }
  180. } //end of void main()
复制代码

[ 本帖最后由 holyzfy 于 2007-5-31 21:11 编辑 ]
作者: lenovo    时间: 2007-05-31 19:45
原帖由 holyzfy 于 2007-5-31 18:56 发表
[code]
/****************************************************************************
文件名:Huffman.cpp
修改历史:
         1.函数Output(HT,HC,n)的输出表示增加了制表位
         2.修改Select(H ...

先去吃饭,有时间帮你看看。
作者: ailantian    时间: 2007-05-31 21:05
我来回复一下,如果不对的话,大家包含
楼主参数没给清楚,让大家猜,就像话说半句,让别人看什么意思。难为人了。
有参数来看
比如我们分析一种最简单的情况,假设左节点一直有,这个程序的过程应当如下
遍历的节点为A,B,C,D,E,F........等等
则其第一个参数的分析如下,HT2因为是一个地址,所以我们可以当一个常数来看待,假定是0x80000000
,至于最开始的地址,我们当根节点
A(HT,HT2)                    即判断根节点的左儿子的权值
B(HT2+HT->lchild,HT2)即HT2的地址,加上根节点的左儿子的权值
C(HT2+B->lchild,HT2) 即HT2的地址,加上B节点的左儿子的权值
D(HT2+C->lchild,HT2) 即HT2的地址,加上C节点的左儿子的权值
E(HT2+D->lchild,HT2)
F(HT2+E->lchild,HT2)


内存结构示意图大致如下
至于内存为什么不重复,这个可能和生成树的时候的约定有关。
主意遍历的顺序是走 根->A->B->C->D.....

[ 本帖最后由 ailantian 于 2007-5-31 21:09 编辑 ]

HT.png (10.16 KB, 下载次数: 32)

内存示意图

内存示意图

HT.dia.gz

1.45 KB, 下载次数: 15

dia图片


作者: ailantian    时间: 2007-05-31 21:14
晕,只看了第一贴,没看到后面:)
作者: holyzfy    时间: 2007-05-31 22:07
终于联系到写这段程序的本人了,呵呵,还是个女的~,她说的意思是HT2+HT->lchild可以看成是HT2[HT->lchild],这样就好理解了,可是改后并不能直接用,编译器提示“ error C2664: 'InOrderTraverse' : cannot convert parameter 1 from 'HTNode' to 'HTNode *'”,这个错误好改,取地址就行了,
附上改后的程序


  1. /*中序遍历HuffmanTree,输出其结点值,并对内部结点作标记*/
  2. void InOrderTraverse(HuffmanTree HT,HuffmanTree HT2)
  3. {
  4.         if(HT->lchild!=0)
  5.                 InOrderTraverse(HT2[HT->lchild],HT2);
  6.         {//如果某个结点有孩子,显然它是内结点,应将其标记出来
  7.                 if(HT->lchild!=0)
  8.                         cout<<","<<HT->weight<<"(内点)";
  9.                 else
  10.                         cout<<","<<HT->weight;
  11.         }
  12.         if(HT->rchild!=0)
  13.                 InOrderTraverse(&HT2[HT->rchild],HT2);
  14. } //end of void InOrderTraverse(HuffmanTree HT,HuffmanTree HT2,int n)
复制代码

作者: lenovo    时间: 2007-05-31 22:17
原帖由 holyzfy 于 2007-5-31 22:07 发表
终于联系到写这段程序的本人了,呵呵,还是个女的~,她说的意思是HT2+HT->lchild可以看成是HT2[HT->lchild],这样就好理解了,可是改后并不能直接用,编译器提示“ error C2664: 'InOr ...

明白就好。
给你4个字母,
分别是a,b,c,d,
权重分别为3,4,5,6。
程序的输出是多少?
作者: holyzfy    时间: 2007-05-31 22:35
不介意被你考,毕竟才学数据结构

char    weight  huffmancode
a       3       00
b       4       01
c       5       10
d       6       11

中序遍历HuffmanTree结果如下:
,3,7(内点),4,18(内点),5,11(内点),6

作者: ailantian    时间: 2007-06-01 09:08
我觉得她的那个代码写的比较晦涩,
我想如果是我写,我可能应该是用指针,而不是用整形来表示那个地址。虽然可以用,
但是程序不好理解。
作者: lenovo    时间: 2007-06-01 09:17
原帖由 ailantian 于 2007-6-1 09:08 发表
我觉得她的那个代码写的比较晦涩,
我想如果是我写,我可能应该是用指针,而不是用整形来表示那个地址。虽然可以用,
但是程序不好理解。

用整数就是为了避免使用指针。
我觉得理解起来不算难吧,
如果你学过数据结构。
作者: ailantian    时间: 2007-06-01 12:21
原帖由 lenovo 于 2007-6-1 09:17 发表

用整数就是为了避免使用指针。
我觉得理解起来不算难吧,
如果你学过数据结构。


呵呵,如果是我还是会用指针,
像树,链表,当然你可以用整数构造,但是我觉得移植性可能不好吧。
内存地址不一定和int型相同。
再说这样的数据结构本身是链状结构,用链不是更容易理解一些吗。

不过要说java没指针不知道怎么实现,没看过
作者: lenovo    时间: 2007-06-01 14:06
原帖由 ailantian 于 2007-6-1 12:21 发表


呵呵,如果是我还是会用指针,
像树,链表,当然你可以用整数构造,但是我觉得移植性可能不好吧。
内存地址不一定和int型相同。
再说这样的数据结构本身是链状结构,用链不是更容易理解一些吗。

不过要 ...

〉〉移植性可能不好吧。
哪里移植性不好了?
〉〉内存地址不一定和int型相同。
这句话又是什么意思呢?
作者: redbison    时间: 2007-06-04 14:03
原帖由 lenovo 于 2007-5-31 22:17 发表

明白就好。
给你4个字母,
分别是a,b,c,d,
权重分别为3,4,5,6。
程序的输出是多少?


lenovo的这个题目权重太平均了吧!至少也要有点层次区别才体现Huffman Code的特点呀!期末考试出这样的题目课程负责人回提意见的。


[ 本帖最后由 redbison 于 2007-6-4 14:05 编辑 ]
作者: lenovo    时间: 2007-06-04 17:57
原帖由 redbison 于 2007-6-4 14:03 发表


lenovo的这个题目权重太平均了吧!至少也要有点层次区别才体现Huffman Code的特点呀!期末考试出这样的题目课程负责人回提意见的。

呵呵,当时随便想的。
没想到是平均的。
他的程序写的很奇怪,
数组下标是从1开始,
我怀疑以前是不是写pascal程序的。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2