哈夫曼树中HT访问结构体内部属性使用.还是->

本文详细介绍了如何构造哈夫曼树,通过创建一个HTNode结构体数组,并利用权重信息逐步构建最小带权路径长度的二叉树。在过程中,不断选择两个权重最小的节点合并,形成新的节点,直到所有节点合并成一棵树。哈夫曼树在数据压缩、编码等领域有广泛应用。
//哈夫曼树
typedef struct {
	int weight;
	int parent, lchild, rchild;
}HTNode,*HuffmanTree;
//构造哈夫曼树
void CreateHuffmanTree(HuffmanTree &HT,int n) {
	if (n <= 1) return;
	int m = 2 * n - 1;
	HT = new HTNode[m + 1];
	for (int i = 1; i <= m; i++)
	{
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	for (int i = 0; i <= n; i++)
	{
		cin >> HT[i].weight;
	}


	for (int i = n+1; i <= m; i++)
	{
		int s1, s2;
		//Select(HT, i - 1, s1, s2);
		
		HT[s1].parent = i;
		HT[s2].parent = i;
		
		
		HT[i].lchild = s1;
		HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight+ HT[s2].weight;
		
	}
}

此时的HT是指针,指向HuffmanTree结构体,但是由于HT又指向new出来的HTNode空间,所以在访问HuffmanTree本身的属性的时候使用HT->lchild,由于HT指向了HTNode数组,在HT[i]的时候相当于arr[i]即已经是一个元素,而不是地址了,所以访问元素的属性的时候使用.而不是->。

#include <stdio.h> #include <stdlib.h> // 哈夫曼节点结构体 typedef struct HuffmanNode { int weight; int parent, lchild, rchild; } HuffmanNode; // 优先队列节点结构体 typedef struct PriorityQueueNode { int index; struct PriorityQueueNode *next; } PriorityQueueNode; // 优先队列结构体 typedef struct PriorityQueue { PriorityQueueNode *front; HuffmanNode *ht; } PriorityQueue; // 创建优先队列 PriorityQueue* createPriorityQueue(HuffmanNode *ht, int n) { PriorityQueue *pq = (PriorityQueue *)malloc(sizeof(PriorityQueue)); pq->ht = ht; pq->front = NULL; for (int i = 1; i <= n; i++) { PriorityQueueNode *newNode = (PriorityQueueNode *)malloc(sizeof(PriorityQueueNode)); newNode->index = i; newNode->next = NULL; if (pq->front == NULL || ht[i].weight < ht[pq->front->index].weight) { newNode->next = pq->front; pq->front = newNode; } else { PriorityQueueNode *current = pq->front; while (current->next != NULL && ht[current->next->index].weight < ht[i].weight) { current = current->next; } newNode->next = current->next; current->next = newNode; } } return pq; } // 从优先队列中取出最小元素 int extractMin(PriorityQueue *pq) { if (pq->front == NULL) return -1; int index = pq->front->index; PriorityQueueNode *temp = pq->front; pq->front = pq->front->next; free(temp); return index; } // 插入元素到优先队列 void insert(PriorityQueue *pq, int index) { PriorityQueueNode *newNode = (PriorityQueueNode *)malloc(sizeof(PriorityQueueNode)); newNode->index = index; newNode->next = NULL; if (pq->front == NULL || pq->ht[index].weight < pq->ht[pq->front->index].weight) { newNode->next = pq->front; pq->front = newNode; } else { PriorityQueueNode *current = pq->front; while (current->next != NULL && pq->ht[current->next->index].weight < pq->ht[index].weight) { current = current->next; } newNode->next = current->next; current->next = newNode; } } // 构建哈夫曼 void createHuffmanTree(HuffmanNode *ht, int *w, int n) { int m = 2 * n - 1; for (int i = 1; i <= n; i++) { ht[i].weight = w[i - 1]; ht[i].parent = 0; ht[i].lchild = 0; ht[i].rchild = 0; } for (int i = n + 1; i <= m; i++) { ht[i].weight = 0; ht[i].parent = 0; ht[i].lchild = 0; ht[i].rchild = 0; } PriorityQueue *pq = createPriorityQueue(ht, n); for (int i = n + 1; i <= m; i++) { int s1 = extractMin(pq); int s2 = extractMin(pq); ht[s1].parent = i; ht[s2].parent = i; ht[i].lchild = s1; ht[i].rchild = s2; ht[i].weight = ht[s1].weight + ht[s2].weight; insert(pq, i); } // 释放优先队列 while (pq->front != NULL) { PriorityQueueNode *temp = pq->front; pq->front = pq->front->next; free(temp); } free(pq); }main函数
11-05
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <limits.h> typedef int ElemType; //定义节点 typedef struct TreeNode { //权值 ElemType weight; //父节点 左右子(存储的是下标) int parent; int lchild; int rchild; }TreeNode; //定义哈夫曼 typedef struct HfTree { //哈夫曼的节点实际存储在一个数组中,每个元素都是一个节点,节点中包含 //当前节点的权值 父节点下标 左右子下标 TreeNode* data; //当前哈夫曼中的节点个数 int length; }HfTree; //初始化哈夫曼 HfTree* InitTree(ElemType* weight,int length) { //为哈夫曼开辟空间 HfTree* T = (HfTree*)malloc(sizeof(HfTree)); T->data = (TreeNode*)malloc(sizeof(TreeNode) * (2 * length - 1)); //初始化原来的节点列表 T->length = length; for (int i = 0; i < T->length; i++) { //权值 T->data[i].weight = weight[i]; //初始的节点没有父节点和左右子,先用特殊值表示空 T->data[i].parent = 0; T->data[i].lchild = -1; T->data[i].rchild = -1; } return T; } //选取当前数组中权值最小的两个节点 int* SelectMin(HfTree* T) { //创建临时变量 分别保存最小值的值与下标 但是函数只返回其下标 值主要是用作比较 int min = INT_MAX, index1 = -1; int secondmin = INT_MAX, index2 = -1; //先找到最小权值的节点下标 for (int i = 0; i < T->length; i++) { //只有还没有父节点的节点才能被新节点当成左右子 if (T->data[i].parent == 0) { if (T->data[i].weight < min) { min = T->data[i].weight; index1 = i; } } } //再找到第二小的节点 for (int i = 0; i < T->length; i++) { //只有还没有父节点的节点才能被新节点当成左右子 //并且要不遍历最小节点 if (T->data[i].parent == 0 && i != index1) { if (T->data[i].weight < secondmin) { secondmin = T->data[i].weight; index2 = i; } } } //使用指针传回两个下标的值 int* ret = (int*)malloc(sizeof(int) * 2); ret[0] = index1; ret[1] = index2; return ret; } //构建哈夫曼 void CreateTree(HfTree* T) { //创建变量保存每次选出的两个最小节点下标 int* ret; int min, secondmin; //实际的数组长度 原列表长度*2-1 int length = 2 * T->length - 1; //从原列表之后的位置开始,新建父节点,也就是用之前位置的两个最小节点创造一个新的节点 for (int i = T->length; i < length; i++) { //获取列表的两个最小节点的下标 ret = SelectMin(T); min = ret[0]; secondmin = ret[1]; //新节点权值=最小节点权值+第二小节点权值 T->data[i].weight = T->data[min].weight + T->data[secondmin].weight; //为新节点(父节点)添加其父节点、左右子的下标作为索引 T->data[i].parent = 0; T->data[i].lchild = min; T->data[i].rchild = secondmin; //反之,给它的左右子添加父节点的下标索引 T->data[min].parent = i; T->data[secondmin].parent = i; free(ret); } //更新当前哈夫曼的节点个数 T->length = length; } //遍历哈夫曼 void PreOrder(HfTree* T,int index) { //只要当前节点不为空,则输出其中的权值 if (index != -1) { printf("%d ", T->data[index].weight); //递归遍历其左右子 PreOrder(T, T->data[index].lchild); PreOrder(T, T->data[index].rchild); } } int main() { ElemType arr[] = { 5,1,3,6,11,2,4 }; int len = sizeof(arr) / sizeof(arr[0]); //初始化 HfTree* T = InitTree(arr, len); //构建 CreateTree(T); //遍历 从哈夫曼数组中的最后一个节点开始 也就是从根节点开始遍历 PreOrder(T, T->length - 1); printf("\n"); return 0; }
最新发布
11-26
帮我解读#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_TREE_HT 100 #define MAX_CHAR 256 // 哈夫曼节点 typedef struct Node { char data; unsigned freq; struct Node *left, *right; } Node; // 最小堆 typedef struct MinHeap { int size; Node** array; } MinHeap; // 编码表 typedef struct Code { char ch; char bits[MAX_TREE_HT]; } Code; // 创建新节点 Node* createNode(char data, unsigned freq) { Node* node = (Node*)malloc(sizeof(Node)); node->data = data; node->freq = freq; node->left = node->right = NULL; return node; } // 创建最小堆 MinHeap* createMinHeap(int capacity) { MinHeap* heap = (MinHeap*)malloc(sizeof(MinHeap)); heap->size = 0; heap->array = (Node**)malloc(capacity * sizeof(Node*)); return heap; } // 交换节点 void swapNodes(Node** a, Node** b) { Node* temp = *a; *a = *b; *b = temp; } // 堆化 void heapify(MinHeap* heap, int idx) { int smallest = idx; int left = 2 * idx + 1; int right = 2 * idx + 2; if (left < heap->size && heap->array[left]->freq < heap->array[smallest]->freq) smallest = left; if (right < heap->size && heap->array[right]->freq < heap->array[smallest]->freq) smallest = right; if (smallest != idx) { swapNodes(&heap->array[smallest], &heap->array[idx]); heapify(heap, smallest); } } // 提取最小节点 Node* extractMin(MinHeap* heap) { Node* temp = heap->array[0]; heap->array[0] = heap->array[heap->size - 1]; heap->size--; heapify(heap, 0); return temp; } // 插入节点 void insertNode(MinHeap* heap, Node* node) { heap->size++; int i = heap->size - 1; while (i && node->freq < heap->array[(i - 1) / 2]->freq) { heap->array[i] = heap->array[(i - 1) / 2]; i = (i - 1) / 2; } heap->array[i] = node; } // 构建最小堆 void buildMinHeap(MinHeap* heap) { int n = heap->size - 1; for (int i = (n - 1) / 2; i >= 0; i--) heapify(heap, i); } // 构建哈夫曼 Node* buildHuffmanTree(char data[], int freq[], int size) { MinHeap* heap = createMinHeap(size); for (int i = 0; i < size; i++) heap->array[i] = createNode(data[i], freq[i]); heap->size = size; buildMinHeap(heap); while (heap->size > 1) { Node* left = extractMin(heap); Node* right = extractMin(heap); Node* parent = createNode('$', left->freq + right->freq); parent->left = left; parent->right = right; insertNode(heap, parent); } return extractMin(heap); } // 生成编码表 void generateCodes(Node* root, char code[], int top, Code codes[], int* index) { if (root->left) { code[top] = '0'; generateCodes(root->left, code, top + 1, codes, index); } if (root->right) { code[top] = '1'; generateCodes(root->right, code, top + 1, codes, index); } if (!root->left && !root->right) { codes[*index].ch = root->data; for (int i = 0; i < top; i++) codes[*index].bits[i] = code[i]; codes[*index].bits[top] = '\0'; (*index)++; } } // 统计字符频率 void countChars(const char* text, int freq[]) { for (int i = 0; i < MAX_CHAR; i++) freq[i] = 0; for (int i = 0; text[i] != '\0'; i++) freq[(unsigned char)text[i]]++; } // 编码文本 char* encode(const char* text, Code codes[], int codeCount) { int length = 0; // 计算编码后长度 for (int i = 0; text[i] != '\0'; i++) { for (int j = 0; j < codeCount; j++) { if (codes[j].ch == text[i]) { length += strlen(codes[j].bits); break; } } } char* encoded = (char*)malloc(length + 1); encoded[0] = '\0'; // 生成编码 for (int i = 0; text[i] != '\0'; i++) { for (int j = 0; j < codeCount; j++) { if (codes[j].ch == text[i]) { strcat(encoded, codes[j].bits); break; } } } return encoded; } // 解码文本(使用哈夫曼) char* decodeWithTree(const char* encoded, Node* root) { if (root == NULL) return NULL; char* decoded = (char*)malloc(strlen(encoded) + 1); int index = 0; Node* current = root; for (int i = 0; encoded[i] != '\0'; i++) { if (encoded[i] == '0') { current = current->left; } else if (encoded[i] == '1') { current = current->right; } else { printf("错误:编码中包含非法字符 '%c'\n", encoded[i]); free(decoded); return NULL; } if (current == NULL) { printf("错误:解码路径错误\n"); free(decoded); return NULL; } // 到达叶子节点 if (!current->left && !current->right) { decoded[index++] = current->data; current = root; } } decoded[index] = '\0'; return decoded; } // 解码文本(使用编码表) char* decodeWithTable(const char* encoded, Code codes[], int codeCount) { char* decoded = (char*)malloc(strlen(encoded) + 1); decoded[0] = '\0'; char currentCode[MAX_TREE_HT] = ""; int codePos = 0; for (int i = 0; encoded[i] != '\0'; i++) { currentCode[codePos++] = encoded[i]; currentCode[codePos] = '\0'; // 查找匹配的编码 for (int j = 0; j < codeCount; j++) { if (strcmp(currentCode, codes[j].bits) == 0) { // 找到匹配,添加对应字符 int len = strlen(decoded); decoded[len] = codes[j].ch; decoded[len + 1] = '\0'; // 重置当前编码 codePos = 0; currentCode[0] = '\0'; break; } } // 防止无限循环 if (codePos >= MAX_TREE_HT - 1) { printf("错误:未找到匹配的编码\n"); free(decoded); return NULL; } } return decoded; } // 显示编码表 void showCodes(Code codes[], int count) { printf("\n字符\t编码\n"); printf("----\t----\n"); for (int i = 0; i < count; i++) { if (codes[i].ch == ' ') printf("空格"); else if (codes[i].ch == '\n') printf("换行"); else if (codes[i].ch == '\t') printf("制表符"); else printf("%c", codes[i].ch); printf("\t%s\n", codes[i].bits); } } // 释放内存 void freeTree(Node* root) { if (root == NULL) return; freeTree(root->left); freeTree(root->right); free(root); } // 显示菜单 void showMenu() { printf("\n=== 哈夫曼编码/译码器 ===\n"); printf("1. 编码文本\n"); printf("2. 译码文本(使用哈夫曼)\n"); printf("3. 译码文本(使用编码表)\n"); printf("4. 退出\n"); printf("请选择操作: "); } int main() { int choice; char text[1000]; char encodedText[5000]; Node* huffmanTree = NULL; Code codes[MAX_CHAR]; int codeCount = 0; while (1) { showMenu(); scanf("%d", &choice); getchar(); // 消耗换行符 switch (choice) { case 1: { // 编码文本 printf("请输入要编码的文本: "); fgets(text, sizeof(text), stdin); // 移除换行符 int len = strlen(text); if (len > 0 && text[len-1] == '\n') text[len-1] = '\0'; if (strlen(text) == 0) { printf("输入为空!\n"); break; } // 统计频率 int freq[MAX_CHAR]; countChars(text, freq); // 收集出现过的字符 char chars[MAX_CHAR]; int freqs[MAX_CHAR]; int charCount = 0; for (int i = 0; i < MAX_CHAR; i++) { if (freq[i] > 0) { chars[charCount] = (char)i; freqs[charCount] = freq[i]; charCount++; } } // 构建哈夫曼 if (huffmanTree != NULL) { freeTree(huffmanTree); } huffmanTree = buildHuffmanTree(chars, freqs, charCount); // 生成编码表 codeCount = 0; char tempCode[MAX_TREE_HT]; generateCodes(huffmanTree, tempCode, 0, codes, &codeCount); // 显示编码表 showCodes(codes, codeCount); // 编码文本 char* encoded = encode(text, codes, codeCount); printf("\n编码结果: %s\n", encoded); // 保存编码结果供后续使用 strncpy(encodedText, encoded, sizeof(encodedText)-1); encodedText[sizeof(encodedText)-1] = '\0'; // 计算压缩率 int originalBits = strlen(text) * 8; int encodedBits = strlen(encoded); double ratio = (1 - (double)encodedBits / originalBits) * 100; printf("\n压缩统计:\n"); printf("原始: %d bits\n", originalBits); printf("编码: %d bits\n", encodedBits); printf("压缩率: %.1f%%\n", ratio); free(encoded); break; } case 2: { // 使用哈夫曼译码 if (huffmanTree == NULL) { printf("请先编码文本生成哈夫曼!\n"); break; } printf("请输入要译码的二进制串: "); fgets(encodedText, sizeof(encodedText), stdin); // 移除换行符 int len = strlen(encodedText); if (len > 0 && encodedText[len-1] == '\n') encodedText[len-1] = '\0'; // 验证输入是否为二进制 for (int i = 0; encodedText[i] != '\0'; i++) { if (encodedText[i] != '0' && encodedText[i] != '1') { printf("错误:输入必须为二进制串(只包含0和1)\n"); break; } } char* decoded = decodeWithTree(encodedText, huffmanTree); if (decoded != NULL) { printf("译码结果: %s\n", decoded); free(decoded); } break; } case 3: { // 使用编码表译码 if (codeCount == 0) { printf("请先编码文本生成编码表!\n"); break; } printf("请输入要译码的二进制串: "); fgets(encodedText, sizeof(encodedText), stdin); // 移除换行符 int len = strlen(encodedText); if (len > 0 && encodedText[len-1] == '\n') encodedText[len-1] = '\0'; char* decoded = decodeWithTable(encodedText, codes, codeCount); if (decoded != NULL) { printf("译码结果: %s\n", decoded); free(decoded); } break; } case 4: printf("程序退出!\n"); if (huffmanTree != NULL) { freeTree(huffmanTree); } return 0; default: printf("无效选择!\n"); } } return 0; }
11-22
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值