哈夫曼树的构建(C语言)

算法思路

主要包括两部分算法,一个是在数组中找到权值最小、且无父结点两个结点位置,因为只有无父结点才能继续组成树; ​ 另一个就是根据这两个结点来修改相关结点值。

  1. 结构定义和头文件

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

    #define OVERFLOW -1

    typedef struct {
    int weight;//结点权值
    int lchild, rchild, parent;//结点左、右孩子、父结点
    }HNode,*HTree;
  2. 在数组中找到目前权值最小的两个结点 由于哈夫曼树规定结点左子树权值小于右子树,所以我这里把权值较小的那个结点位置赋给p1

    这部分我先找到前两个无父结点的结点位置赋给p1和p2,再继续遍历之后的与当前的p1和p2位置的结点权值比较

    • 若结点有父结点,直接跳过

    • 若结点无父结点,且权值小于p1,则将该位置赋给p1,令p2等于之前的p1

    • 若结点无父结点,且权值大于p1、小于p2,则将该位置赋给p2

      void selectMin(HTree HT,int length, int* p1, int* p2) {//搜索当前数组中无父结点的权值最小的两个结点的下标
    int i = ;//数组下标从1开始,0不用

    while (HT[i].parent!= && i <= length)//遍历到第一个无父结点的结点位置
    i++;
    *p1 = i; i++;
    while (HT[i].parent!= && i <= length)//遍历到第二个无父结点的结点位置
    i++;
    *p2 = i; i++;

    if (HT[*p1].weight > HT[*p2].weight) {//令p1始终指向较小权值的结点位置
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
    }

    for (int n = i; n <= length; n++) {//继续遍历,比较之后的无父结点的结点权值与p1、p2
    if (HT[n].parent != )//若该结点有父结点,直接跳过
    continue;
    else if (HT[n].weight < HT[*p1].weight) {//若该结点权值小于p1,令p1等于n,p2等于p1
    *p2 = *p1;
    *p1 = n;
    }
    else if (HT[n].weight > HT[*p1].weight&& HT[n].weight < HT[*p2].weight)//若该结点权值大于p1,小于p2,令*p2=n
    *p2 = n;
    }

    return;
    }
  3. 构建哈夫曼树

      void createHuffmanTree() {//构建哈夫曼树
    int lnode;//哈夫曼树叶子结点数
    printf("input leafnode number:");
    scanf_s("%d", &lnode);
    int length=*lnode-;//哈夫曼树结点数=2*叶子节点数-1

    HTree HT = (HTree)malloc(sizeof(HNode) * (length + ));//数组下标从1开始,所以分配(length+1)大小空间
    if (!HT) exit(OVERFLOW);
    memset(HT, , sizeof(HNode) * (length + ));//将数组内元素都初始化为0

    HTree p = HT;
    for (int i = lnode + ; i <=length; i++) {//把所有非叶子节点的结点权值规定为无穷大,否则会影响接下来选择结点最小值
    (p + i)->weight = ;
    }


    printf("input leafnode weight:");
    for (int i = ; i <= lnode; i++) {//输入叶子结点权值
    scanf_s("%d", &(p+i)->weight);
    }

    int p1, p2;
    for (int i = lnode+; i <= length; i++) {//从第一个非叶子结点开始遍历
    selectMin(p, length, &p1, &p2);
    (p + i)->lchild = p1;//修改左子树的值
    (p + i)->rchild = p2;//修改左子树的值
    (p + i)->weight = (p + p1)->weight + (p + p2)->weight;//修改权值
    (p + p1)->parent = i;//修改左子树的父结点值
    (p + p2)->parent = i;//修改右子树的父结点值
    }

    for (int i = ; i <= length; i++) {
    printf("%3d %3d %3d %3d %3d\n", i, (p + i)->weight, (p + i)->parent, (p + i)->lchild, (p + i)->rchild);//遍历输出
    }

    return;
    }
  4. 主函数及具体实例

      int main() {

    createHuffmanTree();
    return ;
    }

自我总结

写这部分时候动态数组分配和使用那里耗了点时间,主要原因还是不太熟以及vs的操作太迷了。经过这次训练又加深了一点理解,vs的调试也逐渐能够熟练使用了,还是挺开心的。

哈夫曼树的构建(C语言)的更多相关文章

  1. 哈夫曼树(一)之 C语言详解

    本章介绍哈夫曼树.和以往一样,本文会先对哈夫曼树的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现:实现的语言虽不同,但是原理如出一辙,选择其中之一进行了解即可.若 ...

  2. 【算法】赫夫曼树(Huffman)的构建和应用(编码、译码)

    参考资料 <算法(java)>                           — — Robert Sedgewick, Kevin Wayne <数据结构>       ...

  3. Android版数据结构与算法(七):赫夫曼树

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 近期忙着新版本的开发,此外正在回顾C语言,大部分时间没放在数据结构与算法的整理上,所以更新有点慢了,不过既然写了就肯定尽力将这部分完全整理好分享出 ...

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

    赫夫曼(Huffman)树,由发明它的人物命名,又称最优树,是一类带权路径最短的二叉树,主要用于数据压缩传输. 赫夫曼树的构造过程相对比较简单,要理解赫夫曼数,要先了解赫夫曼编码. 对一组出现频率不同 ...

  5. Python---哈夫曼树---Huffman Tree

    今天要讲的是天才哈夫曼的哈夫曼编码,这是树形数据结构的一个典型应用. !!!敲黑板!!!哈夫曼树的构建以及编码方式将是我们的学习重点. 老方式,代码+解释,手把手教你Python完成哈夫曼编码的全过程 ...

  6. 数据结构-哈夫曼树(python实现)

    好,前面我们介绍了一般二叉树.完全二叉树.满二叉树,这篇文章呢,我们要介绍的是哈夫曼树. 哈夫曼树也叫最优二叉树,与哈夫曼树相关的概念还有哈夫曼编码,这两者其实是相同的.哈夫曼编码是哈夫曼在1952年 ...

  7. 高级数据结构---赫(哈)夫曼树及java代码实现

    我们经常会用到文件压缩,压缩之后文件会变小,便于传输,使用的时候又将其解压出来.为什么压缩之后会变小,而且压缩和解压也不会出错.赫夫曼编码和赫夫曼树了解一下. 赫夫曼树: 它是一种的叶子结点带有权重的 ...

  8. Java实现WUST 1002: 哈夫曼树

    [问题描述] 根据给定的若干权值可以构造出一颗哈夫曼树.构造的哈夫曼树可能不唯一,但是按照下面的选取原则所构造出来的哈夫曼树应该是唯一的. (1)每次选取优先级最低的两个结点,优先级最低的作为左子树, ...

  9. C++ 漫谈哈夫曼树

    1. 前言 什么是哈夫曼树? 把权值不同的n个结点构造成一棵二叉树,如果此树满足以下几个条件: 此 n 个结点为二叉树的叶结点 . 权值较大的结点离根结点较近,权值较小的结点离根结点较远. 该树的带权 ...

随机推荐

  1. 深挖Jvm垃圾收集

    垃圾收集(Garbage Collection,GC),它的任务是解决以下 3 件问题: 哪些内存需要回收? 什么时候回收? 如何回收? 其中第一个问题很好回答,在 Java 中,GC 主要发生在 J ...

  2. 如何设计提高服务API的安全性(二)API密钥方式详解

    在上文已经讲述了基础介绍,这篇文章详细讲解API密钥方式. 利用何种加密方式呢? 经过上面加密算法的理解,单向加密不仅性能高,而且有压缩性,即长度一致,有效减少网络传输过程中的字节大小.适合我们这种调 ...

  3. PHP:CURL分别以GET、POST方式请求HTTPS协议接口api【转】

    1.curl以GET方式请求https协议接口 //注意:这里的$url已经包含参数了,不带参数你自己处理哦GET很简单 function curl_get_https($url){ $curl = ...

  4. MySQL服务的构成(二)

    一.什么是实例 这里的实例不是类产生的实例对象,而是Linux系统下的一种机制 1.MySQL的后台进程+线程+预分配的内存结构. 2.MySQL在启动的过程中会启动后台守护进程,并生成工作线程,预分 ...

  5. LCD驱动程序之层次分析

    1.回顾字符设备驱动程序: 字符设备驱动编写的一般步骤: 1)主设备号 2)构造file_operations结构体体 .open = xxxx .read = xxxxx 3)register_ch ...

  6. 怎么认Destsoon标签条件

    看准一个标签认条件 如: <!--{php $tags=tag("moduleid=18&table=club_group_18&condition=status=3 ...

  7. JMeter5.1开发http协议接口之json

    信息头指定是json 传json 包含传token,请参考:https://www.cnblogs.com/uncleyong/p/11668665.html

  8. Iptables不适用与socks协议吗?

    需求描述   现有一个台多公网IP服务器,用作于内网网关,通过NAT访问公网使用,要求不同的内网地址访问公网时使用不同的公网IP.可以简单理解为内网与公网IP进行一对一访问外网的映射. 服务器名称 I ...

  9. flask框架搭建项目的具体步骤

    flask是一个使用python编写的轻量级Web应用框架.与django不同,Django创建工程时,会直接构架好工程目录.而flask工程几乎是自己创建结构. 1.导入相关模块以及需要使用的模块: ...

  10. CPU中断的工作原理,从最底层讲起

    前言 中断的概念属于硬件层.虽然我们在进行软件编程时不会直接使用中断,但理解它对我们来说依然重要. 我们在使用线程切换及状态管理.异常处理.硬件与处理器的交互.I/O操作等指令时,中断都在默默的为我们 ...