三:树的初始化操作及应用

树的双亲表示法

#define MAX_TREE_SIZE 100
typedef  struct PTNode{
     TElemType data;
     int  parent;
}PTNode;
typedef struct {
     PTNode nodes[MAX_TREE_SIZE];
     int r,n; //根位置和结点数目
} Ptree;

孩子表示法

typedef  struct CTNode{
     int child;
     struct CTNode *next;
} *ChildPtr;
typedef struct {
     TElemType data;
     ChildPtr  firstchild;
}CTBox;
typedef struct {
     CTBox nodes[MAX_TREE_SIZE];
     int r,n; //根位置和结点数目
} CTree;

孩子兄弟表示法:即转化为二叉树的方式

typedef  struct CSNode{
     TElemType data;
     struct CSNode *firstchild, *nextsibling;
}CSNode, CSTree;

哈夫曼树的表示

typedef struct{
 unsigned int weight;  //结点的权重
 unsigned int parent,lchild,rchild;  //双亲、左孩子和右孩子“指针”(数组中的下标)
}HTNode,*HuffmanTree;
//HuffmanTree  HT; 哈夫曼树HT的类型为一维数组类型,即为指
//向结点的指针(结构数组名)---动态分配数组存储哈夫曼树
typedef char ** HuffmanCode;
// HuffmanCode  HC; HC[i](i=1~n)分别存储第i个字符的前缀编
//码.HC[i]为一维字// 符数组(名),一维字符数组的长度为n(最大//长度,包含一个结束符’\0’)(各个字符的前缀编码不定长)。//HC是一维字符数组的数组(名),其类型为一个 指向一维字符
//数组(长度为n)的指针。char (*HC)[n]

构造哈夫曼树,并编码

void HuffmanCoding(HuffmanTree &HT,HuffmanCode& HC,int *w,int n){
//w存放n个字符的权值,即w为一维整型数组名。构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC.
if(n<=1) return;
m=2*n-1;//构造出来的哈夫曼树的结点总数为m,其中叶子结点树为n,新增加的   	//结点(分支结点数目为n-1).
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//HT[0]未用,实际使用//HT[1]~HT[m]存储所构造的哈夫曼树的各个结点。即用动态数组存储哈夫曼树。
for(p=HT?, i=1;i<=n; i++, p++, ++w)  *p={ *w,0,0,0 };
//初始化n个带权的叶子结点(weight, parent,lchild和rchild值).若HT[0]不//用的话,则是否应该p=HT+1?
for( ; i<=m; ++i, ++p) *p={ 0,0,0,0 };//初始化其他待生成的新结点(分//支结点)
for(i=n+1;i<=m;i++){ //构造哈夫曼树,分别增加(修正)//HT[n+1..2*n-1]结点,每次添加(修改)一个。
Select[HT,i-1,s1,s2]; //在HT[1..i-1]范围内选择parent为0且//weight最小的两个结点,其序号分别为s1和s2.
//将HT[s1]和HT[s2]为根的两棵二叉树合并成一棵根为HT[i]的二//叉树,并修改它们之间的关系。
HT[s1].parent=i; HT[s2].parent=i; //修改s1和s2的parent值
HT[i].lchild=s1; HT[i].rchild=s2; //修改HT[i]的lchild和					    //rchild值
HT[i].weight=HT[s1].weight+HT[s2].weight; //修改HT[i]的			                        //weight值
}
//求所构造的哈夫曼树中n个字符(叶子结点)的哈夫曼编码—从//叶子到根的逆向求解
HC=(HuffmanCode)malloc((n+1)*sizeof(char*));//分配存储n
//个字符的哈夫曼编码的头指向向量(指针数组)。HC[0]未用。//HC[i](i=1..n)存储第i个字符的哈夫曼编码。
// HC=(char(*)[n])malloc((n+1)*sizeof(char[n]));
cd=(char*)malloc(n*sizeof(char));//cd存储各个字符编码的临				//时工作空间,cd为一维动态字符数组.
cd[n-1]=‘\0;  //编码结束标记
for(i=1;i<=n;i++){ //求第i个字符的哈夫曼编码,结果存储于			 //HC[i]中。
   ?
}
for(i=1;i<=n;i++){ //求第i个字符的哈夫曼编码,结果存储于			 //HC[i]中。
 start=n-1;
 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;
  HC[i]=(char*)malloc(sizeof(char));//为第i个字符的编码分  	//配存储空间HT[i],即HC[i]存储第i个字符的哈夫曼编码。
  strcpy(HC[i],&cd[start]);//编码存储在cd[start..n-1]中, 				   //其中cd[n-1]为结束标记’\0’
  free(cd); //释放工作空间cd
}//HuffmanCoding


总的哈夫曼树

#include <iostream>
#include<cstring>
#define INT  10000
#define Max 200 //最大结点数目
using namespace std;

typedef char**HuffmanCode;
char ch[200];
int w[200];
typedef struct{
    int weight;                     //这个是结点的权值,即把小的放在最底层,大的放在前面,,选取小的构建最底层的树、
    int  lchild,rchild,parent;//注意这些是下标。。。
}HTNode,*HuffmanTree;   // 这个第一个是结点,用来生成节点:内本,第二个是当定义变量时,是指针  :外指

                        // 从HT[] 里面0~n 选择两个weight小的,,
int Select(HuffmanTree &HT,int n,int &s1,int &s2){
	int min1,min2;
	min1=min2=INT;    //s1对应min1 最小   s2对应min2 第二小 一个来存储数组的下标,一个来存储weight
	for(int i=1;i<=n;i++){
		if(HT[i].parent==0){
			if(HT[i].weight<min1){
				min2 = min1;
				min1 = HT[i].weight;
				s2 = s1;
				s1 = i;
			}else if(HT[i].weight<min2){
				min2 = HT[i].weight;
				s2 = i;
			}
		}
	}
	return 1;
}



void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n){
     if(n<=1)
        return;
    int m=2*n-1;   //这个 m  是用来标记总的全部的结点个数,: 。。
    HT=(HuffmanTree)malloc(sizeof(HTNode)*m+1);   //进行申请空间,对于m个结点,申请可m+1个位置。
                                                                                          //是为了后面从1开始
    for(int i=1;i<=m;i++){
        HT[i].lchild=0;
        HT[i].parent=0;
        HT[i].rchild=0;
        HT[i].weight=0;
    }//进行所有的结点初始化为0,
    cout<<"初始化完成。。。"<<endl;
    for(int i=1;i<=n;i++){
        HT[i].weight=w[i];
    }
    int s1=0;
    int s2=0;
    for(int i=n+1; i<=m; i++)      //因为前面的n个均为叶子结点,所以没有孩子,那么接下来的从n+1到m都有孩子,
                                                                                                                      //即给这些位置的结点找孩子。
    {                   //这里的“i-1” 表示要从数组HT[] 从1到i-1 顺序遍历寻找(两个最小的)
        Select(HT,i-1,s1,s2);          //这个选择是将HT[] 数组里面的w最小,即找到两个孩子。
        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;   //  给以新的父亲结点weight值
    }




    HC=(HuffmanCode)malloc(sizeof(char*)*(n+1));

    char *cd=(char *)malloc(sizeof(char)*n);
    cd[n-1]='/0';
    for(int i=1;i<=n;i++){
        int start=n-1;
        for(int 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';
            }
        }
        HC[i]=(char*)malloc(sizeof(char)*(n-start));
        strcpy(HC[i],&cd[start]);
        cout<<ch[i]<<"的编码"<<HC[i]<<endl;;
    }
    free(cd);
    cout<<"编码完成。。。"<<endl;
}

void Decoding(HuffmanTree HT,int n)//译码
{
  int j,len,m;
  string str;
  m=2*n-1;
  cout<<"请输入要译码的:"<<endl;

   cin>>str;

   len=str.size();
int   i=0;j=m;
  while(i<len)
  { //从根出发,按字符‘0’或‘1’确定找左孩子或右孩子,直至叶子结点
   if(str[i]=='0'){
         j=HT[j].lchild;}
   else {j=HT[j].rchild;}
   if(HT[j].lchild==0)
   {
       cout<<"译码结果为:"<<ch[j];
    j=m; }
   i++;
  }
  cout<<endl;
}

int main()
{
HuffmanTree HT;
 HuffmanCode HC;
 int n;
 cout<<"请输入字符的个数n:"<<endl;
 cin>>n;
 for(int i=1;i<=n;i++){
            cout<<"请输入第"<<i<<"个字符"<<endl;
            cin>>ch[i];

 }
 for(int i=1;i<=n;i++){
        cout<<"请输入第"<<i<<"个的权重"<<endl;
    cin>>w[i];
 }
 HuffmanCoding(HT,HC,w,n);
 cout<<"编码结束"<<endl;
 Decoding(HT,n);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值