xmhyyds 2023-12-27 20:26 采纳率: 0%
浏览 26
已结题

哈夫曼树的可视化函数有问题


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <cstring>
#include<stdlib.h>
#define MAXSIZE 100
#include <graphics.h>
using namespace std;

//哈夫曼树的存储结构 
typedef struct HaffmanTree {
    double weight;                    //权值
    char data;
    int parent, lChild, rChild;    //结点的双亲、左孩子、右孩子的下标 
}HTNode, * HuffmanTree;            //动态分配数组储存哈夫曼树 

typedef char** HuffmanCode;        //动态分配数组储存哈夫曼编码表 


//寻找最小的两个元素           
void Select(HuffmanTree& HT, int n, int& s1, int& s2) {
    int i, count = 0;
    for (i = 1; i <= n; i++) {//求出前两个parent为零的i
        if (HT[i].parent == 0 && count == 0) {
            s1 = i;
            count = 1;
        }
        else if (HT[i].parent == 0 && count == 1) {
            s2 = i;
            break;
        }
    }
    if (HT[s1].weight > HT[s2].weight) {//使s1<s2
        count = s1;
        s1 = s2;
        s2 = count;
    }
    for (i++; i <= n; i++) {
        if (HT[i].parent == 0 && HT[i].weight < HT[s1].weight) {
            s2 = s1;
            s1 = i;
        }
        else if (HT[i].parent == 0 && HT[i].weight < HT[s2].weight) {
            s2 = i;
        }
    }
}

//功能一:初始化,并建立哈夫曼树
void Initialization(HuffmanTree& HT, int n) {
    int m;
    if (n <= 1) {
        printf("字符个数不足!\n");
        return;
    }
    m = 2 * n - 1;//一共有m=2n-1个节点
    HT =(HuffmanTree)malloc((m+1)*sizeof(HTNode));        //从1开始,0未用,需要动态分配 m+1 个单元,HT[m]表示根节点 
    for (int i = 1; i <= m; i++) {  
        HT[i].parent = 0;
        HT[i].lChild = 0;
        HT[i].rChild = 0;
    }//将双亲、左孩子、右孩子的下标初始化为0 

    //初始化n个字符及其权值
    cout << "请输入字符及权值:"<<endl;
    char s;
    double w;
    int r=1;
    while(r<=n&&cin>>s>>w)
    {
        HT[r].data=s;
        HT[r].weight=w;
        r++;
    }
    //创建哈夫曼树
    int s1, s2;
    for (int i = n + 1; i <= m; i++) {                     //通过n-1次的选择创建哈夫曼树 
        Select(HT, i - 1, s1, s2);                         //找出权值最小的两个,最小的下标为s1,次小的为s2 
        HT[s1].parent = i;  HT[s2].parent = i;             //将双s1和s2亲设为i
        HT[i].lChild = s1;  HT[i].rChild = s2;             //将其作为下标为i的节点的左右孩子
        HT[i].weight = HT[s1].weight + HT[s2].weight;     //双亲的权值为左右孩子权值之和 
    }
    
    //初始化保存至文件
    ofstream out("hfmTree.txt");
    int i=1;
    for (i = 1; i <= n; i++) {
        out << i << " " << HT[i].data << " " << HT[i].weight << " " << HT[i].parent << " " << HT[i].lChild << " " << HT[i].rChild << endl;
    }
    for (; i <= m; i++) {
        out << i << " " << " " << " " << HT[i].weight << " " << HT[i].parent << " " << HT[i].lChild << " " << HT[i].rChild << endl;
    }
    out.close();
    printf("哈夫曼树已创建!\n"); 
}

//功能二:编码
void Encoding(HuffmanTree HT, HuffmanCode& HC, int n) {
    int start, child, parent;
    HC = (HuffmanCode)malloc((n+1)*sizeof(char*));                 //分配n个字符编码的编码表空间 
    char *cd=(char *)malloc(n*sizeof(char));              //分配临时存放每个字符编码的动态数组空间 
    cd[n - 1] = '\0';                     //编码结束符
    for (int i = 1; i <= n; i++) {
        start = n - 1;                    //start开始指向最后,即编码结束符的位置 
        child = i;
        parent = HT[i].parent;            //parent指向节点child的双亲节点
        while (parent != 0) {
            --start;                    //回溯一次start向前指一个位置
            if (HT[parent].lChild == child)
            {
                cd[start] = '0';        //child为parent的左孩子,生成0 
            } 
            else
            {
                cd[start] = '1';        //child为parent的右孩子,生成1 
            } 
            child = parent;
            parent = HT[parent].parent;    //继续向上回溯
        }
        HC[i] = (char*)malloc((n-start)*sizeof(char));        //为第i个字符编码分配空间
        strcpy(HC[i], &cd[start]);         //将求得的编码从临时空间cd复制到HC的行列中 
    }
    free(cd);                            //释放临时空间
    cout << "对应字符编码为:\n";
    for (int i = 1; i <= n; i++) {
        cout << HT[i].data << ":" << HC[i] << endl;
    }

    //将字符编码写入文件
    ofstream fout("code.txt");
    for (int i = 1; i <= n; i++) {
        fout << HT[i].data << ":" << HC[i];
        fout << endl;
    }
}

//对正文编码
void TextCode(HuffmanTree HT, HuffmanCode& HC, int n) {
    ifstream file("ToBeTran.txt");//输入方式打开;
    if (!file) {                    //判断文件是否打开
        cout << "打开ToBeTran.txt失败!\n";
        exit(0);
    }
    ofstream fout("CodeFile.txt");//输出方式打开
    
    char ch;
    while (file.get(ch)) {
        for (int i = 1; i <= n; i++) {
            if(ch==' ')
            {
                fout<<HC[1];
                break;
            }
            else if (ch == HT[i].data) {
                fout<<HC[i];
                break;
            }
        }
    }
    cout << "编码完成\n";
}

//译码
void Decoding(HuffmanTree HT, int n) {
    ifstream file("CodeFile.txt");
    if (!file) {                    //判断文件是否打开
        cout << "打开CodeFile.txt失败!\n";
        exit(0);
    }

    ofstream fout("TextFile.txt");
    int m = 2 * n - 1;; //根节点
    char ch;
    while (file.get(ch)) {
        if (ch == '1')
            m = HT[m].rChild;
        else if (ch == '0')
            m = HT[m].lChild;
        if (HT[m].lChild == 0 && HT[m].rChild == 0) {  //当前字段解码完毕 
            if(HT[m].data!='!')
            {
                fout << HT[m].data;
            }
            else
            {
                fout<<" ";
            }
            m = 2 * n - 1;
        }
    }
    cout << "译码完成\n";
}

//打印代码文件
void Print(HuffmanTree HT) {
    char ch;
    ifstream fileCode("CodeFile.txt");
    ofstream fout("CodePrin.txt");
    //正文编码结果
    if (!fileCode) {                          
        cout << "打开CodeFile.txt失败!\n";
        exit(0);
    }//判断文件是否打开
    cout << "正文编码结果:\n";
    int i = 1;
    while (fileCode.get(ch)) {
        cout << ch;
        fout << ch;//存到文件中
        if (i == 50) {
            cout << endl;
            i = 0;
        }
        i++;
    }
    cout << endl;
}

//绘制二叉树 
void drawHuffmanTree(HuffmanTree HT, int x, int y, int level, int length,int i)
{
    int nodeX=x,nodeY=y;
    if (HT == NULL)  // 如果当前节点为空,返回
    printf("还未创建二叉树!"); 
        return;
    // 绘制当前节点
    circle(nodeX, nodeY, 20);  // 以(nodeX, nodeY)为圆心,半径为20绘制圆形
    if(i>=28)
    {
        outtextxy(nodeX - 5, nodeY - 5, ' ');  // 在非叶子节点上显示空格 
    }
    else
    {
        outtextxy(nodeX - 5, nodeY - 5, HT[i].data);  // 在叶子节点上显示字母 
    }

    // 绘制左子树
    if(HT[i].lChild!= 0)
    {
        drawHuffmanTree(HT, nodeX-length/2, nodeY-level*50, level + 1, length / 2,HT[i].lChild);
        line(nodeX, nodeY + 20, nodeX - length / 2, nodeY - 50);  // 绘制左子树的连线
    }

    // 绘制右子树
    if(HT[i].rChild!= 0)
    {
        drawHuffmanTree(HT, nodeX+length/2, nodeY-level*50, level + 1, length / 2,HT[i].rChild);
        line(nodeX, nodeY + 20, nodeX + length / 2, nodeY - 50);  // 绘制右子树的连线
    }
}
//菜单
void menu() {
    cout << "                    哈夫曼编/译码器\n";
    cout << "-------------------------------------------------------------------------------\n";
    cout << "                T:初始化,并建立哈夫曼树\n";
    cout << "                E:编码\n";
    cout << "                D:译码\n";
    cout << "                P:打印代码文件\n";
    cout << "                R:画哈夫曼树\n";
    cout << "                Q:退出程序\n";
    cout << "-------------------------------------------------------------------------------\n";
}

int main() {
    int  n;
    char choice;
    HuffmanTree Tree;
    HuffmanCode HC;
    while (1) {
        menu();
        cout << "\n请选择对应的功能选项进行操作:\n";
        cin >> choice;
        switch (choice) {
            //初始化,并建立哈夫曼树
        case 'T':
            cout << "输入字符的个数:";
            cin >> n;
            Initialization(Tree, n);
            break;
          //编码
        case 'E':
            if (Tree != NULL) {
                Encoding(Tree, HC, n);
                TextCode(Tree, HC, n);
            }
            else
                cout << "还未创建哈夫曼树\n";
            break;

            //译码
        case 'D':
            if (Tree != NULL)
                Decoding(Tree, n);
            else
                cout << "还未创建哈夫曼树\n";
            break;
        
            //打印代码文件
        case 'P':
            if (Tree != NULL)
                Print(Tree);
            else
                cout << "还未创建哈夫曼树\n";
            break;
        case 'R':
            initgraph(640, 480);            //初始化图形界面
            setcolor(RED);    //设置绘画颜色为红色
            setbkcolor(WHITE);
            drawHuffmanTree(Tree,320,450,1,54,53);
            getch();                            //暂停,等待键盘按键
            closegraph();                        //关闭图形界面
        case 'Q':
            exit(0);

        default:
            cout << "请重新输入!\n";
            break;
        }
        system("pause");
        system("cls");
    }
    return 0;
}

   为什么我的drawHuffmanTree函数只能输出一个空界面?调试了好久,我知道节点位置的数值计算方面还需要再调整,但是为什么现在什么输出都没有?其他部分的功能都正常实现就只有这个可视化哈夫曼树的部分有问题。求助大家,课程设计的的加分项,本人想多锻炼一下自己。

img

本人编程初学者,代码有写的不规范不规整的地方还请各位见谅,如果有看不懂的地方请大家及时留言,也欢迎各类批评指正,感谢大家不领赐教

  • 写回答

18条回答 默认 最新

  • 叫兽-郭老师 新星创作者: Java技术领域 2023-12-27 20:30
    关注
    获得0.45元问题酬金

    引用GPT4和答主提供,参考如下:

    你的drawHuffmanTree函数没有输出任何内容,是因为你没有在函数中调用绘制图形的函数。你需要在drawHuffmanTree函数中添加绘制图形的代码,例如使用line函数绘制节点之间的连线。以下是修改后的drawHuffmanTree函数:

    void drawHuffmanTree(HuffmanTree HT, int x, int y, int level, int length,int i){    
        int nodeX=x,nodeY=y;    if (HT == NULL)  // 如果当前节点为空,返回    printf("还未创建二叉树!");         return;    // 绘制当前节点    circle(nodeX, nodeY, 20);  // 以(nodeX, nodeY)为圆心,半径为20绘制圆形    if(i>=28)    {        outtextxy(nodeX - 5, nodeY - 5, ' ');  // 在非叶子节点上显示空格     }    else    {        outtextxy(nodeX - 5, nodeY - 5, HT[i].data);  // 在叶子节点上显示字母     }    // 绘制左子树    if(HT[i].lChild!= 0)    {        drawHuffmanTree(HT, nodeX-length/2, nodeY-level*50, level + 1, length / 2,HT[i].lChild);        line(nodeX, nodeY + 20, nodeX - length / 2, nodeY - 50);  // 绘制左子树的连线    }    // 绘制右子树    if(HT[i].rChild!= 0)    {        drawHuffmanTree(HT, nodeX+length/2, nodeY-level*50, level + 1, length / 2,HT[i].rChild);        line(nodeX, nodeY + 20, nodeX + length / 2, nodeY - 50);  // 绘制右子树的连线    }}
    

    注意:在使用graphics.h库时,需要包含头文件<graphics.h>。同时,确保你的编译器支持graphics.h库。

    评论

报告相同问题?

问题事件

  • 系统已结题 1月4日
  • 创建了问题 12月27日