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

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

  

时间: 2024-10-09 13:30:42

哈夫曼树(数组表示)仅代码的相关文章

赫夫曼树JAVA实现及分析

一,介绍 1)构造赫夫曼树的算法是一个贪心算法,贪心的地方在于:总是选取当前频率(权值)最低的两个结点来进行合并,构造新结点. 2)使用最小堆来选取频率最小的节点,有助于提高算法效率,因为要选频率最低的,要么用排序,要么用堆.用堆的话,出堆的复杂度为O(logN),而向堆中插入一个元素的平均时间复杂度为O(1),在构建赫夫曼树的过程中,新生成的结点需要插入到原来的队列中,故用堆来维持这种顺序比排序算法要高效地多. 二,赫夫曼算法分析 ①用到的数据结构分析 首先需要构造一棵赫夫曼树,因此需要二叉链

赫夫曼树编码

在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN) 树和哈夫曼编码.哈夫曼编码是哈夫曼树的一个应用.哈夫曼编码应用广泛,如 JPEG中就应用了哈夫曼编码. 首先介绍什么是哈夫曼树.哈夫曼树又称最优二叉树, 是一种带权路径长度最短的二叉树.所谓树的带权路径长度,就是树中所有的叶结点 的权值乘上其到根结点的 路径长度(若根结点为0层,叶结点到根结点的路径长度 为叶结点的层数).树的带权路径长度记为WPL= (W1*L1+W2*L2+W3*L3+...+Wn*Ln) ,

哈夫曼树原理及构造(转载)

构造哈夫曼树的过程是这样的 一.构成初始集合 对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空.(为方便在计算机上实现算法,一般还要求以Ti的权值Wi的升序排列.) 二.选取左右子树 在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和. 三.删除左右子树 从F中删除这两棵树,

看数据结构写代码(32) 赫夫曼树编码以及译码

杂谈:最近有点慵懒,不好不好.好几天都没写代码,原本准备上星期完结 树 这一章节的.现在 又耽误了.哎.要抓紧时间啊. 下面直接上代码: 可以到我的网盘下载源代码,或者 直接拷贝下面的源代码 运行 网盘地址:点击打开链接 // HuffmanTree.cpp : 定义控制台应用程序的入口点. //哈弗曼编码,译码 #include "stdafx.h" #include <stdlib.h> #include <cstring> enum E_State { E

转载:哈夫曼树的构造和哈夫曼编码(C++代码实现)

作者:qiqifanqi 原文:http://blog.csdn.net/qiqifanqi/article/details/6038822 #include<stdio.h> #define MAX 100 #define MAXVALUE 500 typedef struct { int weight; int parent,lchild,rchild; }node; /*哈夫曼树结点类型*/ /*-----------------------------以下部分定义哈夫曼编码存储结构--

新学的代码:哈夫曼树的生成实验

// Haffman.cpp : Defines the entry point for the console application.// #include "stdafx.h"#include <stdio.h>#include <string.h>typedef char DataType; struct element  //结点定义{        DataType data;   float weight;//此字符的权值      int par

哈夫曼树与哈夫曼编码

哈夫曼树与哈夫曼编码 术语: i)路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径. 路径中分支的数目称为路径长度.若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1. ii)结点的权及带权路径长度 若对树中的每个结点赋给一个有着某种含义的数值,则这个数值称为该结点的权. 结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积. iii)树的带权路径长度 树的带权路径长度:所有叶子结点的带权路径长度之和,记为WPL. 先了解一下

数据结构第三部分:树与树的表示、二叉树及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树、集合及其运算

参考:浙大数据结构(陈越.何钦铭)课件 1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找——方法一:顺序查找(时间复杂度O(n)) int

哈夫曼树(三)之 Java详解

前面分别通过C和C++实现了哈夫曼树,本章给出哈夫曼树的java版本. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载请注明出处:http://www.cnblogs.com/skywang12345/ 更多内容:数据结构与算法系列 目录 哈夫曼树的介绍 Huffman Tree,中文名是哈夫曼树或霍夫曼树,它是最优二叉树. 定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树. 这