哈尔曼树c语言

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <limits.h>


// 最大权值,用于初始化

#define MAX_WEIGHT INT_MAX


// --- 1. 数据结构定义 ---

// 哈夫曼树结点结构体

typedef struct {

    int weight;        // 结点的权值

    int parent, lchild, rchild; // 双亲、左孩子、右孩子的下标

} HTNode, *HuffmanTree;


// 哈夫曼编码表类型(字符指针数组)

typedef char **HuffmanCode;



// --- 2. 辅助函数 Select ---

// 在 HT[1...k] 范围内,找出 parent 为 0 且权值最小的两个结点,用 s1 和 s2 返回其下标

void Select(HuffmanTree HT, int k, int *s1, int *s2) {

    int min1 = MAX_WEIGHT, min2 = MAX_WEIGHT; // 初始化为最大值

    *s1 = 0;

    *s2 = 0;


    for (int i = 1; i <= k; i++) {

        // 只考虑尚未加入树的结点 (parent为0)

        if (HT[i].parent == 0) {

            if (HT[i].weight < min1) {

                // 如果当前结点权值小于 min1,则更新 min1 和 min2

                min2 = min1;

                *s2 = *s1;

                min1 = HT[i].weight;

                *s1 = i;

            } else if (HT[i].weight < min2) {

                // 如果当前结点权值介于 min1 和 min2 之间,则更新 min2

                min2 = HT[i].weight;

                *s2 = i;

            }

        }

    }

}



// --- 3. 核心函数:构造哈夫曼树 ---

// w 存放 n 个权值,构造哈夫曼树 HT

void CreateHuffmanTree(HuffmanTree *HT, int *w, int n) {

    if (n <= 1) return;


    int m = 2 * n - 1; // 哈夫曼树总结点数

    *HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); // 0号单元未用,分配 m+1 个空间

    if (!*HT) {

        fprintf(stderr, "内存分配失败!\n");

        exit(EXIT_FAILURE);

    }


    // 初始化所有结点的双亲、左右孩子下标为0

    for (int i = 1; i <= m; i++) {

        (*HT)[i].parent = 0;

        (*HT)[i].lchild = 0;

        (*HT)[i].rchild = 0;

    }


    // 输入前 n 个结点的权值

    for (int i = 1; i <= n; i++) {

        (*HT)[i].weight = w[i - 1]; // w数组从0开始,HT从1开始

    }


    // --- 开始创建哈夫曼树 ---

    printf("\n--- 构造哈夫曼树过程 ---\n");

    for (int i = n + 1; i <= m; i++) {

        int s1, s2;

        // 在 HT[1...i-1] 中选择两个权值最小的结点

        Select(*HT, i - 1, &s1, &s2);

        printf("第 %2d 次合并: 选择权值 %d (结点%d) 和 %d (结点%d)\n", i - n, (*HT)[s1].weight, s1, (*HT)[s2].weight, s2);


        // 将新结点 i 的双亲设为 s1, s2

        (*HT)[s1].parent = i;

        (*HT)[s2].parent = i;

        // s1, s2 分别作为 i 的左右孩子

        (*HT)[i].lchild = s1;

        (*HT)[i].rchild = s2;

        // i 的权值为 s1, s2 权值之和

        (*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight;

    }

    printf("--- 哈夫曼树构造完成 ---\n\n");

}



// --- 4. 核心函数:生成哈夫曼编码 ---

// 从哈夫曼树 HT 反向生成哈夫曼编码 HC

void HuffmanCoding(HuffmanTree HT, HuffmanCode *HC, int n) {

    *HC = (HuffmanCode)malloc((n + 1) * sizeof(char *)); // 分配 n 个字符编码的头指针

    if (!*HC) {

        fprintf(stderr, "内存分配失败!\n");

        exit(EXIT_FAILURE);

    }

   

    char *cd = (char *)malloc(n * sizeof(char)); // 分配临时存放编码的动态数组

    if (!cd) {

        fprintf(stderr, "内存分配失败!\n");

        exit(EXIT_FAILURE);

    }

    cd[n - 1] = '\0'; // 编码结束符


    // 逐个字符求哈夫曼编码

    for (int i = 1; i <= n; i++) {

        int start = n - 1; // start 指向编码结束符

        int c = i;

        int f = HT[c].parent;


        // 从叶子结点开始向上回溯,直到根结点

        while (f != 0) {

            --start; // 回溯一次,start向前指一个位置

            if (HT[f].lchild == c) {

                cd[start] = '0'; // 结点c是f的左孩子,则生成代码'0'

            } else {

                cd[start] = '1'; // 结点c是f的右孩子,则生成代码'1'

            }

            c = f;

            f = HT[f].parent; // 继续向上回溯

        }


        // 为第 i 个字符编码分配空间

        (*HC)[i] = (char *)malloc((n - start) * sizeof(char));

        if (!(*HC)[i]) {

            fprintf(stderr, "内存分配失败!\n");

            exit(EXIT_FAILURE);

        }

        // 将求得的编码从临时空间 cd 复制到 HC 的当前行

        strcpy((*HC)[i], &cd[start]);

    }


    free(cd); // 释放临时空间

}



// --- 5. 打印函数 ---

void PrintHuffmanCode(HuffmanCode HC, int *w, int n) {

    printf("--- 哈夫曼编码结果 ---\n");

    printf("权值\t编码\n");

    printf("--------------------\n");

    for (int i = 1; i <= n; i++) {

        printf("%d\t%s\n", w[i - 1], HC[i]);

    }

    printf("--------------------\n");

}



// --- 6. 主函数 ---

int main() {

    int n = 8;

    int w[] = {5, 29, 7, 8, 14, 23, 3, 11}; // 【例5.2】的权值


    HuffmanTree HT = NULL;

    HuffmanCode HC = NULL;


    // 1. 构造哈夫曼树

    CreateHuffmanTree(&HT, w, n);


    // 2. 生成哈夫曼编码

    HuffmanCoding(HT, &HC, n);


    // 3. 打印编码结果

    PrintHuffmanCode(HC, w, n);


    // 4. 释放内存

    for (int i = 1; i <= n; i++) {

        free(HC[i]);

    }

    free(HC);

    free(HT);


    return 0;

}

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容