zoukankan      html  css  js  c++  java
  • 最优二叉树(简易版本)

    最优二叉树——哈夫曼树

     

    一:什么是最优二叉树:

      就是从已给出的目标带权结点(单独的结点) 经过一种方式的组合形成一棵树.使树的权值最小。

        注意: 带权值的结点都是叶子结点。权值越小的结点,其到根结点的路径越长

     

    二:哈夫曼算法:

     (1)根据给定的n个权值wl,w2,…,wn构成n棵二叉树的森林F={T1,T2,…,Tn},其中每棵二叉树Ti中都只有一个权值为wi的根结点,其左右子树均空。

     (2)在森林F中选出两棵根结点权值最小的树(当这样的树不止两棵树时,可以从中任选两棵),将这两棵树合并成一棵新树,为了保证新树仍是二叉树,需 要增加一个新结点作为新树的根,并将所选的两棵树的根分别作为新根的左右孩子(谁左,谁右无关紧要),将这两个孩子的权值之和作为新树根的权值。   

     (3)对新的森林F重复(2),直到森林F中只剩下一棵树为止。这棵树便是哈夫曼树。

      注意: ① 初始森林中的n棵二叉树,每棵树有一个孤立的结点,它们既是根,又是叶子 ② n个叶子的哈夫曼树要经过n-1次合并,产生n-1个新结点。最终求得的哈夫曼树中共有2n-1个结点。 ③ 哈夫曼树是严格的二叉树,没有度数为1的分支结点。

     

    三:最优二叉树实现思路:

      设置一个结构数组HuffNode保存哈夫曼树中各结点的信息 , 具有n个叶子结点的哈夫曼树共有2n-1个结点,所以数组HuffNode的大小设置为2n-1 先将由n个字符形成的n个叶结点存放到数组HuffNode的前n个分量中,然后 不断将两个小子树合并为一个较大的子树,每次构成的新子树的根结点顺序放到HuffNode数组中的前n个分量的后面。

     

    四:参考代码:(之后记得看一下)

    #include <stdio.h>
    #include <stdlib.h>
    #define m 100
    ​
    ​
    struct ptree              //定义二叉树结点类型
    {
        int w;                   //定义结点权值
        struct ptree* lchild;     //定义左子结点指针
        struct ptree* rchild;     //定义右子结点指针
    };
    ​
    ​
    ​
    struct pforest              //定义链表结点类型
    {
        struct pforest* link;
        struct ptree* root;
    };
    ​
    ​
    ​
    int WPL = 0;                  //初始化WTL为0
    struct ptree* hafm();
    void travel();
    struct pforest* inforest(struct pforest* f, struct ptree* t);
    ​
    void travel(struct ptree* head, int n)
    {
        //为验证harfm算法的正确性进行的遍历
        struct ptree* p;
        p = head;
        if (p != NULL)
        {
            if ((p->lchild) == NULL && (p->rchild) == NULL) //如果是叶子结点
            {
                printf("%d ", p->w);
                printf("the hops of the node is: %d/n", n);
                WPL = WPL + n * (p->w);    //计算权值
            }//if
            travel(p->lchild, n + 1);
            travel(p->rchild, n + 1);
        }//if
    }//travel
    ​
    ​
    ​
    struct ptree* hafm(int n, int w[m])
    {
        struct pforest* p1, * p2, * f;
        struct ptree* ti, * t, * t1, * t2;
        int i;
        f = (pforest*)malloc(sizeof(pforest));
        f->link = NULL;
        
        for (i = 1; i <= n; i++)          //产生n棵只有根结点的二叉树
        {
            ti = (ptree*)malloc(sizeof(ptree));//开辟新的结点空间
            ti->w = w[i];               //给结点赋权值
            ti->lchild = NULL;
            ti->rchild = NULL;
            f = inforest(f, ti);
            //按权值从小到大的顺序将结点从上到下地挂在一颗树上     
        }//for
    while (((f->link)->link) != NULL)//至少有二棵二叉树
        {
            p1 = f->link;
            p2 = p1->link;
            f->link = p2->link;           //取出前两棵树
            t1 = p1->root;
            t2 = p2->root;
            free(p1);                 //释放p1
            free(p2);                 //释放p2
    ​
            t = (ptree*)malloc(sizeof(ptree));//开辟新的结点空间
            t->w = (t1->w) + (t2->w);        //权相加
            t->lchild = t1;
            t->rchild = t2;             //产生新二叉树
            f = inforest(f, t);
        }//while
    ​
        p1 = f->link;
        t = p1->root;
        free(f);
        return(t);                  //返回t
    }
    ​
    ​
    ​
    pforest* inforest(struct pforest* f, structptree* t)
    {
        //按权值从小到大的顺序将结点从上到下地挂在一颗树上     
        struct pforest* p, * q, * r;
        struct ptree* ti;
        r = (pforest*)malloc(sizeof(pforest)); //开辟新的结点空间
        r->root = t;
        q = f;
        p = f->link;
        
        while (p != NULL)            //寻找插入位置
        {
            ti = p->root;
            if (t->w > ti->w)         //如果t的权值大于ti的权值
            {
                q = p;
                p = p->link;             //p向后寻找
            }//if
            else
                p = NULL;                  //强迫退出循环
        }//while
    ​
        r->link = q->link;
        q->link = r;                 //r接在q的后面
        return(f);                 //返回f
    }
    ​
    ​
    ​
    void InPut(int& n, int w[m])
    {
        printf("please input the sum ofnode/n"); //提示输入结点数
        scanf("%d", &n);      //输入结点数
        printf("please input weight of everynode/n"); //提示输入每个结点的权值
        for (int i = 1; i <= n; i++)
            scanf("%d", &w[i]);  //输入每个结点权值
    }
    ​
    ​
    int main()
    {
        struct ptree* head;
        int n, w[m];
        InPut(n, w);
        head = hafm(n, w);
        travel(head, 0);
        printf("The length of the best path isWPL=%d", WPL);//输出最佳路径权值之和
        return 1;
    }

     

  • 相关阅读:
    Git学习笔记
    利用GitHub Pages和Hexo搭建个人博客
    dpkg的用法
    Ubuntu 16.04安装有道词典
    Linux 命令之删除命令
    Linux 命令之权限修改
    PHP学习记录第一篇:Ubuntu14.04下LAMP环境的搭建
    ubuntu时钟不显示的解决方法
    kali linux 2.0安装sublime text 2
    折腾kali linux2.0
  • 原文地址:https://www.cnblogs.com/instead-everyone/p/13733937.html
Copyright © 2011-2022 走看看