哈夫曼树外加编码


```c
#include <conio.h>
#include <stdio.h>
#include <process.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <fstream>
#define max 100
#include <iostream>
using namespace std;
#define supermax  100000

struct BiTNode
{                  // 二叉树结点类型
   char symbol;
   int data;      // 数据
   int tem1, tem2; // 辅助数据(实习题不用)
   BiTNode *left;  // 左子树指针
   BiTNode *right; // 右子树指针
};

struct HuffmanCode {
    char character;
    char* code;
} ;


void getWidth1(BiTNode *Tree, int depth, int shift, char map[max*2][max*2])
{
	int i;

	if (Tree->left != NULL)
	{
		getWidth1(Tree->left, depth+1, shift, map);
		Tree->tem1 = Tree->left->tem1 + Tree->left->tem2 + 1;
		for (i=(Tree->left->tem1+shift)*2; i<shift*2; i=i+2)
		{
			map[depth*2+1][i]='-';
			map[depth*2+1][i+1]='-';
		}
	}
	else Tree->tem1 = 0;
	if (Tree->right != NULL)
	{
		getWidth1(Tree->right, depth+1, shift+Tree->tem1+1, map);
		Tree->tem2 = Tree->right->tem1 + Tree->right->tem2 + 1;
	}
	else Tree->tem2 = 0;

	for (i=shift*2; i<(Tree->tem1+shift)*2; i++)
		map[depth*2][i]=' ';
	
	map[depth*2][(Tree->tem1+shift)*2]=(char)(Tree->data / 1000 +48);
	map[depth*2][(Tree->tem1+shift)*2+1]=(char)(Tree->data / 100 % 10 +48);
	map[depth*2][(Tree->tem1+shift)*2+2]=(char)(Tree->data / 10 % 10 +48);
	map[depth*2][(Tree->tem1+shift)*2+3]=(char)(Tree->data %10 +48);
	if (Tree->data<1000)
	{
		map[depth*2][(Tree->tem1+shift)*2]=' ';
		if (Tree->data<100)
		{
			map[depth*2][(Tree->tem1+shift)*2+1]=map[depth*2][(Tree->tem1+shift)*2+2];
			map[depth*2][(Tree->tem1+shift)*2+2]=map[depth*2][(Tree->tem1+shift)*2+3];
			map[depth*2][(Tree->tem1+shift)*2+3]=' ';
			if (Tree->data<10)
				map[depth*2][(Tree->tem1+shift)*2+1]=' ';
		}
	}

	if (Tree->left != NULL)
	{
		map[depth*2+1][(Tree->left->tem1+shift)*2+1]=(char)0xa9;
		map[depth*2+1][(Tree->left->tem1+shift)*2+2]=(char)0xb0;
		map[depth*2+1][(Tree->tem1+shift)*2+1]=(char)0xa9;
		map[depth*2+1][(Tree->tem1+shift)*2+2]=(char)0xbc;
		for (i=(Tree->left->tem1+shift)*2+3; i<(Tree->tem1+shift)*2; i=i+2)
		{
			map[depth*2+1][i]=(char)0xa9;
			map[depth*2+1][i+1]=(char)0xa4;
		}
	}
	if (Tree->right != NULL)
	{
		map[depth*2+1][(Tree->tem1+shift)*2+1]=(char)0xa9;
		map[depth*2+1][(Tree->tem1+shift)*2+2]=(char)0xb8;
		map[depth*2+1][(Tree->tem1+Tree->right->tem1+shift)*2+3]=(char)0xa9;
		map[depth*2+1][(Tree->tem1+Tree->right->tem1+shift)*2+4]=(char)0xb4;
		for (i=(Tree->tem1+shift)*2+3; i<(Tree->tem1+Tree->right->tem1+shift)*2+2; i=i+2)
		{
			map[depth*2+1][i]=(char)0xa9;
			map[depth*2+1][i+1]=(char)0xa4;
		}
	}
	if (Tree->left != NULL && Tree->right != NULL)
	{
		map[depth*2+1][(Tree->tem1+shift)*2+1]=(char)0xa9;
		map[depth*2+1][(Tree->tem1+shift)*2+2]=(char)0xd8;
	}

}

//生成文件Map.txt,显示以Tree为根指针的二叉树
void showBinTree1(BiTNode *Tree)
{
	
	char map[max*2][max*2];
	ofstream out;
	int i,j,k;

	out.open("Map.txt");
	if (Tree == NULL)
	{
		out<<"空树";
		out.close();
		return;
	}
	for (i=0; i<max*2; i++)
		for (j=0; j<max*2; j++)
			map[i][j]=' ';
	getWidth1(Tree,0,0,map);
	for (i=0; i<max*2; i++)
	{
		k=max*2-1; 
		while (k>=0 && map[i][k]==' ')
			k--;

		for (j=0; j<=k; j++)
		    out<<map[i][j];	
		out<<"\n";
	}
	out.close();
}

BiTNode *createNode(int data, char symbol) {
    BiTNode* newNode = (BiTNode *)malloc(sizeof(BiTNode));
    newNode->data = data;
    newNode->symbol = symbol;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

//构建哈夫曼树
BiTNode *buildHuffmanTree(char symbols[], int frequencies[], int size) {
    // 创建叶子节点
    BiTNode** nodes = (BiTNode**)malloc(size * sizeof(BiTNode*));
    for (int i = 0; i < size; i++) {
        nodes[i] = createNode(frequencies[i], symbols[i]);
    }//这里要考,理论上有2n-1个节点

    // 构建哈夫曼树
    while (size > 1) {
        BiTNode *leftChild = NULL;
        BiTNode *rightChild = NULL;
        int minIndex1 = -1;
        int minIndex2 = -1;

        // 找到频率最小的两个节点
        for (int i = 0; i < size; i++) {
            if (minIndex1 == -1 || nodes[i]->data < nodes[minIndex1]->data) {
                minIndex2 = minIndex1;
                minIndex1 = i;
            }
            else if (minIndex2 == -1 || nodes[i]->data < nodes[minIndex2]->data) {
                minIndex2 = i;
            }
        }

        // 创建新节点作为它们的父节点
        leftChild = nodes[minIndex1];
        rightChild = nodes[minIndex2];
        BiTNode *parentNode = createNode(leftChild->data + rightChild->data, '\0');
        parentNode->left = leftChild;
        parentNode->right = rightChild;

		// 删除两个子节点
		

        //错误写法
        /*
            if (minIndex1 < minIndex2) {
                nodes[minIndex1] = parentNode;
                for (int i = minIndex2; i < size - 1; i++) {
                    nodes[i] = nodes[i + 1];
                }
            }
            
            else if(minIndex2 < minIndex1){
                
                nodes[minIndex2] = parentNode;
                int i = minIndex1;
                for (int i  = minIndex1; i < size-1; i++) {//在这里如果没有int i  = minIndex1或者int k = size,就会出现赋值错误
                    nodes[i] = nodes[i + 1];
                }
                
            }
        */
        int k = size;
        // 更新节点数组
        if (minIndex1 < minIndex2) {
            nodes[minIndex1] = parentNode;
            for (int i = minIndex2; i < k - 1; i++) {
                nodes[i] = nodes[i + 1];
            }
        }
        
        else if(minIndex2 < minIndex1){//交换nodes里边的位置从大到小,并将parent存入
            
            nodes[minIndex2] = parentNode;
            int i = minIndex1;
            for (i ; i < k-1; i++) {//在这里如果没有int i  = minIndex1或者int k = size,就会出现赋值错误
                nodes[i] = nodes[i + 1];
            }
            
        }

        size--;
        
    }

    // 返回根节点
    return nodes[0];
}



void sortNodes(struct BiTNode** nodes, int size) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = 0; j < size - i - 1; j++) {
            if (nodes[j]->data < nodes[j + 1]->data) {
                struct BiTNode* temp = nodes[j];
                nodes[j] = nodes[j + 1];
                nodes[j + 1] = temp;
            }
        }
    }
}

// 构建哈夫曼树
// BiTNode* buildHuffmanTree(char symbols[], int frequencies[], int size) {
//     // 创建叶子节点
//     BiTNode** nodes = (BiTNode**)malloc(size * sizeof(BiTNode*));
//     for (int i = 0; i < size; i++) {
//         nodes[i] = createNode(frequencies[i], symbols[i]);
//     }

//     // 对节点按照频率从大到小排序(可以使用冒泡、插入或快速排序等算法)
//     for (int i = 0; i < size - 1; i++) {
//         for (int j = 0; j < size - i - 1; j++) {
//             if (nodes[j]->data < nodes[j + 1]->data) {
//                 // 交换节点
//                 BiTNode* temp = nodes[j];
//                 nodes[j] = nodes[j + 1];
//                 nodes[j + 1] = temp;
//             }
//         }
//     }

//     // 构建哈夫曼树
//     while (size > 1) {
//         BiTNode *leftChild = nodes[size - 1]; // 取最后两个节点(频率最小的)
//         BiTNode *rightChild = nodes[size - 2];
//         BiTNode *parentNode = createNode(leftChild->data + rightChild->data, '\0');
//         parentNode->left = leftChild;
//         parentNode->right = rightChild;

//         // 删除已经合并的两个子节点
//         free(leftChild);
//         free(rightChild);

//         // 更新节点数组,保持有序
//         int insertIndex = size - 2;
//         while (insertIndex > 0 && parentNode->data < nodes[insertIndex - 1]->data) {
//             nodes[insertIndex] = nodes[insertIndex - 1];
//             insertIndex--;
//         }
//         nodes[insertIndex] = parentNode;

//         size--;
//     }

//     // 返回根节点
//     return nodes[0];
// }

// 释放哈夫曼树内存
void freeHuffmanTree(struct BiTNode* root) {
    if (root) {
        freeHuffmanTree(root->left);
        freeHuffmanTree(root->right);
        free(root);
    }
}


// 打印哈夫曼编码
void printHuffmanCodes(BiTNode *root, int code[], int top) {
    if (root->left) {
        code[top] = 0;
        printHuffmanCodes(root->left, code, top + 1);
    }

    if (root->right) {
        code[top] = 1;
        printHuffmanCodes(root->right, code, top + 1);
    }

    if (root->symbol != '\0') {
        printf("%c: ", root->symbol);
        for (int i = 0; i < top; i++) {
            printf("%d", code[i]);
        }
        printf("\n");
    }
}

void writeHuffmanCodesToFile(BiTNode *root, int code[], int top, FILE *file) {
    if (root->left) {
        code[top] = 0;
        writeHuffmanCodesToFile(root->left, code, top + 1, file);
    }
    if (root->right) {
        code[top] = 1;
        writeHuffmanCodesToFile(root->right, code, top + 1, file);
    }
    if (!(root->left) && !(root->right)) {
        // 叶子节点,表示字符和编码
        fprintf(file, "%c: ", root->symbol);
        for (int i = 0; i < top; i++) {
            fprintf(file, "%d", code[i]);
        }
        fprintf(file, "\n");
    }
}



// 读取哈夫曼编码文件并创建结构体数组
HuffmanCode* readHuffmanCodesFromFile(const char* filename, int* numCodes) {
    FILE* file = fopen(filename, "r");
    if (file == NULL) {
        perror("无法打开文件");
        exit(1);
    }

    // 假设哈夫曼编码文件的行数不超过 1000 行,你可以根据实际情况调整这个大小
    const int maxLines = 1000;
    HuffmanCode* huffmanCodes = (HuffmanCode*)malloc(maxLines * sizeof(HuffmanCode));

    char line[100]; // 假设每行不超过 100 个字符
    *numCodes = 0;

    while (fgets(line, sizeof(line), file) != NULL) {
        if (*numCodes >= maxLines) {
            fprintf(stderr, "哈夫曼编码文件中的行数超过了预期的最大行数。\n");
            fclose(file);
            free(huffmanCodes);
            exit(1);
        }

        // 解析每一行,假设格式为 "字符: 编码"
        char character;
        char code[100];
        if (sscanf(line, "%c: %s", &character, code) == 2) {
            huffmanCodes[*numCodes].character = character;
            huffmanCodes[*numCodes].code = strdup(code);
            (*numCodes)++;
        }
    }

    fclose(file);
    return huffmanCodes;
}

// 编码文本
char* encodeText(const char* text,HuffmanCode* nodes) {
    int textLength = strlen(text);
    char* encodedText = (char*)malloc(2 * sizeof(char)); // 预估编码后的长度
    int encodedIndex = 0;

    for (int i = 0; i < textLength; i++) {
        char currentChar = text[i];
        for (int j = 0; j < 27; j++) {
            if (currentChar == nodes[j].character) {
                strcat(encodedText, nodes[j].code);
                encodedIndex += strlen(nodes[j].code);
                break;
            }
        }
    }

    // encodedText[encodedIndex] = '\0';
    return encodedText;
}

// 解码文本
char* decodeText(const char* encodedText, struct BiTNode* root) {
    int encodedLength = strlen(encodedText);
    char* decodedText = (char*)malloc(encodedLength * sizeof(char));
    int decodedIndex = 0;
    struct BiTNode* currentNode = root;

    for (int i = 0; i < encodedLength; i++) {
        if (encodedText[i] == '0') {
            currentNode = currentNode->left;
        } else if (encodedText[i] == '1') {
            currentNode = currentNode->right;
        }

        if (currentNode->left == NULL && currentNode->right == NULL) {
            decodedText[decodedIndex++] = currentNode->symbol;
            currentNode = root;
        }
    }

    decodedText[decodedIndex] = '\0';
    return decodedText;
}


int main() {
    char symbols[] = {' ','A', 'B', 'C', 'D',
                        'E','F','G','H','I',
                        'J','K','L','M','N',
                        'O','P','Q','R','S',
                        'T','U','V','W','X',
                        'Y','Z'};
    int frequencies[] = {186,64, 23, 22, 32,
                        103,21,15,47,57,
                        1,5,32,20,20,
                        56,19,2,50,51,
                        55,30,10,11,2,
                        21,2};

    int size = sizeof(symbols) / sizeof(symbols[0]);

    BiTNode *root = buildHuffmanTree(symbols, frequencies, size);

    int code[supermax];
    int top = 0;

    printHuffmanCodes(root, code, top);
    showBinTree1(root);
	FILE *codeFile = fopen("codefile.txt", "w");
    if (codeFile == NULL) {
        perror("无法打开文件");
        return 1;
    }

    // int code[10000];
    // top = 0;

    // 将Huffman编码写入文件
    writeHuffmanCodesToFile(root, code, top, codeFile);

    // 关闭文件
    fclose(codeFile);

    //读取哈夫曼编码文件
    int codeCount;
    HuffmanCode *huffmanCodes = readHuffmanCodesFromFile("codefile.txt", &codeCount);

    if (huffmanCodes == NULL) {
        return 1;
    }

    const char* originalText = " MY FAVORITE   "  ;
    char* encodedText = encodeText(originalText, huffmanCodes);
    printf("Encoded Text: %s\n", encodedText);

    char* decodedText = decodeText(encodedText, root);
    printf("Decoded Text: %s\n", decodedText);
    return 0;
}

问题

在创建哈夫曼树时对于剩余数组的覆盖与比较处理那里比较关键

思想

创建树的时候需要更新节点,更新方法是父节点覆盖一个,还有一个前一个往后覆盖然后减小size

由此引申出来一个问题:C语言的这个哈夫曼树要严格规定覆盖后的遍历次数,所以如果在for循环里边定义变量最好就只在这个for循环使用不然两个分号的变量都需要在for循环外边计算完再在其中使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值