二叉树和哈夫曼树(dsoj c++)

 DS二叉树--赫夫曼树的构建与编码(不含代码框架)

#include <iostream>
#include<string>
#include<cstring>
using namespace std;
//创建哈夫曼树节点
class hfmnode
{
public:
    int left;  // 左孩子下标
    int right;  // 右孩子下标
    int parents;  //双亲结点下标
    int weight;  // 权值
    hfmnode():left(0),right(0),parents(0),weight(0){}
};
class hfm
{
public:
    int num; //权值个数即叶子数量
    int leaf; //树的节点
    hfmnode*tree;  //数组哈夫曼树
    string *code;  //每个字符对应的哈夫曼编码
    void create(int n,int a[]) //建树,参数是叶子节点数量和叶子权值
    {
        num=n;
        leaf=2*n-1;  //有n个结点构成哈夫曼树则会生成2n-1个结点
        tree=new hfmnode[2*n];  //由于数组访问是从位置1开始,所以真正要申请的空间为2n个
        code=new string [num+1];  //实质是个二维字符数组,第i行表示第i个字符对应的编码
        for(int i=1;i<=n;i++)
        {
            tree[i].weight=a[i-1];  //第0个不用,从1开始编号
        }
        for(int i=1;i<=leaf;i++)
        {
            if(i>n){
                tree[i].weight=0;  //前n个结点是叶子,已经设置了权值
            }
            tree[i].parents=0;  //全部设0
            tree[i].left=0;
            tree[i].right=0;
        }
        int s1,s2;
        //构造n-1个非叶子结点
        for(int i=num+1;i<=leaf;i++)
        {
            //找出权值最小的两个点 //因为hufftree位置从1开始weight位置从0开始所以是i-1
            select(i-1, &s1, &s2);
            tree[s1].parents=i;
            tree[s2].parents=i;
            tree[i].weight=tree[s1].weight+tree[s2].weight;
            tree[i].left=s1;
            tree[i].right=s2;
        }
    }
    void select(int pos,int *s1,int *s2)//从1到pos的位置找出权值最小的两个点,把这两个点存到s1和s2里
    {
        // 找出最小的两个权值的下标
           // 函数采用地址传递的方法,找出两个下标保存在 s1 和 s2 中
        int d1=10001,d2=10001;
        *s1=*s2=0;
        for(int i=1;i<=pos;i++)
        {
            if(tree[i].parents==0&&tree[i].weight<d1)
            {
                d2=d1;
                *s2=*s1;
                d1=tree[i].weight;
                *s1=i;  //第一最小值
            }
            else if(tree[i].weight<d2&&tree[i].parents==0)
            {
                d2=tree[i].weight;
                *s2=i;  //第二最小值
            }
        }
    }
    void createcode()
    {
        char *g;
        int start;
        //求n个叶结点的哈夫曼编码
        g=new char[num];  //分配空间
        g[num-1]='\0';  //结束符
        int c,f,i;
        for(i=1;i<=num;++i)
        {
            start = num- 1;  //编码结束位置
            c=i;
            for(f=tree[i].parents;f!=0;c=f,f=tree[f].parents)
            {
                if(tree[f].left==c)
                {
                    g[--start]='0';
                }
                else
                {
                    g[--start]='1';
                }
            }
            code[i] = new char[num-start];
            code[i].assign(&g[start]); // 把cd中从start到末尾的编码复制到huffCode中
        }
        delete[]g;    // 释放工作空间
    }
};
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin>>n;
        int p[1000];
        for(int i=0;i<n;i++)
        {
            cin>>p[i];  //输入权值
        }
        hfm myhuff;
        myhuff.create(n,p);
        myhuff.createcode();
        for(int j=1;j<=n;j++)
        {
            cout<<myhuff.tree[j].weight<<"-";
            cout<<myhuff.code[j]<<endl;
        }
    }
}

E. DS树--带权路径和

#include <iostream>
#include<string>
#include<cstring>
#define ok 1
#define error -1
using namespace std;

class hfmnode
{
public:
    char data;
    hfmnode *left;  // 左孩子
    hfmnode *right;  // 右孩子
    int weight;  // 权值
    int height;  //高度
    hfmnode():left(0),right(0),weight(0),height(0){}
};
class hfm
{
public:
    int len;
    hfmnode*root;  //huffman树,用数组表示
    string str;
    int pos;  //记录位置
    int sum;
    int apl;
    //创造结点
    hfmnode*create(int *w,int h)  //记录权值的数组和高度
    {
        hfmnode *p;
        char ch;
        ch=str[pos];  //字符
        pos++;  //位置++
        if(ch=='0') //空树
        {
            p=NULL;
        }
        else
        {
            p=new hfmnode();
            p->data=ch;
            p->height=h+1;//高度加一(根是0)
            if(p->data>='A'&&p->data<='Z')  //如果是叶子
            {
                p->weight=w[sum];//记录权值的数组
                sum++;
            }
            //递归
            p->left=create(w,p->height);
            p->right=create(w,p->height);
         }
        return p;
    }
    void preorder()  //先序
    {
        root->height=1;
        preorder(root);
        cout<<apl<<endl;
    }
    void preorder(hfmnode*p)
    {
        if(p)
        {
            apl+=p->weight*p->height;  //只有叶子结点是有权值
            preorder(p->left);
            preorder(p->right);
        }
    }
    hfm(){apl=0;}
    //创建树
    void create(string q,int *w) //传入二叉树的字符和叶子权值数组
    {
        pos=0;
        sum=0;
        str.assign(q);  //拷贝字符串
        root=create(w, -1);
    }
};
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        string tree;
        int p[1000];
        int n;
        hfm t;
        cin>>tree>>n;
        for(int i=0;i<n;i++)
        {
            cin>>p[i];
        }
        t.create(tree, p);
        t.preorder();
    }
}

F. DS树--二叉树之最大路径

#include <iostream>
#include<string>
#include<queue>
#include<cstring>
#define ok 1
#define error -1
using namespace std;

class bitnode
{
public:
    
    char data;
    bitnode *left;  // 左孩子
    bitnode *right;  // 右孩子
    int weight;  // 权值
    int height;  //高度
    bitnode():left(0),right(0),weight(0),height(0){}
};
class bittree
{
public:
    int len;
    bitnode*root;
    string str;
    int pos;
    int sum;
    int road;
    queue<int>ro;  //权值队列
    bitnode*create(int *w,int h)
    {
        bitnode *p;
        char ch;
        ch=str[pos];
        pos++;
        if(ch=='0') //空树
        {
            p=NULL;
        }
        else
        {
            p=new bitnode();
            p->data=ch;
            p->height=h+1;//高度加一
            p->left=create(w,p->height);
            p->right=create(w,p->height);
         }
        return p;
    }
    //获取路径最大值
    void getroad()
    {
        getroad(root,0);
        cout<<road<<endl;
    }
    void getroad(bitnode*p,int roa)
    {
        if(p)
        {
            p->weight=ro.front()+roa; //修改权值为队列头权值加当前路径
            ro.pop();
            getroad(p->left,p->weight);
            getroad(p->right,p->weight);
            if(!p->left&&!p->right)  //如果是叶子节点
            {
                if(p->weight>road) //如果权值大于当前总路径则更新
                {
                    road=p->weight;
                }
            }
        }
    }
    bittree(){road=0;}
    void create(string q,int *w,queue<int>r)
    {
        pos=0;
        road=0;
        sum=0;
        str.assign(q);  //拷贝字符串
        ro=r;
        root=create(w, -1);
    }
};
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        string tree;
        int p[1000];
        queue<int> weights;
        int n;
        bittree t;
        cin>>tree>>n;
        for(int i=0;i<n;i++)
        {
            cin>>p[i];
            weights.push(p[i]);
        }
        t.create(tree, p,weights);
        t.getroad();
    }
}

G. 二叉树的中后序遍历构建及求叶子

#include <iostream>
using namespace std;

class bitnode
{
public:
    int data;
    bitnode* left; //左孩子
    bitnode* right; //右孩子
    int weight;
    bitnode()
    {
        left=NULL;
        right=NULL;
    }
};

class tree
{
public:
    bitnode* root;
    int *inoder;
    int *postorder;
    int len;
    int min=99999;
    //创建树
    void create()
    {
       create(root,inoder, postorder, len);
    }
    void create(bitnode *&d,int *p,int *q,int n) //创建树
    {
        if(n==0)
        {
            d=NULL;
        }
        else
        {
            d=new bitnode();
            d->data=q[n-1];  //后序
            int i,j;
            for(i=0;i<n;i++)
            {
                if(p[i]==q[n-1])  //找到根节点
                {
                    break;
                }
            }
            int num1=i; //正着根
            int num2=n-i-1;  //逆着根
            int in1[num1],in2[num2];
            for(j=0;j<n;j++)
            {
                if(j<i)  //传入
                 {
                     in1[j]=p[j];
                 }
                 else if(j>i)
                 {
                     in2[j-i-1]=p[j];
                 }
            }
            int post1[num1], post2[num2];
            for(j=0; j<n; j++)
            {
                 if(j<i)
                 {
                     post1[j] = q[j];
                 }
                 else if(j>=i && j<n-1)
                 {
                     post2[j-i] = q[j];
                 }
             }
            create(d->left, in1,  post1,num1);  //左子树
            create(d->right, in2,post2, num2);  //右子树
        }
    }
    tree(int n,int *p,int *q)
    {
        len=n;  //结点数
        min=99999;
        inoder=new int [n];
        postorder=new int [n];
        for(int i=0;i<n;i++)
        {
            inoder[i]=p[i];
            postorder[i]=q[i];
        }
    }
    void getmin()
    {
        getmin(root);
    }
    void getmin(bitnode*t)
    {
        if(t)
        {
            if(!t->left&&!t->right) //如果是叶子
            {
                if(t->data<min)
                {
                    min=t->data;
                }
            }
            getmin(t->left);
            getmin(t->right);
        }
    }
};
int main()
{
    int n;
    while (cin>>n)
    {
        int *io=new int [n];
        int *po=new int [n];
        for(int i=0;i<n;i++)
        {
            cin>>io[i]; //中序
        }
        for(int i=0;i<n;i++)
        {
            cin>>po[i];  //后序
        }
        tree mytree(n,io,po);
        mytree.create();
        mytree.getmin();
        cout<<mytree.min<<endl;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值