Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 145 additions & 76 deletions src/huffman/huffman.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
#include <stdlib.h>
#include <string.h>

// 前向声明所有静态函数
static void free_huffman_tree(MinHeapNode* node);
static void on_encode_clicked(GtkWidget *widget, gpointer user_data);
static void on_decode_clicked(GtkWidget *widget, gpointer data);

// 全局变量
static GtkWidget *text_view_input;
static GtkWidget *text_view_output;
static GtkWidget *text_view_codes;
Expand All @@ -12,10 +18,18 @@ static MinHeapNode* huffman_tree = NULL;
static HuffmanCode huffman_codes[MAX_CHAR];
static int code_count = 0;

// 释放哈夫曼树的内存
static void free_huffman_tree(MinHeapNode* node) {
if (node == NULL) return;
free_huffman_tree(node->left);
free_huffman_tree(node->right);
free(node);
}

// 存储编码
void store_code(char data, char* code) {
huffman_codes[code_count].character = data;
huffman_codes[code_count].code = strdup(code);
huffman_codes[code_count].code = g_strdup(code);
code_count++;
}

Expand All @@ -32,7 +46,7 @@ char* get_code(char c) {
// 清理编码表
void clear_huffman_codes() {
for (int i = 0; i < code_count; i++) {
free(huffman_codes[i].code);
g_free(huffman_codes[i].code);
}
code_count = 0;
}
Expand Down Expand Up @@ -190,98 +204,118 @@ void count_frequency(const char* text, char* data, int* freq, int* size) {
}

// 编码回调函数
static void on_encode_clicked(GtkWidget *widget, gpointer data) {
static void on_encode_clicked(GtkWidget *widget, gpointer user_data) {
(void)user_data;

// 清理之前的状态
clear_huffman_codes();
if (huffman_tree) {
free_huffman_tree(huffman_tree);
huffman_tree = NULL;
}

// 获取输入文本
GtkTextBuffer *input_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view_input));
GtkTextBuffer *output_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view_output));
GtkTextBuffer *codes_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view_codes));

GtkTextIter start, end;
gtk_text_buffer_get_bounds(input_buffer, &start, &end);
char *text = gtk_text_buffer_get_text(input_buffer, &start, &end, FALSE);

// 检查输入
if (!text || strlen(text) == 0) {
handle_error(gtk_widget_get_toplevel(widget),
ERROR_INVALID_INPUT,
"请输入要编码的文本");
g_free(text);
return;
}

// 内存分配检查
char *encoded = malloc(strlen(text) * 8 + 1);
if (!encoded) {
handle_error(gtk_widget_get_toplevel(widget),
ERROR_MEMORY_ALLOCATION,
"内存分配失败");
g_free(text);
char *input_text = gtk_text_buffer_get_text(input_buffer, &start, &end, FALSE);

if (!input_text || strlen(input_text) == 0) {
handle_error(gtk_widget_get_toplevel(widget), ERROR_INVALID_INPUT, "请输入要编码的文本");
g_free(input_text);
return;
}

// 清理之前的编码表
clear_huffman_codes();

// 清空输出
gtk_text_buffer_set_text(output_buffer, "", -1);
gtk_text_buffer_set_text(codes_buffer, "", -1);

// 统计频率
char char_data[MAX_CHAR];
// 统计字符频率
char char_array[MAX_CHAR];
int freq[MAX_CHAR];
int size;
count_frequency(text, char_data, freq, &size);

int size = 0;
count_frequency(input_text, char_array, freq, &size);
// 构建哈夫曼树
huffman_tree = build_huffman_tree(char_data, freq, size);

// 生成并显示编码表
huffman_tree = build_huffman_tree(char_array, freq, size);
if (!huffman_tree) {
handle_error(gtk_widget_get_toplevel(widget), ERROR_MEMORY_ALLOCATION, "构建哈夫曼树失败");
g_free(input_text);
return;
}

// 清空编码表显示
gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view_codes)), "", -1);

// 生成编码表
char code_str[MAX_TREE_HT];
print_codes(huffman_tree, code_str, 0, codes_buffer);

print_codes(huffman_tree, code_str, 0, gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view_codes)));
// 编码文本
encode_text(text, output_buffer);

g_free(text);
free(encoded);
GString *encoded = g_string_new("");
for (char *p = input_text; *p; p++) {
char *code = get_code(*p);
if (code) {
g_string_append(encoded, code);
g_string_append(encoded, " "); // 添加空格分隔
}
}

// 显示结果
GtkTextBuffer *output_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view_output));
gtk_text_buffer_set_text(output_buffer, encoded->str, -1);

// 清理资源
g_string_free(encoded, TRUE);
g_free(input_text);
}

// 解码回调函数
static void on_decode_clicked(GtkWidget *widget, gpointer data) {
(void)data;

// 获取输入的编码
GtkTextBuffer *input_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view_input));
GtkTextBuffer *output_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view_output));

GtkTextIter start, end;
gtk_text_buffer_get_bounds(input_buffer, &start, &end);
char *encoded_text = gtk_text_buffer_get_text(input_buffer, &start, &end, FALSE);

// 检查输入是否为空

if (!encoded_text || strlen(encoded_text) == 0) {
gtk_text_buffer_set_text(output_buffer, "请输入要解码的二进制串", -1);
handle_error(gtk_widget_get_toplevel(widget), ERROR_INVALID_INPUT, "请输入要解码的二进制串");
g_free(encoded_text);
return;
}

// 检查是否已经构建了哈夫曼树

// 检查输入是否为有效的二进制串
for (char *p = encoded_text; *p; p++) {
if (*p != '0' && *p != '1' && *p != ' ' && *p != '\n') {
handle_error(gtk_widget_get_toplevel(widget), ERROR_INVALID_INPUT,
"输入必须是二进制串(只包含0和1,可以包含空格和换行)");
g_free(encoded_text);
return;
}
}

// 检查是否有哈夫曼树
if (!huffman_tree) {
gtk_text_buffer_set_text(output_buffer, "请先进行编码操作", -1);
handle_error(gtk_widget_get_toplevel(widget), ERROR_INVALID_OPERATION,
"请先进行编码操作以生成哈夫曼树");
g_free(encoded_text);
return;
}

// 检查输入是否只包含0和1
for (int i = 0; encoded_text[i]; i++) {
if (encoded_text[i] != '0' && encoded_text[i] != '1' && encoded_text[i] != ' ') {
gtk_text_buffer_set_text(output_buffer, "输入必须是由0和1组成的二进制串", -1);
g_free(encoded_text);
return;
}
// 解码
char *decoded = decode_text(encoded_text, huffman_tree);
if (!decoded) {
handle_error(gtk_widget_get_toplevel(widget), ERROR_INVALID_OPERATION,
"解码失败:无效的编码或内存不足");
g_free(encoded_text);
return;
}

char *decoded_text = decode_text(encoded_text, huffman_tree);
gtk_text_buffer_set_text(output_buffer, decoded_text, -1);


// 显示结果
GtkTextBuffer *output_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view_output));
gtk_text_buffer_set_text(output_buffer, decoded, -1);

// 清理资源
g_free(encoded_text);
free(decoded_text);
free(decoded);
}

// 编码文本
Expand All @@ -300,22 +334,57 @@ void encode_text(const char* text, GtkTextBuffer* output_buffer) {

// 解码文本
char* decode_text(const char* encoded_text, MinHeapNode* root) {
char* result = malloc(strlen(encoded_text) + 1);
if (!root || !encoded_text) return NULL;

// 预分配足够的空间
size_t max_len = strlen(encoded_text) + 1;
char* result = malloc(max_len);
if (!result) return NULL;

int result_index = 0;
MinHeapNode* current = root;

for (int i = 0; encoded_text[i] != '\0'; i++) {
if (encoded_text[i] == ' ') continue; // 跳过分隔空格
// 添加安全检查
size_t max_iterations = strlen(encoded_text) * 2;
size_t iteration_count = 0;

for (const char* p = encoded_text; *p && result_index < max_len - 1; p++) {
if (*p == ' ' || *p == '\n') continue; // 跳过空格和换行

if (*p != '0' && *p != '1') {
free(result);
return NULL;
}

if (encoded_text[i] == '0')
current = current->left;
else if (encoded_text[i] == '1')
current = current->right;

if (current->left == NULL && current->right == NULL) {
if (!current) { // 添加空指针检查
free(result);
return NULL;
}

current = (*p == '0') ? current->left : current->right;

if (!current) { // 添加空指针检查
free(result);
return NULL;
}

// 到达叶子节点
if (!current->left && !current->right) {
result[result_index++] = current->data;
current = root;
}

// 安全检查
if (++iteration_count > max_iterations) {
free(result);
return NULL;
}
}

// 确保解码完成
if (current != root) {
free(result);
return NULL;
}

result[result_index] = '\0';
Expand Down Expand Up @@ -360,7 +429,7 @@ GtkWidget* create_huffman_page(void) {
g_signal_connect(encode_button, "clicked", G_CALLBACK(on_encode_clicked), NULL);
g_signal_connect(decode_button, "clicked", G_CALLBACK(on_decode_clicked), NULL);

// 创��编码表显示区域
// 创建编码表显示区域
GtkWidget *codes_frame = gtk_frame_new("编码表");
gtk_box_pack_start(GTK_BOX(page), codes_frame, TRUE, TRUE, 5);

Expand Down
45 changes: 32 additions & 13 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "utils/error_handler.h"

#define BACKGROUND_CHANGE_INTERVAL 300000
#define DEFAULT_WINDOW_WIDTH 1366
#define DEFAULT_WINDOW_HEIGHT 768

typedef struct {
GtkWidget *window;
Expand Down Expand Up @@ -173,7 +175,7 @@ static gboolean on_window_resize(GtkWidget *widget,

// 根据窗口宽度调整字体大小
if (width != last_width) {
app_ctx.font_scale_factor = (double)width / 1920.0; // 以1920像素为基准
app_ctx.font_scale_factor = (double)width / 1920.0;
gtk_range_set_value(GTK_RANGE(app_ctx.font_scale), app_ctx.font_scale_factor);
update_font_size();
last_width = width;
Expand All @@ -182,7 +184,7 @@ static gboolean on_window_resize(GtkWidget *widget,
if (resize_timer > 0) {
g_source_remove(resize_timer);
}
resize_timer = g_timeout_add(150, update_background, NULL);
resize_timer = g_timeout_add(500, (GSourceFunc)update_background, NULL);

return FALSE;
}
Expand Down Expand Up @@ -227,6 +229,18 @@ static void load_backgrounds(void) {
closedir(dir);
}

// 窗口大小变化的回调函数
static void on_window_size_changed(GtkWidget *widget,
GtkAllocation *allocation,
gpointer user_data) {
// 获取新的窗口尺寸
int width, height;
gtk_window_get_size(GTK_WINDOW(widget), &width, &height);

// 更新UI元素大小或进行其他必要的调整
// ... 根据需要添加代码 ...
}

int main(int argc, char *argv[]) {
gtk_init(&argc, &argv);
srand(time(NULL));
Expand All @@ -237,17 +251,22 @@ int main(int argc, char *argv[]) {

// 创建主窗口
app_ctx.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(app_ctx.window), "算法与数据结构课程设计");

// 设置窗口默认大小
GdkDisplay *display = gdk_display_get_default();
GdkMonitor *monitor = gdk_display_get_primary_monitor(display);
GdkRectangle workarea = {0};
gdk_monitor_get_workarea(monitor, &workarea);
gtk_window_set_title(GTK_WINDOW(app_ctx.window), "算法与数据结构课程设计展示系统 by 210052202019 龙正");

// 设置默认窗口大小
gtk_window_set_default_size(GTK_WINDOW(app_ctx.window),
DEFAULT_WINDOW_WIDTH,
DEFAULT_WINDOW_HEIGHT);

// 允许调整窗口大小
gtk_window_set_resizable(GTK_WINDOW(app_ctx.window), TRUE);

// 设置窗口最小尺寸(可选)
gtk_widget_set_size_request(app_ctx.window, 800, 600);

int width = (workarea.width * 80) / 100;
int height = (workarea.height * 80) / 100;
gtk_window_set_default_size(GTK_WINDOW(app_ctx.window), width, height);
// 添加窗口大小变化的回调(如果需要响应窗口大小变化)
g_signal_connect(G_OBJECT(app_ctx.window), "size-allocate",
G_CALLBACK(on_window_size_changed), NULL);

// 创建叠加容器
GtkWidget *overlay = gtk_overlay_new();
Expand Down Expand Up @@ -315,7 +334,7 @@ int main(int argc, char *argv[]) {
g_signal_connect(app_ctx.window, "configure-event", G_CALLBACK(on_window_resize), NULL);

// 设置背景更新定时器
g_timeout_add(100, update_background, NULL);
g_timeout_add(BACKGROUND_CHANGE_INTERVAL, update_background, NULL);

// 初始化字体相关变量
app_ctx.base_font_size = 14; // 基础字体大小
Expand Down
Loading