免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: holyzfy
打印 上一主题 下一主题

关于中序遍历HuffmanTree的问题 [复制链接]

论坛徽章:
0
11 [报告]
发表于 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都是左右孩子结构体在该数组中的索引,大体上可以解释通  

论坛徽章:
0
12 [报告]
发表于 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 编辑 ]

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
13 [报告]
发表于 2007-05-31 19:45 |只看该作者
原帖由 holyzfy 于 2007-5-31 18:56 发表
[code]
/****************************************************************************
文件名:Huffman.cpp
修改历史:
         1.函数Output(HT,HC,n)的输出表示增加了制表位
         2.修改Select(H ...

先去吃饭,有时间帮你看看。

论坛徽章:
0
14 [报告]
发表于 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图片

论坛徽章:
0
15 [报告]
发表于 2007-05-31 21:14 |只看该作者
晕,只看了第一贴,没看到后面:)

论坛徽章:
0
16 [报告]
发表于 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)
复制代码

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
17 [报告]
发表于 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。
程序的输出是多少?

论坛徽章:
0
18 [报告]
发表于 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

论坛徽章:
0
19 [报告]
发表于 2007-06-01 09:08 |只看该作者
我觉得她的那个代码写的比较晦涩,
我想如果是我写,我可能应该是用指针,而不是用整形来表示那个地址。虽然可以用,
但是程序不好理解。

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
20 [报告]
发表于 2007-06-01 09:17 |只看该作者
原帖由 ailantian 于 2007-6-1 09:08 发表
我觉得她的那个代码写的比较晦涩,
我想如果是我写,我可能应该是用指针,而不是用整形来表示那个地址。虽然可以用,
但是程序不好理解。

用整数就是为了避免使用指针。
我觉得理解起来不算难吧,
如果你学过数据结构。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP