代码如下
#include<stdio.h>
#include<stdlib.h>
#define MinData 0
//(Huffman)Tree的定义
typedef struct TreeNode* Tree;
struct TreeNode{
int Data;
Tree Left;
Tree Right;
int Height;
};
typedef Tree HufTree;
//最小堆的定义
typedef struct HeapNode* Heap;
struct HeapNode{
Tree* Data;
int Size;
int Capacity;
};
typedef Heap MinHeap;
int Max(int a,int b)
{
return (a >= b ? a : b);
}
//以下三个函数都是建立Heap
Heap CreatHeap(int MaxSize)
{
Heap H = (Heap)malloc(sizeof(struct HeapNode));
H->Data = (Tree*)malloc(MaxSize*sizeof(Tree));
int i;
for(i=0;i<=MaxSize;i++){
H->Data[i] = (Tree)malloc(sizeof(struct TreeNode));
}
H->Capacity = MaxSize;
H->Size = 0;
H->Data[0]->Data = MinData;
return H;
}
void PercDown(MinHeap H,int p)
{
int Parent, Child;
Tree X;
X = H->Data[p];
for(Parent=p; Parent*2<=H->Size; Parent=Child){
Child = Parent*2;
if((Child!=H->Size) && (H->Data[Child]->Data > H->Data[Child+1]->Data))
Child++;
if( X->Data <= H->Data[Child]->Data ) break;
else
H->Data[Parent] = H->Data[Child];
}
H->Data[Parent] = X;
}
void BuildMinHeap( MinHeap H )
{
int i;
for( i = H->Size/2; i>0; i-- )
PercDown( H, i );
}
int IsFull( Heap H )
{
return (H->Size == H->Capacity);
}
void Insert( MinHeap H, Tree item )
{
int i;
if( IsFull(H) ) {
printf("IsFull\n");
return;
}
i = ++H->Size;
for( ; H->Data[i/2]->Data > item->Data; i/=2 )
H->Data[i] = H->Data[i/2];
H->Data[i] = item;
}
int IsEmpty( Heap H )
{
return (H->Size == 0);
}
Tree DeleteMin( MinHeap H )
{
int Parent, Child;
Tree MinItem, temp;
if( IsEmpty(H) ){
printf("IsEmpty\n");
return;
}
MinItem = H->Data[1];
temp = H->Data[H->Size--];
for( Parent=1; Parent*2<=H->Size; Parent=Child ) {
Child = Parent * 2;
if( (Child!=H->Size) && (H->Data[Child]->Data>H->Data[Child+1]->Data))
Child++;
if( temp->Data <= H->Data[Child]->Data ) break;
else
H->Data[Parent] = H->Data[Child];
}
H->Data[Parent] = temp;
return MinItem;
}
HufTree BuildFMinHeap( MinHeap H )
{
Tree T;
while(H->Size>=2){
Tree LT = DeleteMin( H );
Tree RT = DeleteMin( H );
//建立新Tree结点并初始化
T = malloc(sizeof(struct TreeNode));
T->Data = LT->Data + RT->Data;
T->Height = 0;
T->Left = LT;
T->Right = RT;
//将该结点插回H
Insert(H,T);
}
T = DeleteMin(H);
return T;
}
int InOrderTraversal( Tree BT, int MaxSize)
{
int WPL=0;
Tree T = BT;
Tree S[MaxSize];
int rear=-1;
int depth=0;
while( T || rear!=-1 ){
while(T){
S[++rear]=T;
if(T){
depth++;
T->Height=depth;
}
printf("T=%dT-Height=%d\n",T->Data,T->Height);
T = T->Left;
}
if(rear!=-1){
printf("IsOJ1\n");
T = S[rear--];
depth = T->Height;
printf("T->Height=%d\n",depth);
T = T->Right;
if(T){
depth++;
T->Height = depth;
}
printf("IsOJ2\n");
}
}
return WPL;
}
int main()
{
int N,i,x;
char c;
scanf("%d",&N);
Heap H = CreatHeap(N+1);
for(i=1;i<=N;i++){
scanf(" %c",&c);
scanf("%d",&x);
H->Data[i]->Data = x;
H->Data[i]->Height = 0;
H->Data[i]->Left = H->Data[i]->Right = NULL;
H->Size++;
}
printf("IsOK\n");
for(i=0;i<=N;i++){
printf("%3d",H->Data[i]->Data);
}
printf("\n");
BuildMinHeap(H);
//初始的MinHeap已经建立完成
printf("IsOK\n");
//接下来是建立HuffmanTree
HufTree T = BuildFMinHeap(H);
printf("H->Size=%d\n",H->Size);
//计算WPL
printf("IsOK\n");
/*若计算深度,需要遍历*/
int WPL = InOrderTraversal(T,2*N-1);
printf("%d",WPL);
}
运行结果如图
问
从上图可以看到,这个从T=10T-Height=1开始的输出是在函数InOrderTraversal()里面运行的。这里的BT在前面的运算中已经变成了一个链式存储的Huffman树。在我的InOrderTraversal()中,我就是发现嵌套的while里面,也就是
while(T){
S[++rear]=T;
if(T){
depth++;
T->Height=depth;
}
printf("T=%dT-Height=%d\n",T->Data,T->Height);
T = T->Left;
}
这里,他的depth似乎没有办法从下面的depth=T->Height里更新是吗?
比如我输入的代码中,原本按照我的程序T=<数字>T-Height=<数字>在T=6时应该被更新为2,但是他这个继续自增为3了,而且接下来的所有按照T=<数字>T-Height=<数字>输出的格式都刚好顺序递增。就挺奇怪的
分隔符
其实问题说白了就是在这里
int InOrderTraversal( Tree BT, int MaxSize)
{
int WPL=0;
Tree T = BT;
Tree S[MaxSize];
int rear=-1;
int depth=0;
while( T || rear!=-1 ){
while(T){
S[++rear]=T;
if(T){
depth += 1;//注意点1
T->Height=depth;
}
printf("T=%dT-Height=%d\n",T->Data,T->Height);
T = T->Left;
}
if(rear!=-1){
printf("IsOJ1\n");
T = S[rear--];
depth = T->Height;//注意点2
printf("T->Height=%d\n",depth);
T = T->Right;
if(T){
depth++;
T->Height = depth;
}
printf("IsOJ2\n");
}
}
return WPL;
}
看上面的代码,如果一直向左子树遍历,那么depth就会一直自增,同时把当前的depth赋给T->Height,并把经过的结点push到堆栈S里面,直到叶结点上。退出循环,从堆栈里弹出刚刚遍历的那一个结点,把它的Height赋给depth(其实这里的Height应该是depth,是我最初写错了,我最初是直接给每个Height赋高度的,后来发现题目要求是深度,所以只能重新更新深度,但是TreeNode结构体里的Height还没有改),此时如果有右子树,那就往右子树上跑,那么depth++,如果没有,那从外层循环回来继续Pop,再同时把它的深度给depth,依次下去。