哈夫曼树(数组表示)仅代码

关于哈夫曼树的介绍,网上的资料很多,这里就不多介绍了。下面是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\n", i, arr[i]);
        }
    }

    // printf("leafCount = %d.\n", 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.\n", 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\n", 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("\ncount = %d.\n", 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("\n|%-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("\n+--------+");
        for (int j = 0; j < count; ++j)
        {
            printf("----+");
        }
    }

    printf("\n");
}

  

posted @ 2017-05-18 10:13  Wendy.Jacky  阅读(1354)  评论(0编辑  收藏  举报