数据结构:二叉树

目录

18924 二叉树的宽度

18923 二叉树的直径

18724 二叉树的遍历运算

8609 哈夫曼树

额外题:任意两节点距离


18924 二叉树的宽度

#include <iostream>
#include <queue>
#include <vector>

using namespace std;
/**用一维结构体数组表示树!!*/
/**也可用二维整型数组表示*/

struct tree
{
    int l;
    int r;
} v[100];

queue <int> q;

int main()
{
    int n;
    cin>>n;
    n--;
    while(n--)
    {
        int x,y;
        cin>>x>>y;
        if(v[x].l)
            v[x].r=y;
        else
            v[x].l=y;
    }
    int curwide=1,maxwide=1;
    q.push(1);
    while(!q.empty())
    {
        curwide=q.size();
        if(maxwide<curwide)
            maxwide=curwide;
        for(int i=0 ; i<curwide ; i++)
        {
            int t=q.front();  /**临时记录,巧妙利用记录数组*/
            if(v[t].l)
                q.push(v[t].l);
            if(v[t].r)
                q.push(v[t].r);
            q.pop();
        }
    }
    cout<<maxwide<<endl;
    return 0;
}

18923 二叉树的直径

#include<iostream>
#include<cstring>
#include<algorithm>

//用数组储存二叉树的特殊性
using namespace std;

int ans=0;

struct Node
{
    int l,r;
};
Node a[10000];
int dd(int x)
{
    if(!x) //非法输入 或是已无孩子(该题的特殊性)
        return 0;
    //收集答案
    int n=dd(a[x].l);
    int m=dd(a[x].r);
    int len=max(n,m)+1; //选出较大的分支
    ans=max(ans,m+n); //记录直径,要求的答案是这个
    return len;  //返回的是长度,不是直径
}


int main()
{
    int i,n,x,y;
    //输入环节
    cin>>n;
    for(i=1; i<n; i++)
    {
        cin>>x>>y;
        if(a[x].l==0)
            a[x].l=y;
        else
            a[x].r=y;
    }
    //输入结束

    //开始处理
    dd(1);
    cout<<ans;
    return 0;

}//main


/*
5
1 2
1 3
2 4
2 5

3
*/

18724 二叉树的遍历运算

#include<iostream>
#include<cstring>
using namespace std;
char pre[100];//全局变量,先序序列
char in[100];//全局变量,中序序列
void solve(int xl,int xr,int zl,int zr)
/*设四个下标作为指针,含义分别为先序(x)序列的左右和中序(z)序列的左右*/
{
    int i;
    if(xl>xr)
        /* return后什么都不加,是void类型函数的返回,
        返回后不再执行return后面的语句,
        即中断返回值为void类型的函数执行,
        作用相当于break语句,中断循环的执行*/
        return ;
    char ch=pre[xl];//根结点就是先序序列的第一个
    for(i=zl; i<=zr; i++) //在中序序列中找出根节点的下标
    {
        if(in[i]==ch)
            break;
    }
    //对序列进行二分递归
    int lenl=i-zl;//左子树的序列长度

    solve(xl+1,xl+lenl,zl,zl+lenl-1);//左子树,重点记忆
    solve(xl+lenl+1,xr,zl+lenl+1,zr);//右子树,重点记忆
    cout<<ch;//后序遍历最后才访问根结点
}


int main()
{
    scanf("%s",pre+1);//pre+1表示&pre[1],从下标为1开始输入
    scanf("%s",in+1);
    solve(1,strlen(pre+1),1,strlen(in+1)); //从下标1开始计算长度
    return 0;
}

8609 哈夫曼树


#include <stdio.h>
#include <string.h>

typedef struct //哈夫曼树的各节点存储在数组中,且0号单元不使用。因此总共需要大小为2n的数组,其中1~n号单元存储叶子结点,后面的n-1个单元存储其他节点
{
    int weight;
    int parent, lchild, rchild;
} HTNode, *HuffmanTree;
typedef char **HuffmanCode; //哈夫曼编码表是一个二维数组,存储着n个一维数组,每个一维数组存储这一个节点的哈夫曼编码

void Select(HuffmanTree HT, int n, int &s1, int &s2) //记住0号位不储存
{
    /**
    int i, min1 = 9999, min2 = 10000; //min1是最小值,min2是第二小的值
    s1 = s2 = 0;                      //s1为最小值编号,s2为第二小的值的编号
    for (i = 1; i <= n; i++)
    {
        if (!HT[i].parent)
        {
            if (HT[i].weight < min1) //发现一个节点值比最小值还要小
            {
                s2 = s1, s1 = i;
                min2 = min1, min1 = HT[i].weight;
            }
            else if (HT[i].weight >= min1 && HT[i].weight < min2) //发现一个节点值可以作为第二小的值
                s2 = i, min2 = HT[i].weight;
        }
    }
    */

    int i,min1=999,min2=1000;
    s1=s2=0;
    for(i=1 ; i<=n ; i++)
    {
        if(!HT[i].parent) //没配对的
        {
            if(HT[i].weight<min1)//找到新的最最小值
            {
                s2=s1;  //更新旧的最最小值和最小值 ///别忘了还要返回下标
                s1=i;   ///别忘了还要返回下标
                min2=min1;
                min1=HT[i].weight;
            }
            else if(HT[i].weight>=min1&&HT[i].weight<min2) //注意:可以有多个最最小值
            {
                s2=i,  ///别忘了还要返回下标
                min2=HT[i].weight;
            }
        }
    }

}


void CreateHuffmanTree(HuffmanTree &HT, int n)  //填表
{
    if (n <= 1)
        return;             //用于构造哈夫曼树的带权值的节点数不大于1时直接返回
    int m = 2 * n - 1;      //存储共需2n-1个单元
    HT = new HTNode[m + 1]; //由于0号单元不使用,开辟2n个单元的空间用于存储
    for (int i = 1; i <= m; i++)
        HT[i].parent = HT[i].lchild = HT[i].rchild = 0; //初始化将要用于存储的2n-1个单元
    for (int i = 1; i <= n; i++)
        scanf("%d", &HT[i].weight); //输入用于建树的n个节点的权值
    /**
        for (int i = n + 1; i <= m; i++)  ///开始填预留了空位的表
        {
            int s1, s2;                                   //s1,s2存储目前双亲域为0且权值最小的两个节点
            Select(HT, i - 1, s1, s2);                    //选出当前权值最小的两个节点
            HT[s1].parent = HT[s2].parent = i;            //将选出来的两个节点的双亲域置为i,于是在接下来的Select中他们便不会被纳入选择范围
            HT[i].lchild = s1, HT[i].rchild = s2;         //将新节点往后存储,并令s1,s2分别为它的左右孩子,即加入一个新节点到用于建树的节点堆中
            HT[i].weight = HT[s1].weight + HT[s2].weight; //新节点权值为当前权值最小的两个节点权值之和
        }
    */

    for(int i=n+1 ; i<=2*n-1 ; i++) //从 HT数组 空位处开始操作 2n个位置,但最后的下标是2n-1
    {
        int s1,s2;
        Select(HT,i-1,s1,s2);//从i往前看(不包括i,因为它的权值还没填上去)找两个最小值
        HT[s1].parent=HT[s2].parent=i;
        HT[i].lchild=s1,HT[i].rchild=s2;
        HT[i].weight=HT[s1].weight+HT[s2].weight;//这里才把i的权值填上去
    }

}

void CreateHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n) //HC是二维数组的指针,指向哈夫曼编码表
{
    HC = new char *[n + 1];      //HC的元素就是一个个一维数组
    char *cd = new char[n];      //cd是一个临时的一维数组,用于存储编号为n的节点的哈夫曼编码
    cd[n - 1] = '\0';            //编码结束符
    for (int i = 1; i <= n; i++) //对每一个节点进行编码
    {
        int start = n - 1;           //start指向最后的位置,也就是编码结束的位置,每完成一个字符的输入,start前移一个单位
        int c = i, f = HT[i].parent; //f指向节点c的双亲节点
        while (f)                    //f最终指向整棵树的根节点时编码最后一位,之后由于根节点无双亲节点,循环结束
        {
            start--;               //start回溯一个位置
            if (HT[f].lchild == c) //判断编码为'0'还是'1'
                cd[start] = '0';
            else
                cd[start] = '1';
            c = f;
            f = HT[f].parent; //递归,逆序编码,因此编码顺序在cd表现出来是从后往前的
        }
        HC[i] = new char[n - start]; //为第i个字符分配编码空间
        strcpy(HC[i], &cd[start]);   //复制cd的内容到HC[i]
    }
    delete cd; //释放临时空间cd
}

int main()
{
    int n;
    scanf("%d", &n); //输入权值个数
    HuffmanTree HT;
    CreateHuffmanTree(HT, n); //建树
    HuffmanCode HC;
    CreateHuffmanCode(HT, HC, n); //求哈夫曼编码表
    for (int i = 1; i <= n; i++)
        puts(HC[i]); //输出哈夫曼编码表
    return 0;
}

额外题:任意两节点距离

/**2.哈夫曼树、3.任意两节点之间的最小距离*/
#include <iostream>

using namespace std;


/**以下为 3.任意两节点之间的最小距离*/
/**注意 领悟 函数相互调用,而不是 不断添加参数到函数里**/

/*
记root为二叉树的根节点,lca是两个节点n1和n2的最低公共祖先节点,如题目示意图中节点4和5的最低公共祖先为2,节点4和6的最低公共祖先
为1,则有以下结论是成立的:
Dist(n1, n2) = Dist(root, n1) + Dist(root, n2) - 2*Dist(root, lca) 
Dist(n1, n2)表示节点n1和n2的距离
*/


#include "stdio.h"
#include "malloc.h"
#define TRUE 1
#define FALSE 0
#define OK  1
#define ERROR  0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int  Status;

typedef char  ElemType;
typedef struct BiTNode
{
    ElemType data;
    struct BiTNode *lchild,*rchild;//左右孩子指针
} BiTNode,*BiTree;

Status CreateBiTree(BiTree &T)    // 算法6.4
{
    // 按先序次序输入二叉树中结点的值(一个字符),’#’字符表示空树,
    // 构造二叉链表表示的二叉树T。
    char ch;
    scanf("%c",&ch);
    if (ch=='#') T = NULL;
    else
    {
        if (!(T = (BiTNode *)malloc(sizeof(BiTNode)))) return ERROR;
        T->data=ch; // 生成根结点
        CreateBiTree(T->lchild);   // 构造左子树
        CreateBiTree(T->rchild);  // 构造右子树
    }
    return OK;
} // CreateBiTree






BiTNode* findzuxian(BiTNode*T,char n1,char n2)
{
    if(!T)
        return NULL;
    if(T->data==n1||T->data==n2)
    {
        return T; //想不到
    }
    BiTNode*l=findzuxian(T->lchild,n1,n2);
    BiTNode*r=findzuxian(T->rchild,n1,n2);
    if(l&&r)
        return T;
    return (l==NULL?r:l);
}

int dfs(BiTNode*T,char n)
{
    if(T==NULL)
        return -1;
    if(T->data==n)
        return 0;

    int l=dfs(T->lchild,n);
    if(l==-1)
        l=dfs(T->rchild,n);
    if(l!=-1)
        return l+1;
    else
        return -1;

}

int main()   //主函数
{
    BiTNode*T=NULL;
    CreateBiTree(T);

    char n1,n2;
    cin>>n1>>n2;
    BiTNode*tmp=findzuxian(T,n1,n2);

    int dista=dfs(T,tmp->data);
    int dist1=dfs(T,n1);
    int dist2=dfs(T,n2);

    cout<<dist1+dist2-2*dista<<endl;


}//main

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值