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