从头结点开始编码的赫夫曼树

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#ifndef MACRO_//宏
#define MACRO_
#define OK 1
#define FALSE 0
#define ERROR 0
#define TURE 1
#define OVERFLOW -2
#define INFEASIBLE -1
typedef int Status;
typedef int BOOL;
#endif
/*注意,自顶向下求编码会破坏HT的原本数据,都变成2,要想克服,需采用自底向上求编码
      或者另设记录每个元素访问记录的数组    同时,也无法正确解码
      -----------------严蔚敏教材缺陷---------------
*/

typedef struct
{
    int weight;
    int parent, lchild, rchild;
}HTNode, *HuffmanTree;//动态分配数组存储赫夫曼树

typedef char **HuffmanCode;//动态分配数组存储赫夫曼编码表

Status Input(int *ElemNum, int **WeightArray);
//输入权值
//成功返回OK,ElemNum不合适返回ERROR
void SlectMin(int i, int *S1, int *S2, HuffmanTree HT);
//从HuffmanTree中选出Parent为0,权值最小的两个数,分别将下标存放在S1和S2中,其中S1中存放的值<S2中存放的值
//i表示当前有效结点的下标
void CreatHuffmanTree(HuffmanTree *HT, int *WeightArray, int ElemNum);
//WeightArray存放ElemNum个字符的权值(均>0),构造赫夫曼树HT
void HuffmanCoding_FromRoot(HuffmanTree HT, HuffmanCode *HC, int ElemNum);
//从头结点开始遍历,求出n个字符的赫夫曼编码HC
void Decode(HuffmanTree HT, int ElemNum);
//输入哈夫曼编码,解码

int main()
{
    int ElemNum, *WeightArray;
    HuffmanTree HT;
    HuffmanCode HC;
    while (Input(&ElemNum, &WeightArray) == ERROR)
        printf("The value of ElemNum is not feasible ! \n");
    CreatHuffmanTree(&HT, WeightArray, ElemNum);
    HuffmanCoding_FromRoot(HT, &HC, ElemNum);
    for (int i = 1; i <= ElemNum; ++i)
        printf("%-3d  ,coding is : %s\n", HT[i].weight, HC[i]);
    /*注意,自顶向下求编码会破坏HT的原本数据,都变成2,要想克服,需采用自底向上求编码
      或者另设记录每个元素访问记录的数组
      -----------------严蔚敏教材缺陷---------------
    */
    Decode(HT, ElemNum);
    system("pause");
}

Status Input(int *ElemNum,int **WeightArray)
//输入权值
//成功返回OK,ElemNum不合适返回ERROR
{
    printf("How many elems ? \n");
    scanf("%d", ElemNum);
    if (*ElemNum>1)//小于2还建什么Huffman树呢?
    {
        *WeightArray = (int *)malloc(sizeof(int)*(*ElemNum));
        if (!(*WeightArray))
            exit(OVERFLOW);
        printf("\nPlease Enter the weight\n");
        for (int i = 0; i < (*ElemNum); ++i)
            scanf("%d", &(*WeightArray)[i]);
        return OK;
    }//if
    return ERROR;
}//CrearHuffmanTree

void CreatHuffmanTree(HuffmanTree *HT,int *WeightArray,int ElemNum)
//WeightArray存放ElemNum个字符的权值(均>0),构造赫夫曼树HT
{
    for (int i = 0; i < ElemNum; ++i)
        printf("%d ", WeightArray[i]);
    int TotalNum = 2 * ElemNum - 1;//总结点数
    *HT = (HuffmanTree)malloc(sizeof(HTNode)*(TotalNum + 1));//0号单元弃用,动态分配数组存储赫夫曼树
    if (!*HT)exit(OVERFLOW);//分配失败
    HuffmanTree p = *HT;
    int i,S1,S2;
    for (i = 1; i <=ElemNum; ++i)
        (*HT)[i] = {WeightArray[i-1], 0, 0, 0 };//初始化赫夫曼树前ElemNum个结点
    for (i; i <= TotalNum; ++i)
        (*HT)[i] = { 0, 0, 0, 0 };//初始化后面的结点
    for (i = 0; i < ElemNum-1; ++i)//ElemNum需循环建树ElemNum-1次
    {
        SlectMin(i + ElemNum, &S1, &S2, *HT);//选出两个最小值S1,S2,其中S1的值小于S2的值
        //printf("\nTake %d %d ", S1, S2);
        (*HT)[S1].parent = (*HT)[S2].parent = i + ElemNum + 1;//i+ElemNum+1的值是父节点的下标
        (*HT)[i + ElemNum + 1].lchild = S1;
        (*HT)[i + ElemNum + 1].rchild = S2;
        (*HT)[i + ElemNum + 1].weight = (*HT)[S1].weight + (*HT)[S2].weight;
    }//for
    printf("\n---------------------Creat HuffmanTree OK !---------------------\n");
}//CreatHuffmanTree

void SlectMin(int i,int *S1,int *S2,HuffmanTree HT)
//从HuffmanTree中选出Parent为0,权值最小的两个数,分别将下标存放在S1和S2中,其中S1中存放的值<S2中存放的值
//i表示当前有效结点的下标
{
    int j;
    *S1 = *S2 = INT_MAX;
    for (j = 1; j <= i; ++j)//选出第一个最小值
    {
        if (HT[j].parent != 0)//父节点需为0
            continue;
        if (HT[*S1].weight > HT[j].weight)
            *S1 = j;
    }//for
    for (j = 1; j <= i; ++j)//选出第二个最小值
    {
        if (HT[j].parent != 0)//父节点需为0
            continue;
        if (j == *S1)//不能选刚选过的
            continue;
        if (HT[*S2].weight > HT[j].weight)
            *S2 = j;
    }//for
}//SlectMin

void HuffmanCoding_FromRoot(HuffmanTree HT,HuffmanCode *HC,int ElemNum)
//从头结点开始遍历,求出n个字符的赫夫曼编码HC
{
    *HC = (HuffmanCode)malloc(sizeof(char *)*(ElemNum + 1));
    if (!(*HC))exit(OVERFLOW);
    char *buffer = (char *)malloc(sizeof(char)*ElemNum);//分配编码缓冲区大小
    if (!buffer)exit(OVERFLOW);
    int CodeNum = 2 * ElemNum - 1;//正在访问结点的下标
    int CodeLen = 0;//编码长度
    for (int i = 1; i <= CodeNum; ++i) HT[i].weight = 0;//遍历赫夫曼树时用作结点状态标志(相当于初始化访问次数)
    while (CodeNum)//访问到根结点的父节点即0,说明遍历完该树
    {
        if (HT[CodeNum].weight == 0)//还没被访问过
        {
            HT[CodeNum].weight = 1;//标记访问一次
            if (HT[CodeNum].lchild != 0)//有左子树,访问它的左子树
            {
                CodeNum = HT[CodeNum].lchild;
                buffer[CodeLen++] = ‘0‘;//向左访问,编码为0
            }//if
            else if (HT[CodeNum].rchild == 0)//左子树右子树都为0,说明它是叶子结点
            {
                buffer[CodeLen] = ‘\0‘;
                (*HC)[CodeNum] = (char *)malloc(sizeof(char)*(CodeLen + 1));
                if (!(*HC)[CodeNum])exit(OVERFLOW);//分配存储空间失败
                strcpy((*HC)[CodeNum], buffer);//将编码拷贝
            }//else if
        }//if
        else if (HT[CodeNum].weight==1)//被访问过一次,即该结点左子树被访问过,接下来访问它的右子树
        {
            HT[CodeNum].weight = 2;//标记访问2次
            if (HT[CodeNum].rchild != 0)//有右子树,访问它的右子树
            {
                CodeNum = HT[CodeNum].rchild;
                buffer[CodeLen++] = ‘1‘;//向右访问,编码为1
            }//if
        }//else if
        else//被访问过2次,即左子树右子树都被访问过,回溯
        {
            --CodeLen;
            CodeNum = HT[CodeNum].parent;
        }//else
    }//while
}//HuffmanCoding

void Decode(HuffmanTree HT,int ElemNum)
//输入哈夫曼编码,解码
{
    int i = 2*ElemNum-1;
    char buffer[20];
    fflush(stdin);
    printf("Enter the huffmanCode  : ");
    gets(buffer);
    int j = 0;
    while (buffer[j]!=‘\0‘)
    {
        if (buffer[j]==‘0‘)
            i = HT[i].lchild;
        else i = HT[i].rchild;
        ++j;
    }//while
    printf("The num is %d", HT[i].weight);
}//Decode

原文地址:https://www.cnblogs.com/rainbow-/p/9594941.html

时间: 2024-10-20 15:13:30

从头结点开始编码的赫夫曼树的相关文章

【数据结构】赫夫曼树的实现和模拟压缩(C++)

赫夫曼(Huffman)树,由发明它的人物命名,又称最优树,是一类带权路径最短的二叉树,主要用于数据压缩传输. 赫夫曼树的构造过程相对比较简单,要理解赫夫曼数,要先了解赫夫曼编码. 对一组出现频率不同的字符进行01编码,如果设计等长的编码方法,不会出现混淆的方法,根据规定长度的编码进行翻译,有且只有一个字符与之对应.比如设计两位编码的方法,A,B,C,D字符可以用00-11来表示,接收方只要依次取两位编码进行翻译就可以得出原数据,但如果原数据只由n个A组成的,那发出的编码就是2n个0组成,这样的

赫夫曼树编码

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

赫夫曼树的构建、编码、译码解析

当你開始看这篇博文的时候.我相信你对树及二叉树的基本概念已有所了解.我在这里就不再赘述. 我们主要对赫 夫曼树的特点.构建.编码.译码做一个具体的介绍,并附有代码,全部函数代码都通过了測试.我不保证全部代码是最优的(毕竟是我一个人苦思冥想出来的,我相信在大家的集思广益之下还有优化的空间),但我保证全部代码是正确的. 一.赫夫曼树的特点 赫夫曼树又称作最优二叉树,是一类带权路径长度最短的树. 首先给出路径和路径长度的概念.从树中一个节点到 还有一个节点之间的分支构成这两个节点之间的路径.路径上的分

赫夫曼树编码的表示与实现--自己写数据结构

头文件huffman.h #ifndef _HUFFMAN_H_ #define _HUFFMAN_H_ #define MAX_WEIGHT 10000 typedef struct _HTNode { int weight; int parent,lchild,rchild; char data; }HTNode,*pHTNode; typedef char** huffmancode; void select_min_weight(HTNode* btree,int mn,int* s1,

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

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

赫夫曼树编码解码实例(C)

//HuffmanTree.h #include <stdlib.h> #include <stdio.h> #include <string.h> #define OVERFLOW -1 typedef struct{ char data; //节点所存字符 unsigned int weight; //节点权重 unsigned int parent,lchild,rchild; }HTNode, *HuffmanTree; //动态分配数组存储赫夫曼树 typed

赫夫曼树JAVA实现及分析

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

13.赫夫曼树及其应用

一.赫夫曼树定义与原理 1.路径长度:从树中一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称作路径的长度; 2.树的路径长度:即从树根到每一结点的路径长度之和; 3.结点的带权的路径长度:即从该结点从到树根之间的路径长度与结点上权的乘积; 4.树的带权路径长度:为树中所有叶子结点的带权路径长度之和; 5.赫夫曼树定义:假设有n个权值{w1,w2,....,wn},构造一颗有n个叶子结点的二叉树,每个叶子结点带权wk,每个叶子的路径长度为lk,则其中带权路径长度WPL最小的

赫夫曼树(最优二叉树)

.在选择最小s1s2的时候少了一个空语句分号..调试了好久..坑爹. 这个是最优的编码策略能达到最少的编码 1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<math.h> 5 #include<queue> 6 #include<algorithm> 7 using namespace std; 8 typedef struct 9 {