採用鏈式存儲結構構造哈夫曼樹


/************************************************************************
*
* 文件名:HFtree.c
*
* 文件描述:本程序給出哈夫曼樹的鏈式構造法和哈夫曼的編碼
*           在turboc 2.0 調試通過,在其他編譯環境下請把
*           gotoxy和getch兩個函數重寫
*
* 創建人: 顏清國   2006年5月4日
* 說明: 
*            採用鏈式存儲結構構造哈夫曼樹,可以很方便的將樹的各種操作加
*            到哈夫曼樹上來,包括其編碼
************************************************************************/

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"

#define LEN sizeof(HFtree) /*HFtree結構體大小*/

/*哈夫曼樹結構體*/
typedef struct tagHFtree
{
	char data;            /*結點數據,以後用到*/
	double weight;         /*結點的權重*/
	struct tagHFtree* parent; /*雙親結點*/
	struct tagHFtree* lchild; /*左孩子*/
	struct tagHFtree* rchild; /*右孩子*/
	struct tagHFtree* next;    /*指向下一個結點*/
}HFtree;

/*哈夫曼編碼結構體*/
struct tagHFcode
{
 char data;           /*結點數據*/
 double weight;       /*結點的權重*/     
 int code[20];            /*存放編碼*/
 int top;             /*編碼的位數*/
};

/***********************************************
 創建哈夫曼樹核心部分
************************************************/
void Create(HFtree**head)
{
	HFtree*lp,*temp,*lchild,*rchild;
	while((*head)->next->next!=NULL)
	{
		lchild=rchild=(*head);   /*每次從頭開始查找,這裏(*head)的weight沒用,*/
                                          /*剛好用來放左右孩子*/           
                temp=(*head)->next;    /*最初的的weight*/
		lchild->weight=rchild->weight=3.14e+38;  /*重新找時每次將左右孩子的weight置爲最大*/
		lp=(HFtree*)malloc(LEN);
                lp->parent=NULL;
		while(temp!=NULL)            /*查找最小的作爲左孩子*/
		{
			if(lchild->weight > temp->weight)
			{
				lchild=temp;
			}
			temp=temp->next;
		}
		temp=(*head)->next;          /*重新定位到(*head)->next*/
		while(temp!=NULL)            /*查找次小的作爲右孩子*/
		{                 /*注意這裏不要用temp->weight!=lchild->weigh*/
			if(rchild->weight > temp->weight && temp!=lchild) 
			{
				rchild=temp;
			}
			temp=temp->next;
		}
		
		lp->lchild=lchild;                        /*對LP及其左右孩子附值*/
		lp->rchild=rchild;                        
		lchild->parent = rchild->parent =lp;
		lp->weight=lchild->weight + rchild->weight;  /*將左右孩子的權值相加*/
		lp->next=(*head)->next;                /*將LP插到表頭*/
		(*head)->next=lp;                      /*每次讓(*head)->next指向新加進來的結點*/
		temp=lp;                               /*將lp和temp兩個指針重新定位,用來遍歷鏈表*/
		lp=lp->next;
		while(lp!=NULL)                        /*將左右孩子從待創建的鏈表系列中刪除*/
		{
			if(lp==lchild || lp==rchild)
			{
				temp->next=lp->next;
				lp->next=NULL;
			}
			else
				temp=lp;
			lp=temp->next;
			
		}
	}
}


/***********************************************
創建哈夫曼樹
************************************************/
void CreateHFtree(double nodewei[],int n,HFtree**head)
{
	int i=0;
	HFtree*lp=(HFtree*)malloc(LEN),*rear;
	(*head)=(HFtree*)malloc(LEN);
        (*head)->parent=NULL;
	(*head)->next=rear=lp;                                 /*head頭結點,保證指向剩餘的結點鏈*/
	lp->parent=lp->lchild=lp->rchild=lp->next=NULL;
	while(iweight=nodewei[i++];
		rear->next=lp;                          /*第一次REAR指向自身*/
		rear=lp;
		lp=(HFtree*)malloc(LEN);
		lp->parent=lp->lchild=lp->rchild=lp->next=NULL;
	}
	free(lp);                                    /*釋放最後一個結點*/
	Create(head);                               /*創建一棵樹,樹的頭結點爲(*HEAD)->next*/
}

/*************************************************
 由先序遍歷求出哈夫曼樹求出哈夫曼編碼
**************************************************/
void HFcoding(HFtree*root,HFtree*temp,struct tagHFcode HFcode[],int*leaftop)
{
 if(root!=NULL)
 {
  if(root->lchild==NULL && root->rchild==NULL)    /*是葉子結點,求得編碼*/
  {
   temp=root;
   HFcode[(*leaftop)].top=0;
   HFcode[(*leaftop)].weight=root->weight;
   HFcode[(*leaftop)].data=root->data;
   while(temp->parent!=NULL)
   {
    if(temp->parent->lchild==temp)                   
    HFcode[(*leaftop)].code[HFcode[(*leaftop)].top]=0;
    else
    HFcode[(*leaftop)].code[HFcode[(*leaftop)].top]=1;
    HFcode[(*leaftop)].top++;
    temp=temp->parent;
   }
   (*leaftop)++;
  }
  HFcoding(root->lchild,temp,HFcode,leaftop);
  HFcoding(root->rchild,temp,HFcode,leaftop);
}
}

/***********************************************
 輸出求得的哈夫曼編碼
************************************************/
void OutCoding(struct tagHFcode HFcode[],int leaftop)
{
 int i=0,j=0;
          for(;i<leaftop;i++)
          {
                 printf("%.1f :",HFcode[i].weight);
                 j=HFcode[i].top-1;
                 while(j>=0 )
                 {
                  printf("%d",HFcode[i].code[j]);
                  j--;
                 }
                 printf("/n");
          }
}
/********************************************
用括號表示法輸出樹
**********************************************/
void OutTree(HFtree *root)
{
	if(root != NULL)
	{
		printf("%.1f",root->weight);       /*先輸出根結點*/
		if(root->lchild != NULL || root->rchild != NULL)
		{
			printf("(");
			OutTree(root->lchild);        /*處理左子樹*/
			if(root->rchild != NULL)
			{
				printf(",");
			}
			OutTree(root->rchild);         /*處理右子樹*/
			printf(")");
		}
	}
}

/*****************************************************************
 用樹形表示法輸出樹
******************************************************************/
void DispTree(HFtree *root,int x,int y,int n)     /*n用來控制第一層樹的高度*/
{
 int i=0;
 if(root !=NULL)
  {
    gotoxy(x,y);                               /*到相應結點輸出*/
    printf("%.1f",root->weight);
    if(root->lchild != NULL)                  /*處理左子樹,這裏只有第一次N爲可變的,*/
    {
       i=1;                                   /*爲的是能夠輸出整棵樹,而不會被覆蓋,*/
       while(ilchild,x-n,y+n,2);       /*遞歸處理左子樹*/
     }
     if(root->rchild != NULL)
    {
       i=1;
       while(irchild,x+n,y+n,2);       /*遞歸處理右子樹*/
     }
   }
}
 
/*****************************************************************
 主函數入口
******************************************************************/
void main()
{
        double nodewei[20];
        struct tagHFcode HFcode[20];
        int leaftop=0,i=0;
        HFtree*temp=NULL;
	HFtree*head;
        textbackground(1);
        textcolor(2);
        clrscr();
        printf("the HFtree and HFcoding demo/r/n");
        printf("Input the leafnode weight:");
        scanf("%lf",&nodewei[i]);
        while(nodewei[i++]!=0.0)/*接收數據,以0結尾*/
                scanf("%lf",&nodewei[i]);
        CreateHFtree(nodewei,i-1,&head);  /*根據接收的數據創建*/
        printf("HFtree:");
	OutTree(head->next);              /*輸出哈夫曼樹括號表示法*/
        HFcoding(head->next,temp,HFcode,&leaftop);  /*根據哈夫曼樹,求出哈夫曼編碼*/
        printf("/nthe HFcoding is:/n");
        OutCoding(HFcode,leaftop);        /*輸出哈夫曼編碼*/
        DispTree(head->next,30,10,6);     /*用樹形表示法輸出樹*/
        getch();
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章