罗宾范佩西 2017-10-29 04:12 采纳率: 0%
浏览 931

C++用哈夫曼树实现编码压缩文章为何报错,请大佬指点。

  1. #ifndef HFTREE #define HFTREE

#include
using namespace std;

template
class hfTree {
private:
struct Node
{
Type data;
int weight;
int parent, left, right;
};
Node * elem;
int length;
public:
struct hfCode {
Type data;
string code;
};

    hfTree(const Type *x, const int * w, int size);
    void getCode(hfCode result[]);
    ~hfTree() { delete [] elem; }

};

template
hfTree::hfTree(const Type * v, const int * w, int size)
{
const int max = 32767;
int min1, min2;//最小树,次最小树的权值
int x, y;//最小树,次最小树的下标

length = 2 * size;
elem = new Node[length];
//将数表初始化
for (int i = size; i < length; ++i)
{
    elem[i].weight = w[i - size];
    elem[i].data = v[i - size];
    elem[i].parent = elem[i].left = elem[i].right = 0;
}
//归并森林中的树
for (int i = size - 1; i > 0; --i)
{
    min1 = min2 = max; x = y = 0;
    for (int j = i + 1; j<length; ++j)
        if (elem[j].parent == 0)
            if (elem[j].weight<min1)
            {
                min2 = min1; min1 = elem[j].weight; x = y; y = j;
            }
            else if (elem[j].weight<min2)
            {
                min2 = elem[j].weight; x = j;
            }//第52-61:找出待归并的两棵树
    elem[i].weight = min1 + min2;
    elem[i].left = x; elem[i].right = y; elem[i].parent = 0;
    elem[x].parent = i; elem[y].parent = i;
}

}

template
void hfTree::getCode(hfCode result[])
{
int size = length / 2;
int p, s;//p是s的父节点
for (int i = size; i<length; ++i)
{
result[i - size].data = elem[i].data;
result[i - size].code = " ";
p = elem[i].parent; s = i;
while (p) {
if (elem[p].left == s)
result[i - size].code = "0" + result[i - size].code;
else result[i - size].code = "1" + result[i - size].code;
s = p; p = elem[p].parent;
}
}
}

#include"hfTree.h"
#include
#include
using namespace std;
/*
输入一篇英文文章,统计每个字符出现的次数,
并以此构造哈夫曼树和输出每个字符的哈夫曼编码,
最后输出这篇文章的编码。
*/
int main()
{
struct Wen
{
char abc;
int weight;
}; Wen *elems;
//结点指针保存文章的字符和权重
cout << "请输入一段英文,按回车键结束。" << endl;
string str;
getline(cin, str);

int str_lenth = str.length();
elems=new Wen [str_lenth];
int _length = 0;

for (int j = 0; j < str_lenth; j++)
    for (int i = 0; i <= j; i++)
    {
        if (elems[i].abc== str[j])
        {
            elems[i].weight++; break;
        }
        else if(elems[i].abc==0)
            elems[i].abc = str[j]; 
            elems[i].weight = 1; 
            _length++;
    }//两次for循环统计文章相同的字符和权重
char *xx = new char[_length]; 
int *ww = new int[_length];
for (int i = 0; i < _length; i++) {
    xx[i] = elems[i].abc;
    ww[i] = elems[i].weight;
}//将文章出现的字符和权重保存在两个数组中

hfTree<char>tree(xx, ww, _length);
hfTree<char>::hfCode result [200];

tree.getCode(result);
for (int i = 0; i < _length; ++i)
    cout << result[i].data << " " << result[i].code <<endl;
system("pause");
return 0;

}
VS2015和dev都可以编译,但是vs2015再输入文章后程序就无法运行了
dev则是输出不正确。

  • 写回答

1条回答 默认 最新

  • A_Ender 2017-10-29 06:55
    关注

    其实我不是很懂C++,我是实现pascal的

    1 /***************************************
    2 目的:1.根据输入的字符代码集及其权值集,
    3 构造赫夫曼树,输出各字符的赫夫曼编码
    4 2.输入赫夫曼码序列,输出原始字符代码
    5 作者:Dmego 时间:2016-11-11
    6 ****************************************/
    7 #include
    8 #define MAX_MA 1000
    9 #define MAX_ZF 100
    10 using namespace std;
    11
    12 //哈夫曼树的储存表示
    13 typedef struct
    14 {
    15 int weight; //结点的权值
    16 int parent, lchild, rchild;//双亲,左孩子,右孩子的下标
    17 }HTNode,*HuffmanTree; //动态分配数组来储存哈夫曼树的结点
    18

    19 //哈夫曼编码表的储存表示
    20 typedef char **HuffmanCode;//动态分配数组存储哈夫曼编码
    21
    22 //返回两个双亲域为0且权值最小的点的下标
    23 void Select(HuffmanTree HT, int n, int &s1, int &s2)
    24 {
    25 /*n代表HT数组的长度
    26 /
    27
    28 //前两个for循环找所有结点中权值最小的点(字符)
    29 for (int i = 1; i <= n; i++)
    30 {//利用for循环找出一个双亲为0的结点
    31 if (HT[i].parent == 0)
    32 {
    33 s1 = i;//s1初始化为i
    34 break;//找到一个后立即退出循环
    35 }
    36 }
    37 for (int i = 1; i <= n; i++)
    38 {/
    利用for循环找到所有结点(字符)权值最小的一个
    39 并且保证该结点的双亲为0*/
    40 if (HT[i].weight < HT[s1].weight && HT[i].parent == 0)
    41 s1 = i;
    42 }
    43 //后两个for循环所有结点中权值第二小的点(字符)
    44 for (int i = 1; i <= n; i++)
    45 {//利用for循环找出一个双亲为0的结点,并且不能是s1
    46 if (HT[i].parent == 0 && i != s1)
    47 {
    48 s2 = i;//s2初始化为i
    49 break;//找到一个后立即退出循环
    50 }

    51 }
    52
    53 for (int i = 1; i <= n; i++)
    54 {/*利用for循环找到所有结点(字符)权值第二小的一个,
    55 该结点满足不能是s1且双亲是0*/
    56 if (HT[i].weight < HT[s2].weight && HT[i].parent == 0 && i!= s1)
    57 s2 = i;
    58 }
    59
    60 }
    61
    62 //构造哈夫曼树
    63 void CreateHuffmanTree(HuffmanTree &HT, int n)
    64 {
    65 /*-----------初始化工作-------------------------*/
    66 if (n <= 1)
    67 return;
    68 int m = 2 * n - 1;
    69 HT = new HTNode[m + 1];
    70 for (int i = 1; i <= m; ++i)
    71 {//将1~m号单元中的双亲,左孩子,右孩子的下标都初始化为0
    72 HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0;
    73 }
    74 for (int i = 1; i <= n; ++i)
    75 {
    76 cin >> HT[i].weight;//输入前n个单元中叶子结点的权值
    77 }
    78 /*-----------创建工作---------------------------*/
    79 int s1,s2;
    80 for (int i = n + 1; i <= m; ++i)
    81 {//通过n-1次的选择,删除,合并来构造哈夫曼树
    82 Select(HT, i - 1, s1, s2);
    83 /*cout << HT[s1].weight << " , " << HT[s2].weight << endl;*/
    84 /*将s1,s2的双亲域由0改为i
    85 (相当于把这两个结点删除了,这两个结点不再参与Select()函数)*/
    86 HT[s1].parent = i;
    87 HT[s2].parent = i;
    88 //s1,与s2分别作为i的左右孩子
    89 HT[i].lchild = s1;
    90 HT[i].rchild = s2;
    91 //结点i的权值为s1,s2权值之和
    92 HT[i].weight = HT[s1].weight + HT[s2].weight;
    93 }
    94 }
    95
    96 //从叶子到根逆向求每个字符的哈夫曼编码,储存在编码表HC中
    97 void CreatHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n)
    98 {
    99 HC = new char*[n + 1];//分配储存n个字符编码的编码表空间
    100 char cd = new char[n];//分配临时存储字符编码的动态空间
    101 cd[n - 1] = '\0';//编码结束符
    102 for (int i = 1; i <= n; i++)//逐个求字符编码
    103 {
    104 int start = n - 1;//start 开始指向最后,即编码结束符位置
    105 int c = i;
    106 int f = HT[c].parent;//f指向结点c的双亲
    107 while (f != 0)//从叶子结点开始回溯,直到根结点
    108 {
    109 --start;//回溯一次,start向前指向一个位置
    110 if (HT[f].lchild == c) cd[start] = '0';//结点c是f的左孩子,则cd[start] = 0;
    111 else cd[start] = '1';//否则c是f的右孩子,cd[start] = 1
    112 c = f;
    113 f = HT[f].parent;//继续向上回溯
    114 }
    115 HC[i] = new char[n - start];//为第i个字符编码分配空间
    116 strcpy(HC[i], &cd[start]);//把求得编码的首地址从cd[start]复制到HC的当前行中
    117 }
    118 delete cd;
    119 }
    120
    121 //哈夫曼译码
    122 void TranCode(HuffmanTree HT,char a[],char zf[],char b[],int n)
    123 {
    124 /

    125 HT是已经创建好的哈夫曼树
    126 a[]用来传入二进制编码
    127 b[]用来记录译出的字符
    128 zf[]是与哈夫曼树的叶子对应的字符(叶子下标与字符下标对应)
    129 n是字符个数,相当于zf[]数组得长度
    130 /
    131
    132 int q = 2*n-1;//q初始化为根结点的下标
    133 int k = 0;//记录存储译出字符数组的下标
    134 int i = 0;
    135 for (i = 0; a[i] != '\0';i++)
    136 {//for循环结束条件是读入的字符是结束符(二进制编码)
    137 //此代码块用来判断读入的二进制字符是0还是1
    138 if (a[i] == '0')
    139 {/
    读入0,把根结点(HT[q])的左孩子的下标值赋给q
    140 下次循环的时候把HT[q]的左孩子作为新的根结点*/
    141 q = HT[q].lchild;
    142 }
    143 else if (a[i] == '1')
    144 {
    145 q = HT[q].rchild;
    146 }
    147 //此代码块用来判断HT[q]是否为叶子结点
    148 if (HT[q].lchild == 0 && HT[q].rchild == 0)
    149 {/*是叶子结点,说明已经译出一个字符
    150 该字符的下标就是找到的叶子结点的下标*/
    151 b[k++] = zf[q];//把下标为q的字符赋给字符数组b[]
    152 q = 2 * n - 1;//初始化q为根结点的下标
    153 //继续译下一个字符的时候从哈夫曼树的根结点开始
    154 }
    155 }
    156 /*译码完成之后,用来记录译出字符的数组由于没有结束符输出的
    157 时候回报错,故紧接着把一个结束符加到数组最后*/
    158 b[k] = '\0';
    159 }
    160 //菜单函数
    161 void menu()
    162 {
    163 cout << endl;
    164 cout << " ┏〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓┓" << endl;
    165 cout << " ┃ ★★★★★★★哈夫曼编码与译码★★★★★★★ ┃" << endl;
    166 cout << " ┃ 1. 创建哈夫曼树 ┃" << endl;
    167 cout << " ┃ 2. 进行哈夫曼编码 ┃" << endl;
    168 cout << " ┃ 3. 进行哈夫曼译码 ┃" << endl;
    169 cout << " ┃ 4. 退出程序 ┃" << endl;
    170 cout << " ┗〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓┛" << endl;
    171 cout << " <><注意:空格字符用'- '代替><>" << endl;
    172 cout << endl;
    173 }
    174 void main()
    175 {
    176 int falg;//记录要编码的字符个数
    177 char a[MAX_MA];//储存输入的二进制字符
    178 char b[MAX_ZF];//存储译出的字符
    179 char zf[MAX_ZF];//储存要编码的字符
    180 HuffmanTree HT = NULL;//初始化树为空数
    181 HuffmanCode HC = NULL;//初始化编码表为空表
    182 menu();
    183 while (true)
    184 {
    185 int num;
    186 cout << "<><请选择功能(1-创建 2-编码 3-译码 4-退出)><>: ";
    187 cin >> num;
    188 switch (num)
    189 {
    190 case 1 :
    191 cout << "<><请输入字符个数><>:";
    192 cin >> falg;
    193 //动态申请falg个长度的字符数组,用来存储要编码的字符
    194 /*char zf = new char[falg];/
    195 cout << "<><请依次输入" << falg << "个字符:><>: ";
    196 for (int i = 1; i <= falg; i++)
    197 cin >> zf[i];
    198 cout << "<><请依次输入" << falg << "个字符的权值><>: ";
    199 CreateHuffmanTree(HT, falg);//调用创建哈夫曼树的函数
    200 cout << endl;
    201 cout << "<><创建哈夫曼成功!,下面是该哈夫曼树的参数输出><>:" << endl;
    202 cout << endl;
    203 cout << "结点i"<<"\t"<<"字符" << "\t" << "权值" << "\t" << "双亲" << "\t" << "左孩子" << "\t" << "右孩子" << endl;
    204 for (int i = 1; i <= falg * 2 - 1; i++)
    205 {
    206 cout << i << "\t"< 207 }
    208 cout 209 break;
    210 case 2:
    211 CreatHuffmanCode(HT, HC, falg);//调用创建哈夫曼编码表的函数
    212 cout 213 cout <生成哈夫曼编码表成功!,下面是该编码表的输出><>:" << endl;
    214 cout << endl;
    215 cout << "结点i"<<"\t"<<"字符" << "\t" << "权值" << "\t" << "编码" << endl;
    216 for (int i = 1; i <= falg; i++)
    217 {
    218 cout << i << "\t"< 219 }
    220 cout 221 break;
    222 case 3:
    223 cout <请输入想要翻译的一串二进制编码><>:";
    224 /*这样可以动态的直接输入一串二进制编码,
    225 因为这样输入时最后系统会自动加一个结束符*/
    226 cin >> a;
    227 TranCode(HT, a, zf, b, falg);//调用译码的函数,
    228 /*这样可以直接把数组b输出,因为最后有
    229 在数组b添加输出时遇到结束符会结束输出*/
    230 cout << endl;
    231 cout << "<><译码成功!翻译结果为><>:" << b << endl;
    232 cout << endl;
    233 break;
    234 case 4:
    235 cout << endl;
    236 cout << "<><退出成功!><>" << endl;
    237 exit(0);
    238 default:
    239 break;
    240 }
    241 }
    242

    243 //-abcdefghijklmnopqrstuvwxyz
    244 //186 64 13 22 32 103 21 15 47 57 1 5 32 20 57 63 15 1 48 51 80 23 8 18 1 16 1
    245 //000101010111101111001111110001100100101011110110
    246
    247 }

    评论

报告相同问题?

悬赏问题

  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?