zoukankan      html  css  js  c++  java
  • 哈夫曼树(数组表示)仅代码

    关于哈夫曼树的介绍,网上的资料很多,这里就不多介绍了。下面是C语言的代码实现。GCC5.3.0编译通过。

    // Created by Jacky on 2017-5-18
    // main.c -- 哈夫曼树(数组表示)
    
    #include <stdio.h>
    #include <stdlib.h>
    
    /**
     * 哈夫曼树的结点定义
     */
    typedef struct HuffmanNode
    {
        char data;  // 字符
        int weight; // 权值,字符出现次数
        int parent; // 父结点的数组下标
        int left;   // 左孩子的数组下标
        int right;  // 右孩子的数组下标
    } HuffmanNode;
    
    /**
     * 哈夫曼树定义
     */
    typedef struct HuffmanTree
    {
        int count;          // 结点数,也就是数组长度 = 2 * 叶子结点 - 1
        HuffmanNode *nodes; // 结点数组
    } HuffmanTree;
    
    #define HUFFMANTREE_INIT {0, NULL}
    
    void InitHuffmanTree(HuffmanTree *T, const char *str);
    void CreateHuffmanTree(HuffmanTree *T);
    void PrintHuffmanTree(HuffmanTree T);
    void Visit(HuffmanNode *node);
    void PreOrderTraversal(HuffmanTree T, void (*visit)(HuffmanNode *));
    void InOrderTraversal(HuffmanTree T, void (*visit)(HuffmanNode *));
    void PostOrderTraversal(HuffmanTree T, void (*visit)(HuffmanNode *));
    
    int main(int argc, char const *argv[])
    {
        HuffmanTree T = HUFFMANTREE_INIT;
        InitHuffmanTree(&T, "aaaabbc");
        CreateHuffmanTree(&T);
        PrintHuffmanTree(T);
        // PostOrderTraversal(T, Visit);
    
        free(T.nodes);// 释放结点申请的内存
        T.nodes = NULL;
        return 0;
    }
    
    /**
     * 初始化哈夫曼树。
     * 根据给定的字符串,统计每个字符出现的次数。
     * 并用统计的信息来构造哈夫曼树的叶子结点。
     * @param T   哈夫曼树对象指针
     * @param str 需要统计的字符串
     */
    void InitHuffmanTree(HuffmanTree *T, const char *str)
    {
        // 统计每个字符出现的次数。
        int arr[256] = {0};
        while (*str)
        {
            arr[*str]++;
            str++;
        }
    
        int leafCount = 0;
    
        // 统计叶子结点的个数。
        for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
        {
            if (arr[i])
            {
                leafCount++;
                // printf("%c %d
    ", i, arr[i]);
            }
        }
    
        // printf("leafCount = %d.
    ", leafCount);
    
        HuffmanNode *nodes = (HuffmanNode *)malloc((2 * leafCount - 1) * sizeof(HuffmanNode));
        T->count = 2 * leafCount - 1;
    
        leafCount = 0;
        for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
        {
            if (arr[i])
            {
                nodes[leafCount].data = i;
                nodes[leafCount].weight = arr[i];
                nodes[leafCount].parent = nodes[leafCount].left = nodes[leafCount].right = -1;
                leafCount++;
            }
        }
        T->nodes = nodes;
    }
    
    /**
     * 通过给定的叶子结点构造整棵哈夫曼树。
     * @param T 哈夫曼树对象指针
     */
    void CreateHuffmanTree(HuffmanTree *T)
    {
        int leafCount = (T->count + 1) / 2;// 结点数 = 2 * 叶子结点 - 1
    
        for (int i = leafCount; i < T->count; ++i)
        {
            int min1 = -1;// weight最小的结点数组下标
            int min2 = -1;// weight次小的结点数组下标
            for (int j = 0; j < i; ++j)
            {
                if (T->nodes[j].parent == -1)
                {
                    if (min1 == -1)// 第一次进入的时候,给min1赋值
                    {
                        min1 = j;
                    }
                    else if (min2 == -1)// 第二次进入的时候,给min1,min2赋值
                    {
                        if (T->nodes[j].weight < T->nodes[min1].weight)
                        {
                            min2 = min1;
                            min1 = j;
                        }
                        else
                        {
                            min2 = j;
                        }
                    }
                    else// 第三次及之后进入
                    {
                        if (T->nodes[j].weight < T->nodes[min1].weight)
                        {
                            min2 = min1;
                            min1 = j;
                        }
                        else if (T->nodes[j].weight < T->nodes[min2].weight)
                        {
                            min2 = j;
                        }
                    }
                }
            }
            // printf("min1 = %d, min2 = %d.
    ", min1, min2);
            T->nodes[i].data = 0;
            T->nodes[i].weight = T->nodes[min1].weight + T->nodes[min2].weight;
            T->nodes[i].parent = -1;
            T->nodes[i].left = min1;
            T->nodes[i].right = min2;
    
            T->nodes[min1].parent = T->nodes[min2].parent = i;
        }
    }
    
    /**
     * 哈夫曼树的结点的访问
     * @param node 结点地址
     */
    void Visit(HuffmanNode *node)
    {
        printf("%c %2d
    ", node->data, node->weight);
    }
    
    void PreOrder(HuffmanTree T, void (*visit)(HuffmanNode *), int index)
    {
        if (index != -1)
        {
            visit(&T.nodes[index]);
            PreOrder(T, visit, T.nodes[index].left);
            PreOrder(T, visit, T.nodes[index].right);
        }
    }
    
    void InOrder(HuffmanTree T, void (*visit)(HuffmanNode *), int index)
    {
        if (index != -1)
        {
            InOrder(T, visit, T.nodes[index].left);
            visit(&T.nodes[index]);
            InOrder(T, visit, T.nodes[index].right);
        }
    }
    
    void PostOrder(HuffmanTree T, void (*visit)(HuffmanNode *), int index)
    {
        if (index != -1)
        {
            PostOrder(T, visit, T.nodes[index].left);
            visit(&T.nodes[index]);
            PostOrder(T, visit, T.nodes[index].right);
        }
    }
    
    /**
     * 前序遍历
     */
    void PreOrderTraversal(HuffmanTree T, void (*visit)(HuffmanNode *))
    {
        PreOrder(T, visit, T.count - 1);
    }
    
    /**
     * 中序遍历
     */
    void InOrderTraversal(HuffmanTree T, void (*visit)(HuffmanNode *))
    {
        InOrder(T, visit, T.count - 1);
    }
    
    /**
     * 后续遍历
     */
    void PostOrderTraversal(HuffmanTree T, void (*visit)(HuffmanNode *))
    {
        PostOrder(T, visit, T.count - 1);
    }
    
    /**
     * 打印哈夫曼树信息,方便调试
     * @param T         哈夫曼树对象
     */
    void PrintHuffmanTree(HuffmanTree T)
    {
        printf("
    count = %d.
    ", T.count);
        char *rows[] = {"index", "data", "weight", "parent", "left", "right"};
        int count = T.count;
    
        for (int i = 0; i < sizeof(rows) / sizeof(rows[0]); ++i)
        {
            if (i == 0)
            {
                printf("+--------+");
                for (int i = 0; i < count; ++i)
                {
                    printf("----+");
                }
            }
            printf("
    |%-8s|", rows[i]);
            for (int j = 0; j < count; ++j)
            {
                switch (i)
                {
                case 0:// index
                    printf(" %-3d|", j);
                    break;
                case 1:// data
                    if (T.nodes[j].data == 10)// 回车
                    {
                        printf(" %-3d|", T.nodes[j].data);
                    }
                    else
                    {
                        printf(" %-3c|", T.nodes[j].data);
                    }
                    break;
                case 2:// weight
                    printf(" %-3d|", T.nodes[j].weight);
                    break;
                case 3:// parent
                    printf(" %-3d|", T.nodes[j].parent);
                    break;
                case 4:// left
                    printf(" %-3d|", T.nodes[j].left);
                    break;
                case 5:// right
                    printf(" %-3d|", T.nodes[j].right);
                    break;
                }
            }
            printf("
    +--------+");
            for (int j = 0; j < count; ++j)
            {
                printf("----+");
            }
        }
    
        printf("
    ");
    }
    

      

  • 相关阅读:
    python实现单链表及常用方法->判空|长度|头尾及指定插入|删除|搜索|反转
    k8s v1.21.9集群安装带认证的elk 6.8.18
    docker安装Elasticsearch6.8集群并设置密码
    kubernetes v1.20.9部署keepalived-vip实现高可用pod访问
    rsync远程同步工具的使用-实现跳板机与内网数据传输
    旧金山大学 大卫 算法演示
    IO多路复用之select、poll、epoll详解-转载
    docker容器中使用systemctl命令 set-hostname
    win7 安装ss
    常用相似度语料
  • 原文地址:https://www.cnblogs.com/jackylovewendy/p/6871971.html
Copyright © 2011-2022 走看看