数据结构代码汇总(5)--二叉树

本文将复习二叉树的相关操作及应用
一、二叉树的节点定义

typedef struct node
{
    int data;
    struct node *lchild;
    struct node *rchild;
}node,*tree;

我们使用二叉链表来存储树,比较好理解
二、遍历及其应用
1.递归遍历算法
最常用的就是递归遍历,这个算法非常简单,也非常容易理解,代码也比较简洁,其内容在书上163页
2.非递归遍历算法(170-174页)
基于栈我们可以不用递归来实现二叉树的遍历,下面是代码

typedef struct
{
    tree arr[50];
    int top;
}stack;//栈的定义

void init(stack *s)//初始化
{
    s->top=-1;
}

void push(stack *s,tree ch)//进栈
{
    s->top++;
    s->arr[s->top]=ch;
}

tree pop(stack *s)//出栈
{
    tree c=s->arr[s->top];
    s->top--;
    return c;
}
//上面的基本上是栈相关操作,为了大家理解把它写了出来,下面是正文
void pre(tree root)//先序遍历
{
    stack s;
    init(&s);
    node *p;
    p=root;
    while(p||(s.top!=-1))
    {
        if(p)
        {
            printf("%c ",p->data);//遍历根
            push(&s,p);
            p=p->lchild;//左子树
        }
        else
        {
            p=pop(&s);
            p=p->rchild;//右子树
        }
    }
}

void mid(tree root)//中序
{
    stack s;
    init(&s);
    tree p=root;
    while(p||(s.top!=-1))
    {
        if(p)
        {
            push(&s,p);
            p=p->lchild;//左子树
        }
        else
        {
            p=pop(&s);
            printf("%c ",p->data);//遍历根
            p=p->rchild;//右子树
        }
    }
}

void post(tree root)//后序遍历,相较前两个较为复杂一点
{
    node *p,*q;
    stack s;
    q=NULL;
    p=root;
    init(&s);
    while(p||(s.top!=-1))
    {
        if(p)//左子树
        {
            push(&s,p);
            p=p->lchild;
        }
        else
        {
            p=s.arr[s.top];
            if(p->rchild==NULL||p->rchild==q)//没有右孩子或右孩子已经遍历过
            {
                printf("%c ",p->data);//访问根
                q=p;
                p=pop(&s);
                p=NULL;
            }
            else//右子树
            {
                p=p->rchild;
            }
        }
    }
}

3.递归的应用
3.1输出节点:上面的算法其实已经输出了,此处不再赘述
3.2统计叶子节点数目:166页,算法比较简单,此处不赘述
3.3通过遍历去创建二叉链表:167页算法6.7,也比较简单,此处不赘述
3.4求二叉树的高度:168页6.8

int treedepth(tree root)
{
    int hl,hr,max;//hl是左子树的高度,hr右子树的高度
    if(root)
    {
        hl=treedepth(root->lchild);//求左子树的高度
        hr=treedepth(root->rchild);//求右子树的高度
        max=(hl>hr)?hl:hr;//得到大者
        return max+1;//返回树的深度,记得+1
    }
    else
        return 0;//空树否则返回0
}

先序递归求二叉树的高度也比较简单,不再赘述
3.5横向树形显示二叉树
169页6.10
本算法使用逆中序的输出方法,结合了上面求高度的算法设计出来的,层深决定左右位置,先右子树,再根,最后左子树。

void printtree(tree root,int n)
{
    if(!root)
        return;
    printtree(root->lchild,n+1);
    for(int i=0;i<n;i++)
    {
        printf(" ");
    }
    printf("%c\n",root->data);
    printtree(root->rchild,n+1);
}

三、哈夫曼树的创建及哈夫曼编码
1.哈夫曼树类型定义及编码,191-196页

#include <iostream>
#include <string.h>

using namespace std;

typedef struct
{
	char data;//这个是为了后面哈夫曼编码作为铺垫
	int weight;
	int parent;
	int lchild;
	int rchild;
}node,*hftree;

void select(hftree ht, int n, int &s1, int &s2)
{
    s1=s2=0; // 初始化为0,表示尚未找到
    int min1=32767,min2=32767;
    for (int i=1;i<=n;i++)
    {
        if (ht[i].parent==0)
        {
            if (ht[i].weight<min1)
            {
                min2=min1;
                s2=s1;
                min1=ht[i].weight;
                s1=i;
            }
            else if(ht[i].weight<min2)
            {
                min2=ht[i].weight;
                s2=i;
            }
        }
    }
}

void crthuffmantree(hftree ht,int w[],int n)
{
    int i,s1,s2,temp;
    for(i=1;i<=n;i++)//叶子节点初始化
    {
        temp=96+i;
        ht[i].data=static_cast<char>(temp);
        ht[i].lchild=ht[i].rchild=ht[i].parent=0;
        ht[i].weight=w[i];
    }

    for(i=n+1;i<=2*n-1;i++)//非叶节点初始化
    {
        ht[i].weight=ht[i].lchild=ht[i].rchild=ht[i].parent=0;
    }

    for(i=n+1;i<=2*n-1;i++)//生成哈夫曼树
    {
        select(ht,i-1,s1,s2);//挑选最小的两个节点
        ht[i].weight=ht[s1].weight+ht[s2].weight;
        ht[s1].parent=ht[s2].parent=i;
        ht[i].lchild=s1;
        ht[i].rchild=s2;
    }
}

void huffmancode(hftree ht,char code[][10],int n)//哈夫曼编码,和书上略微不同,我传的是二维数组
{
    char *cd;
    cd=(char*)malloc(n*sizeof(char));
    cd[n-1]='\0';
    int i,start,c,p;
    for(i=1;i<=n;i++)
    {
        start=n-1;
        c=i;
        p=ht[i].parent;
        while(p)
        {
            start--;
            if(ht[p].lchild==c)
                cd[start]='0';
            else
                cd[start]='1';
            c=p;
            p=ht[p].parent;//找双亲
        }
        strcpy(code[i],&cd[start]);
    }
    free(cd);
}


int main()
{
    int n,w[10];
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>w[i];
    }
    node ht[40];
    crthuffmantree(ht,w,n);
    char code[10][10];//存放编码的二维字符数组
    huffmancode(ht,code,n);
    for(int i=1;i<=n;i++)
    {
        cout<<ht[i].data<<":";
        for(int j=0;code[i][j]!='\0';j++)
        {
            cout<<code[i][j];
        }
        cout<<endl;
    }
    return 0;
}

2.编码及解码
编码解码例题

    //这部分请把它插到上个代码的后面使用
    char str1[50],str2[50];
    scanf("%10s",str1);//输入字符串输入二进制串
    scanf("%100s",str2);//
    for(i=0;str1[i]!='\0';i++)
    {
        int temp=str1[i];//把字符的ASCII码值-96对应到code对应行数
        for(j=0;code[temp-96][j]!='\0';j++)//根据哈夫曼编码求二进制串的过程:把每个字符对应的编码直接输出即可
        {
            cout<<code[temp-96][j];
        }
    }
    i=0;
    while(i<strlen(str2))//类似于串的BF匹配算法
    {
        for(j=1;j<=n;j++)//j控制行
        {
            int flag=1;
            for(k=0;code[j][k]!='\0';k++)//k控制列
            {
                if(code[j][k]!=str2[i])//如果不等,回溯
                {
                    flag=0;
                    i-=k;
                    break;
                }
                    i++;
            }
            if(flag)//匹配成功,则输出
                 cout<<ht[j].data;
        }
    }

本文到此结束,哈夫曼树的难度就有一点大了,程序还是调试了一段时间的,本系列文章目前为止还没有参考网上大佬,仅参考了课本,目的就是为了用书上的思维写,帮助大家理解,下一章我们写图,我个人认为是数据结构最难的一部分了,加油

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值