1.C语言实现

1.1代码说明

a  创建双向链表:

在创建哈夫曼树的过程中,需要不断对结点进行更改和删除,所以选用双向链表的结构更容易

'''C
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
 
 
//哈夫曼树结构体,数据域存储字符及其权重
typedef struct node
{
    char c;
    int weight;
    struct node *lchild, *rchild;
}Huffman, *Tree;
 
 
//双向链表结构体,数据域存储哈夫曼树结点
typedef struct list
{
    Tree root;
    struct list *pre;
    struct list *next;
}List, *pList;
 
 
//创建双向链表,返回头结点指针
pList creatList()
{
    pList head = (pList)malloc(sizeof(List));
 
    pList temp1 = head;
    pList temp2 = (pList)malloc(sizeof(List));
    temp1->pre = NULL;
    temp1->next = temp2;
    temp1->root = (Tree)malloc(sizeof(Huffman));
    temp1->root->c = 'a';
    temp1->root->weight = 22;
    temp1->root->lchild = NULL;
    temp1->root->rchild = NULL;
    
 
    temp2->pre = temp1;
    temp1 = temp2;
    temp2 = (pList)malloc(sizeof(List));
    temp1->next = temp2;
    temp1->root = (Tree)malloc(sizeof(Huffman));
    temp1->root->c = 'b';
    temp1->root->weight = 5;
    temp1->root->lchild = NULL;
    temp1->root->rchild = NULL;
    
 
    temp2->pre = temp1;
    temp1 = temp2;
    temp2 = (pList)malloc(sizeof(List));
    temp1->next = temp2;
    temp1->root = (Tree)malloc(sizeof(Huffman));
    temp1->root->c = 'c';
    temp1->root->weight = 38;
    temp1->root->lchild = NULL;
    temp1->root->rchild = NULL;
 
    temp2->pre = temp1;
    temp1 = temp2;
    temp2 = (pList)malloc(sizeof(List));
    temp1->next = temp2;
    temp1->root = (Tree)malloc(sizeof(Huffman));
    temp1->root->c = 'd';
    temp1->root->weight = 9;
    temp1->root->lchild = NULL;
    temp1->root->rchild = NULL;
 
    temp2->pre = temp1;
    temp1 = temp2;
    temp2 = (pList)malloc(sizeof(List));
    temp1->next = temp2;
    temp1->root = (Tree)malloc(sizeof(Huffman));
    temp1->root->c = 'e';
    temp1->root->weight = 44;
    temp1->root->lchild = NULL;
    temp1->root->rchild = NULL;
 
    temp2->pre = temp1;
    temp1 = temp2;
    temp2 = (pList)malloc(sizeof(List));
    temp1->next = temp2;
    temp1->root = (Tree)malloc(sizeof(Huffman));
    temp1->root->c = 'f';
    temp1->root->weight = 12;
    temp1->root->lchild = NULL;
    temp1->root->rchild = NULL;
 
    temp2->pre = temp1;
    temp1 = temp2;
    temp1->next = NULL;
    temp1->root = (Tree)malloc(sizeof(Huffman));
    temp1->root->c = 'g';
    temp1->root->weight = 65;
    temp1->root->lchild = NULL;
    temp1->root->rchild = NULL;
 
    return head;                          
}

b创建栈结构:

解码过程需要用到两个栈,一个用来存放树结点,一个用来存放码0和1

'''C
#define STACK_INIT_SIZE 100   //栈初始开辟空间大小
#define STACK_INCREMENT 10    //栈追加空间大小
 
//字符栈结构体,存放编码'0'和'1'
typedef struct {
    char *base;
    char *top;
    int size;
}charStack;
 
 
//栈初始化
charStack charStackInit()
{
    charStack s;
    s.base = (char *)malloc(sizeof(char)*STACK_INIT_SIZE);
    s.top = s.base;
    s.size = STACK_INIT_SIZE;
    return s;
}
 
//入栈
void charPush(charStack *s, char e)
{
    if(s->top - s->base >= s->size)
    {
        s->size  = STACK_INCREMENT;
        s->base = realloc(s->base, sizeof(char)*s->size);
    }
    *s->top = e;
    s->top  ;
}
 
//出栈
char charPop(charStack *s)
{
    if(s->top != s->base)
    {
        s->top--;
        return *s->top;
    }
    return -1;
}
 
//得到栈顶元素,但不出栈
char charGetTop(charStack *s)
{
    s->top--;
    char temp = *s->top;
    s->top  ;
    return temp;
}
 
//栈结构体,存放哈夫曼树结点
typedef struct 
{
    Huffman *base;
    Huffman *top;
    int size;
}BiStack;
 
//栈初始化
BiStack stackInit()
{
    BiStack s;
    s.base = (Huffman *)malloc(sizeof(Huffman)*STACK_INIT_SIZE);
    s.top = s.base;
    s.size =STACK_INIT_SIZE;
    return s;
}
 
//入栈
void push(BiStack *s, Huffman e)
{
    if(s->top - s->base >= s->size)
    {
        s->size  = STACK_INCREMENT;
        s->base = (Huffman *)realloc(s->base, sizeof(Huffman)*s->size);
    }
    *s->top = e;
    s->top  ;
}
 
//出栈
Huffman pop(BiStack *s)
{
    Huffman temp;
    s->top--;
    temp = *s->top;
    return temp;
}
 
//得到栈顶元素,但不出栈
Huffman getTop(BiStack s)
{
    Huffman temp;
    s.top--;
    temp = *s.top;
    return temp;
}
 
char stack[7][10];             //记录a~g的编码
//遍历栈,得到字符c的编码
void traverseStack(charStack s, char c)
{
    int index = c - 'a'; 
    int i = 0;
    while(s.base != s.top)
    {
        stack[index][i] = *s.base;
        i  ;
        s.base  ;
    }
}

c 创建哈夫曼树:

'''C
//通过双向链表创建哈夫曼树,返回根结点指针
Tree creatHuffman(pList head)
{
    pList list1 = NULL;
    pList list2 = NULL;
    pList index = NULL;
    Tree root = NULL;
    while(head->next != NULL)   //链表只剩一个结点时循环结束,此结点数据域即为哈夫曼树的根结点
    {
        list1 = head;
        list2 = head->next;
        index = list2->next;
        root = (Tree)malloc(sizeof(Huffman));
        while(index != NULL)    //找到链表中权重最小的两个结点list1,list2
        {
            if(list1->root->weight > index->root->weight || list2->root->weight > index->root->weight)
            {
                if(list1->root->weight > list2->root->weight) list1 = index;
                else list2 = index;
            }
            index = index->next;
        }
        //list1和list2设为新结点的左右孩子
        if(list2->root->weight > list1->root->weight)
        {
            root->lchild = list1->root;
            root->rchild = list2->root;
        }
        else
        {
            root->lchild = list2->root;
            root->rchild = list1->root;
        }
        //新结点字符统一设为空格,权重设为list1与list2权重之和
        root->c = ' ';
        root->weight = list1->root->weight   list2->root->weight;
        //list1数据域替换成新结点,并删除list2
        list1->root = root;
        list2->pre->next = list2->next;
        if(list2->next != NULL)
            list2->next->pre = list2->pre;    
    }
    return head->root;
}

d编码:

'''C
char stack[7][10];             //记录a~g的编码
//遍历栈,得到字符c的编码
void traverseStack(charStack s, char c)
{
    int index = c - 'a'; 
    int i = 0;
    while(s.base != s.top)
    {
        stack[index][i] = *s.base;
        i  ;
        s.base  ;
    }
}
 
 
//通过哈夫曼树编码
void encodeHuffman(Tree T)
{  
    BiStack bs = stackInit();
    charStack cs = charStackInit();
    Huffman root = *T;  
    Tree temp = NULL;
    push(&bs, root);      //根结点入栈
    while(bs.top != bs.base)      //栈空表示遍历结束
    {
        root = getTop(bs);
        temp = root.lchild;       //先访问左孩子
        while(temp != NULL)       //左孩子不为空
        {
            //将结点左孩子设为空,代表已访问其左孩子
            root.lchild = NULL;
            pop(&bs);            
            push(&bs, root);
            //左孩子入栈
            root = *temp;
            temp = root.lchild;
            push(&bs, root);
            //'0'入字符栈
            charPush(&cs, '0');
        }
        temp = root.rchild;     //后访问右孩子     
        while(temp == NULL)     //右孩子为空,代表左右孩子均已访问,结点可以出栈 
        {
            //结点出栈
            root = pop(&bs);
            //寻到叶子结点,可以得到结点中字符的编码
            if(root.c != ' ')
                traverseStack(cs, root.c);
            charPop(&cs);       //字符栈出栈
            if(bs.top == bs.base) break;    //根结点出栈,遍历结束
            //查看上一级结点是否访问完左右孩子  
            root = getTop(bs);
            temp = root.rchild;           
        }
        if(bs.top != bs.base)
        {
            //将结点右孩子设为空,代表已访问其右孩子
            root.rchild = NULL;       
            pop(&bs);
            push(&bs, root);
            //右孩子入栈
            root = *temp;      
            push(&bs, root);
            //'1'入字符栈
            charPush(&cs, '1');
        }    
    }
}

e解码:

'''C
char decode[100];   //记录解码得到的字符串
//通过哈夫曼树解码
void decodeHuffman(Tree T, char *code)
{
    int cnt = 0;
    Tree root;
    while(*code != '\0')                  //01编码字符串读完,解码结束
    {
        root = T;
        while(root->lchild != NULL)       //找到叶子结点
        {
            if(*code != '\0')
            {
                if(*code == '0')
                    root = root->lchild;
                else
                    root = root->rchild;
                code  ;
            }
            else break;
        }
        decode[cnt] = root->c;             //叶子结点存放的字符即为解码得到的字符
        cnt  ;
    }
}

f主函数:

'''C
void main()
{
    pList pl = creatList();
    printf("字符的权重如下\n");
    for(pList l = pl; l->next != NULL; l = l->next)
        printf("字符%c的权重是 %d\n", l->root->c, l->root->weight);
    Tree T = creatHuffman(pl);
    encodeHuffman(T);
    printf("\n\n字符编码结果如下\n");
    for(int i = 0; i < 7; i  )
        printf("%c : %s\n", i 'a', stack[i]);
    char code[100];
    printf("\n\n请输入编码:\n");
    scanf("%s", code);
    printf("解码结果如下:\n");
    decodeHuffman(T, code);
    printf("%s\n", decode);
    printf("\n\n");
    system("date /T");
    system("TIME /T");
    system("pause");
    exit(0); 
}

1.2运行结果

2.Python实现

2.1代码说明

a创建哈夫曼树:

#coding=gbk
 
import datetime
import time
from pip._vendor.distlib.compat import raw_input
 
#哈夫曼树结点类
class Huffman:
    def __init__(self, c, weight):
        self.c = c
        self.weight = weight
        self.lchild = None
        self.rchild = None
    
    #创建结点左右孩子    
    def creat(self, lchild, rchild):
        self.lchild = lchild
        self.rchild = rchild
 
#创建列表        
def creatList():
    list = []
    list.append(Huffman('a', 22))
    list.append(Huffman('b', 5))
    list.append(Huffman('c', 38))
    list.append(Huffman('d', 9))
    list.append(Huffman('e', 44))
    list.append(Huffman('f', 12))
    list.append(Huffman('g', 65))
    return list
 
#通过列表创建哈夫曼树,返回树的根结点
def creatHuffman(list):
    while len(list) > 1:               #列表只剩一个结点时循环结束,此结点即为哈夫曼树的根结点
        i = 0
        j = 1
        k = 2
        while k < len(list):           #找到列表中权重最小的两个结点list1,list2          
            if list[i].weight > list[k].weight or list[j].weight > list[k].weight:
                if list[i].weight > list[j].weight:
                    i = k
                else:
                    j = k
            k  = 1       
        root = Huffman(' ', list[i].weight   list[j].weight) #新结点字符统一设为空格,权重设为list1与list2权重之和   
        if list[i].weight < list[j].weight:                  #list1和list2设为新结点的左右孩子
            root.creat(list[i], list[j])
        else:
            root.creat(list[j], list[i])
        #list1数据域替换成新结点,并删除list2
        list[i] = root
        list.remove(list[j])
    return list[0]

b编码:

#通过哈夫曼树编码
def encodeHuffman(T):
    code = [[], [], [], [], [], [], []]
    #列表实现栈结构
    treeStack = []
    codeStack = []
    treeStack.append(T)
    while treeStack != []:        #栈空代表遍历结束
        root = treeStack[-1]
        temp = root.lchild
        while temp != None:
            #将结点左孩子设为空,代表已访问其左孩子
            root.lchild = None        
            #左孩子入栈          
            treeStack.append(temp)         
            root = temp
            temp = root.lchild
            #0入编码栈
            codeStack.append(0)
        temp = root.rchild            #后访问右孩子
        while temp == None:           #右孩子为空,代表左右孩子均已访问,结点可以出栈
            root = treeStack.pop()           #结点出栈
            #寻到叶子结点,可以得到结点中字符的编码
            if root.c != ' ':
                codeTemp = codeStack.copy()
                code[ord(root.c) - 97] = codeTemp     
            if treeStack == []:    #根结点出栈,遍历结束
                break
            codeStack.pop()        #编码栈出栈
            #查看上一级结点是否访问完左右孩子
            root = treeStack[-1]
            temp = root.rchild
        if treeStack != []:
            treeStack.append(temp)     #右孩子入栈
            root.rchild = None         #将结点右孩子设为空,代表已访问其右孩子
            codeStack.append(1)        #1入编码栈
    return code 

c解码:

#通过哈夫曼树解码
def decodeHuffman(T, strCode):
    decode = []
    index = 0
    while index < len(strCode):        #01编码字符串读完,解码结束
        root = T
        while root.lchild != None:     #找到叶子结点
            if index < len(strCode):
                if strCode[index] == '0':
                    root = root.lchild
                else:
                    root = root.rchild
                index  = 1
            else:
                break
        decode.append(root.c)           #叶子结点存放的字符即为解码得到的字符
    return decode

d主函数:

if __name__ == '__main__':
    list = creatList()
    print("字符的权重如下")
    for i in range(len(list)):
        print("字符{}的权重为: {}".format(chr(i 97), list[i].weight))
    T = creatHuffman(list)
    code = encodeHuffman(T)
    print("\n字符编码结果如下")
    for i in range(len(code)):
        print(chr(i 97), end=' : ')
        for j in range(len(code[i])):
            print(code[i][j], end='')
        print("")
    strCode = input("\n请输入编码:\n")
    #哈夫曼树在编码时被破坏,必须重建哈夫曼树
    list = creatList()
    T = creatHuffman(list)
    decode = decodeHuffman(T, strCode)
    print("解码结果如下:")
    for i in range(len(decode)):
        print(decode[i], end='')
    print("\n\n")
    datetime = datetime.datetime.now()
    print(datetime.strftime("%Y-%m-%d\n%H:%M:%S"))
    input("Press Enter to exit…") 

2.2运行结果

以上就是利用Python和C语言分别实现哈夫曼编码的详细内容,更多关于Python哈夫曼编码的资料请关注Devmax其它相关文章!

利用Python和C语言分别实现哈夫曼编码的更多相关文章

  1. XCode 3.2 Ruby和Python模板

    在xcode3.2下,我的ObjectiveCPython/Ruby项目仍然可以打开更新和编译,但是你无法创建新项目.鉴于xcode3.2中缺少ruby和python的所有痕迹(即创建项目并添加新的ruby/python文件),是否有一种简单的方法可以再次安装模板?我发现了一些关于将它们复制到某个文件夹的信息,但我似乎无法让它工作,我怀疑文件夹的位置已经改变为3.2.解决方法3.2中的应用程序模板

  2. 开始使用 swift 的 c语言 库

    为了手头上的一个项目,我需要使用CommonCrypto库中的HMAC函数.虽然苹果在swift中已经提供了许多系统库,但是CommonCrypto不在其中.庆幸的是,要使用这个库并不怎么费事,只需要做一点额外的工作.开始访问库在使用库之前,我们需要通知Swift编译器.要完成这个过程,我们有两种方式.它们都能在示例工程中正常运行,但是你应该根据你代码的用途来选择具体的方式.好消息是,你随便使用那

  3. Swift教程10-运算符与C语言的不同

    =,==这些运算符和其他语言的类似,是比较前后两个值是否相等,或者大小关系比较字符串内容是否相等,使用==即可但是Swift新增了===恒等于,是针对于引用类型,如两个对象之间是否是同一个对象与之对应的是!运算符示例Swift新增的??

  4. Swift 体会

    前言Swift体会我不算是一个果粉,但是我很喜欢苹果的产品,甚至可以说是狂热。运行速度从苹果官方所给出的数据来看,Objective-C比Python快2.8倍,而Swift比Python快3.9倍,可见苹果在Swift上下了大量的功夫进行优化。开发环境Swift语言的开发环境是苹果公司提供的集成开发环境Xcode,可以用来开发iOS应用、iOS游戏、OSX窗体程序、OSX游戏、OSX命令行程序,读者可以直接从AppStore中搜索并下载。由于Swift是苹果的产品,所以目前只支持苹果的系统。

  5. [翻译]Swift编程语言——关于Swift

    Swift是一门用于iOS和OSX应用开发的新的编程语言,它以C和Objective-C语言为基础,但没有C语言的兼容性约束。Swift的酝酿花费了数年。Apple为了Swift改进了已有的编译器、调试器和框架的底层。对于Objective-C语言的开发者,Swift是那样的似曾相识。在这个基础之上,Swift引入了许多新的特性并且支持面向对象编程。Swift将现代编程语言的精华和苹果工程文化中的智慧结合在一起。所有这些使得Swift对于开发者和Apple都是一笔对未来可靠的投资。

  6. swift笔记-赋值运算符

    复杂些的运算例如逻辑与运算符&&,或让i值加1的便捷自增运算符++i等。Swift支持大部分标准C语言的运算符,且改进许多特性来减少常规编码错误。当然允许你使用Swift的溢出运算符来实现溢出。本章节只描述了Swift中的基本运算符,高级运算符包含了高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。三元运算符操作三个操作对象,和C语言一样,Swift只有一个三元运算符,就是三目运算符(a?

  7. Swift基本使用-函数和闭包(三)

    声明函数和其他脚本语言有相似的地方,比较明显的地方是声明函数的关键字swift也出现了Python中的组元,可以通过一个组元返回多个值。传递可变参数,函数以数组的形式获取参数swift中函数可以嵌套,被嵌套的函数可以访问外部函数的变量。可以通过函数的潜逃来重构过长或者太复杂的函数。

  8. runTime(二)

    我们前面已经讲过一篇runtime原理,现在这篇文章主要介绍的是runtime是什么以及怎么用!首先,第一个问题,1》runtime实现的机制是什么,怎么用,一般用于干嘛?在我们平时编写的OC代码中,程序运行过程时,其实最终都是转成了runtime的C语言代码,runtime算是OC的幕后工作者比如说,下面一个创建对象的方法中,举例:OC:第二个问题runtime用来干什么呢??..这是我们学习runtime必须知道的函数!

  9. Swift:基本概述

    在介绍Swift之前,先说一段小插曲。Swift中文被翻译为“雨燕”。swift语言是苹果2014年6月3日正式推出一门新的的语言。),大家也许会困惑了,我不是在介绍Swift的使用吗?更容易让很多初学者愿意往Swift方面发展。并且它尽可能的保持方法名类名与objective-c中的一致,这也使得一些长期从事objective-c开发的程序员,很方便的转向Swift的开发。

  10. Swift学习笔记九——整型Int在Swift中表示的最大值最小值问题

    我们在学习C语言的时候,总是会去记忆一些数值,如int能表示的最大值最小值,long型能表示的最大值最小值。来到Swift中就比较简单了,直接用代码就可以看到类型所能表示的最值。。如图所示,Int8表示占一个字节,Int16表示占两个字节,以此类推。妈妈再也不用担心我记忆这些麻烦的数据了。

随机推荐

  1. 10 个Python中Pip的使用技巧分享

    众所周知,pip 可以安装、更新、卸载 Python 的第三方库,非常方便。本文小编为大家总结了Python中Pip的使用技巧,需要的可以参考一下

  2. python数学建模之三大模型与十大常用算法详情

    这篇文章主要介绍了python数学建模之三大模型与十大常用算法详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感想取得小伙伴可以参考一下

  3. Python爬取奶茶店数据分析哪家最好喝以及性价比

    这篇文章主要介绍了用Python告诉你奶茶哪家最好喝性价比最高,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

  4. 使用pyinstaller打包.exe文件的详细教程

    PyInstaller是一个跨平台的Python应用打包工具,能够把 Python 脚本及其所在的 Python 解释器打包成可执行文件,下面这篇文章主要给大家介绍了关于使用pyinstaller打包.exe文件的相关资料,需要的朋友可以参考下

  5. 基于Python实现射击小游戏的制作

    这篇文章主要介绍了如何利用Python制作一个自己专属的第一人称射击小游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手试一试

  6. Python list append方法之给列表追加元素

    这篇文章主要介绍了Python list append方法如何给列表追加元素,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  7. Pytest+Request+Allure+Jenkins实现接口自动化

    这篇文章介绍了Pytest+Request+Allure+Jenkins实现接口自动化的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  8. 利用python实现简单的情感分析实例教程

    商品评论挖掘、电影推荐、股市预测……情感分析大有用武之地,下面这篇文章主要给大家介绍了关于利用python实现简单的情感分析的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

  9. 利用Python上传日志并监控告警的方法详解

    这篇文章将详细为大家介绍如何通过阿里云日志服务搭建一套通过Python上传日志、配置日志告警的监控服务,感兴趣的小伙伴可以了解一下

  10. Pycharm中运行程序在Python console中执行,不是直接Run问题

    这篇文章主要介绍了Pycharm中运行程序在Python console中执行,不是直接Run问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

返回
顶部