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

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

  

转载于:https://www.cnblogs.com/dan-jacky/p/6871971.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这里是使用数组实现的哈夫曼树创建算法的完整代码: ```c++ #include <iostream> #include <climits> using namespace std; // 定义一个节点结构体 struct Node { int weight; // 权值 int parent; // 父节点 int left; // 左子节点 int right; // 右子节点 }; // 创建哈夫曼树的函数 void createHuffmanTree(Node *tree, int *weights, int n) { // 初始化森林,每个节点作为一棵只包含自己的树 for (int i = 0; i < n; i++) { tree[i].weight = weights[i]; tree[i].parent = -1; tree[i].left = -1; tree[i].right = -1; } // 合并森林中的树,直到森林中只剩下一棵树 for (int i = 0; i < n - 1; i++) { int min1 = INT_MAX, min2 = INT_MAX; // 记录森林中权值最小的两棵树 int min1Index = -1, min2Index = -1; // 在森林中找到权值最小的两棵树 for (int j = 0; j < n + i; j++) { if (tree[j].parent == -1) { // 只考虑还没有被合并的树 if (tree[j].weight < min1) { min2 = min1; min2Index = min1Index; min1 = tree[j].weight; min1Index = j; } else if (tree[j].weight < min2) { min2 = tree[j].weight; min2Index = j; } } } // 合并权值最小的两棵树 tree[min1Index].parent = n + i; tree[min2Index].parent = n + i; tree[n + i].weight = tree[min1Index].weight + tree[min2Index].weight; tree[n + i].left = min1Index; tree[n + i].right = min2Index; } } int main() { int weights[] = { 5, 2, 4, 7, 1, 3, 6 }; int n = sizeof(weights) / sizeof(weights[0]); Node *tree = new Node[2 * n - 1]; // 创建哈夫曼树 createHuffmanTree(tree, weights, n); // 输出哈夫曼树中每个节点的信息 for (int i = 0; i < 2 * n - 1; i++) { cout << "Node " << i << ": weight=" << tree[i].weight << ", parent=" << tree[i].parent << ", left=" << tree[i].left << ", right=" << tree[i].right << endl; } delete [] tree; return 0; } ``` 在这个例子中,我们使用一个整型数组表示待编码字符串中每个字符的出现频率。我们首先创建一个大小为2*n-1的节点数组,其中n是字符的个数。然后调用createHuffmanTree函数来创建哈夫曼树。最后,我们输出哈夫曼树中每个节点的信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值