【数据结构】二叉树和哈夫曼编码

1、二叉树的基本操作

内容:
1)采用二叉链表结构建立二叉树
2)编程实现二叉树的先序、中序、后序和层序遍历
3)编程实现非递归中序遍历
4)编程实现:求二叉树的高度和叶子结点个数

实现思路
① 设置存储空间的初始分量
② 定义结构体类型的二叉树数据类型,并引入堆栈
③ 实现先序建立二叉树、前序遍历二叉树、中序遍历二叉树、后序遍历二叉树、层序遍历二叉树、先序非递归遍历二叉树、求二叉树深度、求叶子结点个数等函数
④ 先序建立二叉树、前序遍历二叉树、中序遍历二叉树、后序遍历二叉树、求二叉树深度、求叶子结点个数使用递归实现
⑤ 层序遍历二叉树使用数组或者队列实现
⑥ 先序非递归遍历二叉树使用堆栈和循环实现
⑦ 在主函数里面调用各个方法进行检验

二叉树基本操作程序代码:

#include <iostream>

using namespace std;

#define MAXSIZE 100  //顺序栈存储空间的初始配量
#define OK 1
#define ERROR 0

typedef char TElemType;

typedef struct BiTNode //二叉树
{
    TElemType data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

typedef BiTree ElemType;
typedef struct StackNode  //链栈的存储结构
{
    ElemType data;
    struct StackNode *next;
}StackNode,*LinkStack;

void InitStack(LinkStack &S)  //链栈的初始化
{
    S=NULL;
}

void Push(LinkStack &S,ElemType e)
{
    StackNode *p=new StackNode;
    p->data=e;
    p->next=S;
    S=p;
}

void Pop(LinkStack &S,ElemType &e)
{
    if(S==NULL)
        return;
    e=S->data;
    StackNode *p=S;
    S=S->next;
    delete p;
}

bool StackEmpty(LinkStack S)
{
    if(S==NULL)
        return true;
    return false;
}


void CreateBiTree(BiTree &T) //先序建立二叉树
{
    char ch;
    cin>>ch;
    if(ch=='#')
        T=NULL;
    else
    {
        T=new BiTNode;
        T->data=ch;
        CreateBiTree(T->lchild);
        CreateBiTree(T->rchild);
    }
}

void PreOrderTraverse(BiTree T)  //前序遍历
{
    if(T)
    {
        cout<<T->data;
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }
}

void InOrderTraverse(BiTree T)  //中序遍历
{
    if(T)
    {
        InOrderTraverse(T->lchild);
        cout<<T->data;
        InOrderTraverse(T->rchild);
    }
}

void PostOrderTraverse(BiTree T) //后续遍历
{
    if(T)
    {
        PostOrderTraverse(T->lchild);
        PostOrderTraverse(T->rchild);
        cout<<T->data;
    }
}

void LevelOrderTraverse(BiTree T) //层次遍历
{
    BiTree temp[100];
    int in=0;
    int out=0;
    temp[in++]=T;
    while(in>out)
    {
        if(temp[out])
        {
            cout<<temp[out]->data;
            temp[in++]=temp[out]->lchild;
            temp[in++]=temp[out]->rchild;
        }
        out++;
    }
}

int Depth(BiTree T)  //二叉树深度
{
    if(T==NULL)
        return 0;
    else
    {
        int m=Depth(T->lchild);
        int n=Depth(T->rchild);
        if(m>n)
            return m+1;
        else
            return n+1;
    }
}

void InOrderTraverse_1(BiTree T) //中序非递归遍历
{
    LinkStack S;
    InitStack(S);
    BiTree p=T;
    BiTree q=new BiTNode;
    while(p || !StackEmpty(S))
    {
        if(p)
        {
            Push(S,p);
            p=p->lchild;
        }
        else
        {
            Pop(S,q);
            cout<<q->data;
            p=q->rchild;
        }
    }
}

int leave_number(BiTree T) //叶子结点的个数
{
    if(T==NULL)
        return 0;
    if(T->lchild==NULL && T->rchild==NULL)
        return 1;
    return leave_number(T->lchild)+leave_number(T->rchild);
}

int main()
{
    BiTree T;
    //InitBiTNode(&T);
    cout<<"请输入二叉树:"<<endl;
    CreateBiTree(T);
    cout<<"先序遍历:";
    PreOrderTraverse(T); cout<<endl;
    cout<<"后序遍历:";
    PostOrderTraverse(T); cout<<endl;
    cout<<"中序遍历:";
    InOrderTraverse(T); cout<<endl;
    cout<<"层序遍历:";
    LevelOrderTraverse(T); cout<<endl;
    cout<<"深度为:"<<Depth(T)<<endl;
    cout<<"中序非递归遍历:";
    InOrderTraverse_1(T); cout<<endl;
    cout<<"叶子结点个数:";
    cout<<leave_number(T);
    return 0;
}

2、哈夫曼编码

内容:
1) 给定报文中26个字母a-z及空格的出现频率{64, 13, 22, 32, 103, 21, 15, 47, 57, 1, 5, 32, 20, 57, 63, 15, 1, 48, 51, 80, 23, 8, 18, 1, 16, 1,168},构建哈夫曼树并为这27个字符编制哈夫曼编码,并输出
2)模拟发送端,从键盘输入字符串,以%为结束标记,在屏幕上输出输入串的编码
3)模拟接收端,从键盘上输入0-1哈夫曼编码串,翻译出对应的原文。

实现思路:
① 定义结构体类型的哈夫曼树数据类型
② 实现哈夫曼树的初始化,父结点、子结点都赋值为0
③ 实现Select函数搜索哈夫曼树里面最小的两个结点并返回
④ 实现创建二叉树,不断搜索最小的两个结点加入树中
⑤ 实现创建哈夫曼编码函数,左子树为0,右子树为1,从叶子结点向上寻找直到根节点
⑥ 实现转码函数和翻译函数(从根向下0向左1向右)
⑦ 主函数进行函数调用,实现程序

哈夫曼编码程序代码:

#include <iostream>
#include <string>
#include <map>
#include <algorithm>
using namespace std;

typedef map<int,string> HuffmanCode;
int a[27];

//哈夫曼树的存储结构
typedef struct
{
    int weight;
    char c;
    int parent,lchild,rchild;
}HTNode,*HuffmanTree;

void Select(HuffmanTree HT,int n,int &s1,int &s2)
{
    for(int i=1;i<=n;i++)
    {
        if(HT[i].parent == 0)
        {
            if(s1 == 0)
                s1=i;
            else
            {
                s2=i;
                break;
            }
        }
    }
    if(HT[s1].weight > HT[s2].weight)
    {
        int t=s1;
        s1=s2;
        s2=t;
    }
    for(int i=1;i<=n;i++)
    {
        if(HT[i].parent == 0)
        {
            if(HT[i].weight < HT[s1].weight)
            {
                s2=s1;
                s1=i;
            }
            else if(HT[i].weight < HT[s2].weight && i!=s1)
            {
                s2=i;
            }
        }
    }
}

//初始化哈夫曼树
void initHuffmanTree(HuffmanTree &HT)
{
    int n=27;
    int m = 2 * n - 1;
    HT = new HTNode[m+1];
    for(int i = 0; i <= m; i++) //将m个元素的双亲、左孩子、右孩子的小标都初始化为0
    {
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
    }
    for(int i=1;i<=n;i++)  //输入前n个单元中叶子结点的权值
    {
        HT[i].weight=a[i-1];
        HT[i].c='a'+i-1;
    }
    HT[27].c=' ';
}

//创建哈夫曼树
void CreatHuffmanTree(HuffmanTree &HT)
{
    int n=27;
    int m = 2 * n - 1;
    for(int i=n+1;i<=m;i++)
    {
        int s1=0;
        int s2=0;
        Select(HT,i-1,s1,s2);
        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;
    }
}

void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC)
{
    int n=27;
    for(int i=1;i<=n;i++)
    {
        string str="";
        int c=i;
        int f=HT[i].parent;
        while(f!=0)
        {
            if(HT[f].lchild==c)
                str += "0";
            else
                str += "1";
            c=f;
            f=HT[f].parent;
        }
        reverse(str.begin(),str.end());
        HC[i] = str;
    }
}

//字符串转码
string zhuanma(HuffmanCode HC,string str)
{
    string s="";
    for(int i=0;i<str.length();i++)
    {
        if(str[i]>='A'&&str[i]<='Z')
            str[i]=str[i]+32;
        if(str[i]==' ')
        {
            s+=HC[27];
        }
        else
        {
            s+=HC[str[i]-'a'+1];
        }
    }
    return s;
}

//译码
void translation(HuffmanTree HT,string str)
{
    HTNode ht=HT[53];
    cout<<"翻译结果为:"<<endl;
    for(int i=0;i<str.length();i++)
    {
        if(str[i]=='0')
            ht=HT[ht.lchild];
        else
            ht=HT[ht.rchild];
        if(ht.lchild==0&&ht.rchild==0)
        {
            cout<<ht.c;
            ht=HT[53];
        }
    }
}

int main()
{
    string str="abcdefghijklmnopqrstuvwxyz ";
    int flag=1;
    HuffmanTree HT;
    HuffmanCode HC;
    int n=27;
    while(flag)
    {
        cout<<"****************************************************************************************"<<endl;
        cout<<"*******************  1.输入HuffmanTree的参数。                       *******************"<<endl;
        cout<<"*******************  2.初始化HuffmanTree的参数。(含有26字母及空格) *******************"<<endl;
        cout<<"*******************  3.创建HuffmanTree和编码表。                     *******************"<<endl;
        cout<<"*******************  4.输出编码表。                                  *******************"<<endl;
        cout<<"*******************  5.输入编码,并翻译为字符。                      *******************"<<endl;
        cout<<"*******************  6.输入字符,并实现转码。                        *******************"<<endl;
        cout<<"*******************  7.退出。                                        *******************"<<endl;
        cout<<"****************************************************************************************"<<endl;
        int ip;
        cout<<"请输入指令:";
        cin>>ip;

        switch(ip)
        {
        case 1:
            {
                cout<<"请按顺序输入HuffmanTree的27个参数:"<<endl;
                for(int i=0;i<27;i++)
                    cin>>a[i];
                break;
            }
        case 2:
            {
                initHuffmanTree(HT);
                cout<<"参数初始化成功"<<endl;
                cout<<"结点i\tweight\tparent\tlchild\trchild\n";
                for(int i=1;i<2*n;i++)
                    cout<<i<<"\t"<<HT[i].weight<<"\t"<<HT[i].parent<<"\t"<<HT[i].lchild<<"\t"<<HT[i].rchild<<endl;
                system("pause");
                break;
            }
        case 3:
            {
                CreatHuffmanTree(HT);
                CreateHuffmanCode(HT,HC);
                cout<<"创建成功"<<endl;
                for(int i=1;i<2*n;i++)
                    cout<<i<<"\t"<<HT[i].weight<<"\t"<<HT[i].parent<<"\t"<<HT[i].lchild<<"\t"<<HT[i].rchild<<endl;
                system("pause");
                break;
            }
        case 4:
            {
                cout<<"字符编号\t哈夫曼编码"<<endl;
                for(map<int,string>::iterator iter=HC.begin();iter!=HC.end();iter++)
                {
                    cout<<"'"<<str[iter->first-1]<<"'"<<"\t\t"<<iter->second<<endl;
                }
                system("pause");
                break;
            }
        case 5:
            {
                string s;
                cout<<"请输入需要翻译的编码:"<<endl;
                cin>>s;
                translation(HT,s);
                cout<<endl;
                system("pause");
                break;
            }
        case 6:
            {
                string s;
                cout<<"请输入需要转码的字符串:"<<endl;
                cin.ignore();
                getline(cin,s);
                cout<<"字符串对应的编码为:\n"<<zhuanma(HC,s)<<endl;
                system("pause");
                break;
            }
        case 7:
            {
                flag=0;
                break;
            }
        default :
            {
                cout<<"指令错误!请重新输入!"<<endl;
                system("pause");
                break;
            }
        }
        system("cls");
    }
    return 0;
}
/*
hello world
h 0001
e 010
l 10111
l 10111
o 1001
  111
w 110001
o 1001
r 0010
l 10111
d 10110
000101010111101111001111110001100100101011110110
*/

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值