二叉树的层次遍历、哈夫曼树及哈夫曼编码的建立

本文介绍了一种使用C语言实现哈夫曼树的方法,并详细展示了如何通过构造哈夫曼树来获得哈夫曼编码的过程。此外,还提供了层次遍历、先序遍历、中序遍历和后序遍历二叉树的功能。
#include <stdio.h>
#include <malloc.h>
#define N 100        //叶子结点数
#define M 2*N-1     //树中结点总数
#define MAXN 0x7fffffff
typedef char ElemType;

typedef struct Node
{
    ElemType data;
    Node *Lchild,*Rchild;
} BiTNode,*BiTree;

typedef struct//哈夫曼树的节点结构类型
{
    char data;  //结点值
    double weight;  //权重
    int parent;     //双亲结点
    int lchild;     //左孩子结点
    int rchild;     //右孩子结点
} HTNode;

typedef struct//每个节点哈夫曼编码的结构类型
{
    char cd[N]; //存放哈夫曼码
    int start;
} HCode;

typedef struct node
{
    BiTree data;
    node *next;
} Node1,*LinkQueueNode;

typedef struct
{
    LinkQueueNode front; //队头指针
    LinkQueueNode rear;  //队尾指针
} LinkQueue;

BiTree CreateBiTree();//建立二叉树
int Leaf(BiTree T);//分治法统计叶子节点数目
bool LayerOrder(BiTree bt);//层次遍历二叉树
bool InitQueue(LinkQueue *Q);//链队列初始化
bool EnterQueue(LinkQueue *Q,BiTree x);//入队,将数据元素x插入到队列Q中
bool DeleteQueue(LinkQueue *Q,BiTree *x);//出队,将队列Q的队头元素出队并保存到x所指的存储空间中
bool IsEmpty(LinkQueue *Q);//判断链队列是否为空
void PreOrder(BiTree T);//先序
void InOrder(BiTree T);//中序
void PostOrder(BiTree T);//后序
void CreateHT(HTNode ht[],int n);//构造哈夫曼树
void CreateHCode(HTNode ht[],HCode hcd[],int n);//实现哈夫曼编码
void DispHCode(HTNode ht[],HCode hcd[],int n);//输出哈夫曼编码

int main(void)
{
    int count;
    int n=7;
    char str[8]= {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
    double fnum[7]= {0.40,0.30,0.15,0.05,0.04,0.03,0.03};
    HTNode ht[M];
    HCode hcd[N];
    for (int i=0; i<n; i++)
    {
        ht[i].data=str[i];
        ht[i].weight=fnum[i];
    }
    BiTree root=CreateBiTree();
    CreateHT(ht,n);
    CreateHCode(ht,hcd,n);
    printf("先序遍历二叉树:\n");
    PreOrder(root);//先序
    printf("\n");
    printf("中序遍历二叉树:\n");
    InOrder(root);//中序
    printf("\n");
    printf("后序遍历二叉树:\n");
    PostOrder(root);//后序
    printf("\n");
    printf("层次遍历二叉树:\n");
    LayerOrder(root);
    printf("\n");
    count=Leaf(root);
    printf("叶子节点的数目为:\n");
    printf("%d\n",count);
    DispHCode(ht,hcd,n);
    printf("\n");
    return 0;
}

BiTree CreateBiTree()//建立二叉树
{
    ElemType x;
    BiTree T;
    scanf("%c",&x);
    if(x=='#')
        T=NULL;
    else
    {
        T=(BiTree)malloc(sizeof(BiTNode));
        T->data=x;
        T->Lchild=CreateBiTree();
        T->Rchild=CreateBiTree();
    }
    return T;
}

bool LayerOrder(BiTree bt)//层次遍历二叉树
{
    LinkQueue Q;
    BiTree p;
    InitQueue(&Q);
    if(bt==NULL)
        return false;
    EnterQueue(&Q,bt);
    while(!IsEmpty(&Q))
    {
        DeleteQueue(&Q,&p);
        printf("%c ",p->data);
        if(p->Lchild)
            EnterQueue(&Q,p->Lchild);
        if(p->Rchild)
            EnterQueue(&Q,p->Rchild);
    }
    return true;
}

bool InitQueue(LinkQueue *Q)//链队列初始化
{
    Q->front=(LinkQueueNode)malloc(sizeof(Node));
    if(Q->front!=NULL)
    {
        Q->rear=Q->front;
        Q->front->next=NULL;
        return true;
    }
    else
        return false;//溢出
}

bool EnterQueue(LinkQueue *Q,BiTree x)//入队,将数据元素x插入到队列Q中
{
    LinkQueueNode NewNode;
    NewNode=(LinkQueueNode)malloc(sizeof(Node));
    if(NewNode!=NULL)
    {
        NewNode->data=x;
        NewNode->next=NULL;
        Q->rear->next=NewNode;
        Q->rear=NewNode;
    }
    else
        return false;//溢出
}

bool DeleteQueue(LinkQueue *Q,BiTree *x)//出队,将队列Q的队头元素出队并保存到x所指的存储空间中
{
    LinkQueueNode p;
    if(Q->front==Q->rear)//表示队列已空
        return false;
    p=Q->front->next;
    Q->front->next=p->next;//队头元素p出队
    if(Q->rear==p)//如果队中只有一个元素p,则p出队后成为空队
        Q->rear=Q->front;
    *x=p->data;
    free(p);//释放存储空间
    return true;
}

bool IsEmpty(LinkQueue *Q)//判断链队列是否为空
{
    return Q->front == Q->rear;

}

int Leaf(BiTree T)//分治法统计叶子节点数目
{
    int count;
    if(T==NULL)
        count=0;
    else if(T->Lchild==NULL&&T->Rchild==NULL)
        count=1;
    else
        count=Leaf(T->Lchild)+Leaf(T->Rchild);
    return count;
}

void PreOrder(BiTree T)//先序
{
    if(T!=NULL)
    {
        printf("%c ",T->data);
        PreOrder(T->Lchild);
        PreOrder(T->Rchild);
    }
}

void InOrder(BiTree T)//中序
{
    if(T!=NULL)
    {
        InOrder(T->Lchild);
        printf("%c ",T->data);
        InOrder(T->Rchild);
    }
}

void PostOrder(BiTree T)//后序
{
    if(T!=NULL)
    {
        PostOrder(T->Lchild);
        PostOrder(T->Rchild);
        printf("%c ",T->data);
    }
}

void CreateHT(HTNode ht[],int n)//构造哈夫曼树
{
    int i,k,lnode,rnode;
    double min1,min2;
    for (i=0; i<2*n-1; i++)         //所有结点的相关域置初值-1
        ht[i].parent=ht[i].lchild=ht[i].rchild=-1;
    for (i=n; i<2*n-1; i++)         //构造哈夫曼树
    {
        min1=min2=MAXN;            //lnode和rnode为最小权重的两个结点位置
        lnode=rnode=-1;
        for (k=0; k<=i-1; k++)
        {
            if (ht[k].parent==-1)   //只在尚未构造二叉树的结点中查找
            {
                if (ht[k].weight<min1)
                {
                    min2=min1;
                    rnode=lnode;
                    min1=ht[k].weight;
                    lnode=k;
                }
                else if (ht[k].weight<min2)
                {
                    min2=ht[k].weight;
                    rnode=k;
                }
            }
        }
        ht[i].weight=ht[lnode].weight+ht[rnode].weight;
        ht[i].lchild=lnode;
        ht[i].rchild=rnode;
        ht[lnode].parent=i;
        ht[rnode].parent=i;
    }
}

void CreateHCode(HTNode ht[],HCode hcd[],int n)//实现哈夫曼编码
{
    int i,f,c;
    HCode hc;
    for (i=0; i<n; i++) //根据哈夫曼树求哈夫曼编码
    {
        hc.start=n;
        c=i;
        f=ht[i].parent;
        while (f!=-1)   //循序直到树根结点
        {
            if (ht[f].lchild==c)    //处理左孩子结点
                hc.cd[hc.start--]='0';
            else                    //处理右孩子结点
                hc.cd[hc.start--]='1';
            c=f;
            f=ht[f].parent;
        }
        hc.start++;     //start指向哈夫曼编码最开始字符
        hcd[i]=hc;
    }
}

void DispHCode(HTNode ht[],HCode hcd[],int n)//输出哈夫曼编码
{
    int i,k;
    double sum=0,m=0;
    int j;
    printf("  输出哈夫曼编码:\n"); //输出哈夫曼编码
    for (i=0; i<n; i++)
    {
        j=0;
        printf("      %c:\t",ht[i].data);
        for (k=hcd[i].start; k<=n; k++)
        {
            printf("%c",hcd[i].cd[k]);
            j++;
        }
        m+=ht[i].weight;
        sum+=ht[i].weight*j;
        printf("\n");
    }
    printf("\n  平均长度=%.2lf\n",1.0*sum/m);
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值