求能建立最优二叉树函数,并且可以建立函数输入二叉树,并输出其哈夫曼树的源代码!以下供参考

Scofield_zao 2009-01-05 05:44:13


#include <stdio.h>

#include <iostream.h>

typedef int ElemType;

#include "Haffman.h"

void main()

{

int n,i;

BTreeNode *fbt=NULL;

cout<<"输入待构造的哈夫曼树中带权叶子结点数n:";

cin>>n;

ElemType *a=new ElemType[n];

cout<<"输入"<<n<<"个整数作为权值:";

for(i=0;i<n;i++)

cin>>a[i];

fbt=CreatHuffman(a,n);

cout<<"构造的哈夫曼树为:"<<endl;

PrintBTree(fbt,n);

cout<<"树中每个叶子的哈夫曼编码:"<<endl;

HuffManCoding(fbt,0);

}

Haffman.h:

struct BTreeNode{

ElemType data;

BTreeNode *left;

BTreeNode *right;

};

BTreeNode *CreatHuffman(ElemType a[],int n) //构造哈夫曼树

{

BTreeNode **b,*q;

b=new BTreeNode*[n];

int i,j;

for(i=0;i<n;i++){

b[i]=new BTreeNode;

b[i]->data=a[i];

b[i]->left=b[i]->right=NULL;

}

for(i=1;i<n;i++){

int k1=-1,k2;

for(j=0;j<n;j++){

if(b[j]!=NULL&&k1==-1){

k1=j;

continue;

}

if(b[j]!=NULL){

k2=j;

break;

}

}

for(j=k2;j<n;j++){

if(b[j]!=NULL){

if(b[j]->data<b[k1]->data){

k2=k1;

k1=j;

}

else if(b[j]->data<b[k2]->data)

k2=j;

}

}

q=new BTreeNode;

q->data=b[k1]->data+b[k2]->data;

q->left=b[k1];

q->right=b[k2];

b[k1]=q;

b[k2]=NULL;

}

delete []b;

return q;

}

void PrintBTree(BTreeNode *BT,int n) //以广义表形式输出哈夫曼树

{

int i;

if(BT!= NULL){

PrintBTree(BT->right,n+1);

for(i=0;i<n-1;i++)

cout<<" ";

if(n>0)

cout<<"--";

cout<<BT->data<<endl;

PrintBTree(BT->left,n+1);

}

}

void HuffManCoding(BTreeNode *BT, int len) //求哈夫曼编码

{

static int a[10];

if(BT!=NULL){

if(BT->left==NULL&&BT->right==NULL){

cout<<"结点权值为"<<BT->data<<"的编码:";

for(int i=0;i<len;i++)

cout<<a[i]<<' ';

cout<<endl;

}

else{

a[len]=0;

HuffManCoding(BT->left, len+1);

a[len]=1;

HuffManCoding(BT->right, len+1);

}

}

}

...全文
982 19 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
belinda814 2010-01-22
  • 打赏
  • 举报
回复
谢谢啦!~~~
wohaoa 2009-06-23
  • 打赏
  • 举报
回复
丿
Scofield_zao 2009-01-06
  • 打赏
  • 举报
回复
回家咯,结分去了!
Scofield_zao 2009-01-05
  • 打赏
  • 举报
回复
好的,谢谢楼上的啊
感谢大家的支持撒!
就呆在云上 2009-01-05
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct hufftree hnode, *phtree;
struct hufftree{
int a;
phtree ltree;
phtree rtree;

};


void min_smin(const hnode *buffer,const int size, int *secondmin, int *min)
{
if(size <= 1)
return;
*min = buffer[0].a;
*secondmin = 101;
for(int i = 1;i < size;i++)
{
if(buffer[i].a <= *min)
{
*secondmin = *min;
*min = buffer[i].a;
}
else if (buffer[i].a < *secondmin)
*secondmin = buffer[i].a;
}
}


/*
这个霍夫曼的设计,就是先找到最小的两个节点,对于第一个我们仅仅是复制一个节点
对于第二小的数的节点,我们复制一个一样的节点,同时把复制的两个节点作为第二小
的原始节点的左右子树,同时把原始节点的大小修改为最小的两个节点值的和!

中间我们101作为访问过的节点的值,因为我们的霍夫曼树中每一个节点之后才是100,
也就是应该小于100,用101适合做标记。

同时我们使用一个last最为最后的一个节点的索引,因为最后的一个节点已经是最终的
树了,最后用tree参数复制最后的一个节点。
*/
void creat_huff(hnode buffer[],int size, phtree tree) {
int insize = size;
int smin, min;
int j = 0, count = 0;
int last = 0;
phtree node1, node2;
while(1 < insize) {
//求最小的两个数
min_smin(buffer, size, &smin, &min);
while(j < size) {
if(buffer[j].a == smin || buffer[j].a == min) {
if(count == 0) {
node1 = new hnode;
// make a copy of a min node
node1->a = buffer[j].a;
node1->ltree = buffer[j].ltree;
node1->rtree = buffer[j].rtree;
buffer[j].a = 101;
count++;
}
else if(count == 1){
node2 = new hnode;
// make a copy of a min node
node2->a = buffer[j].a;
node2->ltree = buffer[j].ltree;
node2->rtree = buffer[j].rtree;

//然后把node1和node2都附在buffer[j]上作为左右子树!
buffer[j].a = min+smin;
buffer[j].ltree = node1;
buffer[j].rtree = node2;
count = 0;
last = j;
break;
}
}
j++;
}
insize--, j = 0;
}

//复制最后一个节点
tree->a = buffer[last].a;
tree->ltree = buffer[last].ltree;
tree->rtree = buffer[last].rtree;
}

//用后序删除,因为这里用的引用传入参数,如果用前序或者中序的话
//释放了tree,那么他的左右子树不可知了,而且也不为0一般的情况下。
void freehuff(phtree &tree) {
if(tree) {
freehuff(tree->ltree);
freehuff(tree->rtree);
delete tree;
}
}

int main(){
hnode a[7];
for(int i = 0; i < 7; i++)
{
a[i].a = i+5;
a[i].ltree = a[i].rtree = NULL;
}
phtree newtree = new hnode;
creat_huff(a, 7, newtree);
freehuff(newtree);
return 0;
}


写的要死,可以满足不?
萧霖 2009-01-05
  • 打赏
  • 举报
回复
up 学习
baihacker 2009-01-05
  • 打赏
  • 举报
回复
自己建立一个,然后copy进去就OK了.
代码是VC6的...很多不标准,可能编译不过,自己改一下.
Scofield_zao 2009-01-05
  • 打赏
  • 举报
回复
在VC++ 2005 express edition 中怎么建立#include "Huffman.h"的头文件啊
并在"Huffman.h"包含一些什么其他头文件?
baihacker 2009-01-05
  • 打赏
  • 举报
回复
#include "Huffman.h"
#include "windows.h"


void show_info()
{
cout<<"==============================Huffman树显示程序=============================="<<endl;
cout<<"\t1.对文件进行编码\t\t2.对文件进行解码\t"<<endl;
cout<<"\t3.对指定字符进行编码\t\t4.退出程序"<<endl;
}

int get_cmd()
{
int i;
for(;;)
{
cout<<"请输入命令:";
cin>>i;
if (i<1||i>4)
cout<<"错误的命令!"<<endl;
else
break;
}
return i;
}

void exe_1();
void exe_2();
void exe_3();

int main()
{
int cmd;
for (;;)
{
show_info();
cmd = get_cmd();
if (cmd==4)
{
cout<<"谢谢使用!"<<endl;
Sleep(1000);
return 1;
}

switch (cmd)
{
case 1:
exe_1();break;
case 2:
exe_2();break;
case 3:
exe_3();break;
}
}
return 0;

}

void exe_1()
{
char filenames[256], filenamed[256];
cout<<"请输入文件名:";
cin>>filenames;

Huffman h;
h.LoadCharSet();
cout<<"数据装入中..."<<endl;
if (!h.CreateHuffmanTreeFromFile(filenames))
{
cout<<"装入文件出错,可能有未知的符!"<<endl;
return;
}
h.ShowCode();//显示编码

cout<<"请输入目标文件名:";
cin>>filenamed;
cout<<"数据写入中..."<<endl;
if (!h.CreateHuffmanTreeFromFile(filenames)||!h.EnCode(filenames,filenamed))
{
cout<<"文件编码出错!"<<endl;
return;
}
else
cout<<"文件编码成功!"<<endl;

cout<<"为你的编码文件输入一个编码对照文件名:";
cin>>filenamed;
if (!SaveAs(filenamed,h))
{
cout<<"写入文件出错!"<<endl;
return;
}
else
{
cout<<"编码对照文件写入文件成功!"<<endl;
return;
}

}

void exe_2()
{
char filename1[256], filename2[256];

cout<<"请输入编码对照文件名:";
cin>>filename1;

Huffman h;

if(!LoadFrom(filename1,h))
{
cout<<"装入编码对照文件出错!"<<endl;
return;
}

cout<<"请输入编码文件名:";
cin>>filename1;

cout<<"请输入目标文件名:";
cin>>filename2;

if(!h.DeCode(filename1,filename2))
{
cout<<"解码出错!"<<endl;
return;
}
else
{
cout<<"解码成功!"<<endl;
return;
}
}

void exe_3()
{
char c[128];
int w[128];
int n, i;

cout<<"请输入字符数:";
cin>>n;
if (n>128)
{
cout<<"字符数太多!"<<endl;
return;
}

for (i=0;i<n;i++)
{
cout<<"请输入第"<<i+1<<"个字符:"<<endl;
cin>>c[i];
}

for (i=0;i<n;i++)
{
cout<<"请输入第"<<i+1<<"个字符的权重:"<<endl;
cin>>w[i];
}
Huffman h;
h.LoadCharSet(c,n);
h.LoadWeight(w,n);
h.CreateHuffmanTreeFromData();
h.ShowCode();
}
baihacker 2009-01-05
  • 打赏
  • 举报
回复


#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;

#ifndef HUFFMAN_H
#define HUFFMAN_H
//下面的不符合标准,应该加上int
const N = 128;
const MAX_WEIGHT = 888888888;//最大权,如果不保险可以设为-1然后修改函数Huffman::select
const MAX_CHAR_LENGTH = 16;

typedef struct{
char HfmCode[MAX_CHAR_LENGTH];
char ch;
}code, *HuffmanCode;

typedef struct
{
unsigned int weight; /* 用来存放各个结点的权值*/
char ch;
unsigned int parent, LChild, RChild ; /*指向双亲、孩子结点的指针*/
}HTNode, * HuffmanTree; /*动态分配数组,存储哈夫曼树*/

/*类的使用说明:
1.定义一个对象;
2.如果是统计文件里所有的字符并对其进行编码的话
直接使用函数CreateHuffmanTreeFromFile从文件载
入,字符集为ASCII码,即0-127;
如果是对指定字符集进行编码的话,使用函数LoadCharSet
载入字符集,如果没有参数的话会自动载入ASCII码字符集
然后使用LoadWeight载入权重;
3.如果不是从文件载入则调用CreateHuffmanTreeFromData
生成Huffman树,并且生成相应编码,而从文件载入的话就会
自动生成Huffman树
4.EnCode对文件进行编码,如果遇到不认识的字符,则报错;
5.DeCode对文件进行解码,如果在EnCode中曾经跳过不认识的
字符,则不能成功解码,并且不会报错,后果不可预料;
6.ShowCode显示字符和对应编码
如果只是定义一个对象然后调用的话,后果不可预测;
7.WeightTest进行文件权重测试,载入一个文件,然后显示各
个字符的数目;
8.SaveAs可以把一个Huffman对象保存到一个文件;
9.LoadFrom可以从一个文件载入Huffman对象,但是不能进行
合法性判断,所以如果载入的是非SaveAs生成的对象,那么
后果很严重.
*/

class Huffman
{

int CHAR_NUM;//字符集的数目

int w[N+1]; /*各字符的权重*/
char st[N+1]; /* 字符集,和st[i]和s[i]对应,由于是只对字母进行编码,所以在 实际运行中没有起作用*/
HTNode ht[2*N];//树
code hc[N+1];//编码
bool CreateWeightFromFile(char*);//根据文件得到各字符的权重
void CreateHuffmanTree();
void select(int n, int *s1, int *s2);
void CreateHuffmanCode();//根据树求编码
int findcode(char ch);
public:
Huffman();
void LoadCharSet();//设置字符集为asc字符
void LoadCharSet(char*,int n);//设置字符集为指定字符
bool LoadWeight(int*,int);//装入数据

bool CreateHuffmanTreeFromData();//从本身数据创建H树
bool CreateHuffmanTreeFromFile(char*);//由一个文件创建H树

void ShowCode();//显示编码

bool EnCode(char*,char*);//根据当前数据,对文件进行编码
bool DeCode(char*,char*);//根据当前数据,对文件进行解码

void WeightTest(char*);//测试函数,调试中用的
};

Huffman::Huffman()
{
for (int i=1;i<=128;w[i++]=0);
}

void Huffman::LoadCharSet()//设置 字符集为asc字符集
{
for (int i=1;i<=128;hc[i].ch=st[i]=i-1,i++);
CHAR_NUM = 128;
}

void Huffman::LoadCharSet(char* c,int n)
{
for (int i=1;i<=n;hc[i].ch=st[i]=c[i-1],i++);
CHAR_NUM = n;
}

bool Huffman::CreateHuffmanTreeFromData()
{
CreateHuffmanTree();
CreateHuffmanCode();
return true;
}

bool Huffman::LoadWeight(int* wt,int n)
{
if (n!=CHAR_NUM)
return false;
for (int i=1;i<=n;w[i]=wt[i-1],i++);
return true;
}

bool Huffman::CreateWeightFromFile(char* fn)
{
fstream f;

f.open(fn,ios::in|ios::binary);
if (!f)
return false;

char t[2];
int i;
while (!f.eof())
{
f.read(t,1);
if (f.gcount()==1)
{
i = findcode(t[0]);
if (i!=0)
w[i]++;
else
return false;
}
}
f.close();
return true;
}

void Huffman::WeightTest(char* fn)
{
if (CreateWeightFromFile(fn))
for (int i=1;i<=CHAR_NUM;i++)
cout<<st[i]<<":\t"<<w[i]<<endl;
}

void Huffman::select(int n, int *s1, int *s2)
{ /*ht,为树所在数组的头指针,n为允许查找的最大序号,s1,s2,返回最小的两个序号*/
int p1=MAX_WEIGHT;
int p2=MAX_WEIGHT; /*p1, p2用来记录最小的两个权, 要求p1<p2*/
int pn1=0;
int pn2=0, i; /*pn1, pn2 用来记录这两个权的序号*/
for (i=1;i<=n;i++)
if (ht[i].weight<p1 && ht[i].parent==0)
{/*如果当前结点的权比p1小,那么p2的权赋为p1的权, p1的权为当前权,同时修改n1, pn2*/
/*查找的结点要求没有父结点*/
pn2=pn1;
p2=p1;
p1=ht[i].weight;
pn1=i;
}
else
if (ht[i].weight<p2 &&ht[i].parent==0)
{/*如果当前结点的权比p2小(由第一个if,当前权不比p1小),那么p2的权赋为当前权,同时修改pn2*/
p2=ht[i].weight;
pn2=i;
}
*s1=pn1;
*s2=pn2; /*赋值返回*/
}

void Huffman::CreateHuffmanTree()
{ /* w存放已知的n个权值,构造哈夫曼树ht */
/*由于是用数组的结构来存储树,故ht放的是数组的头指针*/
int m,i;
int s1, s2; /*在select函数中使用,用来存储最小权的结点的序号*/
m=2*CHAR_NUM-1;
for (i=1;i<=CHAR_NUM;i++)
{/*1-n号放叶子结点,初始化*/
ht[i].weight = w[i];
ht[i].ch=st[i];
ht[i].LChild = 0;
ht[i].parent = 0;
ht[i].RChild = 0;
}

for (i=CHAR_NUM+1;i<=m;i++)
{
ht[i].weight = 0;
ht[i].LChild = 0;
ht[i].parent = 0;
ht[i].RChild = 0;
} /*非叶子结点初始化*/
/* ------------初始化完毕!对应算法步骤1---------*/

for (i=CHAR_NUM+1;i<=m;i++) /*创建非叶子结点,建哈夫曼树*/
{ /*在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋值给s1、s2返回*/
select(i-1,&s1,&s2);
ht[s1].parent=i;
ht[s2].parent=i; /*设置这两个最小的权的结点的父结点为i*/
ht[i].LChild=s1;
ht[i].RChild=s2; /*设置这个父结点的子结点*/
ht[i].weight=ht[s1].weight+ht[s2].weight; /*设置这个父结点权*/
}
}/*哈夫曼树建立完毕*/

void Huffman::CreateHuffmanCode()
/*从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码*/
{
char cd[MAX_CHAR_LENGTH];
int i;
unsigned int c;
int start;
int p;
cd[MAX_CHAR_LENGTH-1]='\0'; /*从右向左逐位存放编码,首先存放编码结束符*/
for (i=1;i<=CHAR_NUM;i++) /*求n个叶子结点对应的哈夫曼编码*/
{
hc[i].ch=ht[i].ch;
start=MAX_CHAR_LENGTH-1;

for (c=i,p=ht[i].parent; p!=0; c=p,p=ht[p].parent) /*从叶子到根结点求编码*/
if (ht[p].LChild == c)
cd[--start]='0'; /*左分支标0*/
else
cd[--start]='1'; /*右分支标1*/
/*for循环结点条件为 *p=0表示c是根结点了,而每循环一次又由cd[--start]倒序记录了
每一步是父结点的左或右结点,也就是形成了H编码,并放在cd中*/

strcpy(hc[i].HfmCode,&cd[start]);
}
}

bool Huffman::CreateHuffmanTreeFromFile(char* fn)
{
if (!CreateWeightFromFile(fn))
return false;
CreateHuffmanTree();
CreateHuffmanCode();
return true;
}

void Huffman::ShowCode()
{
for (int i=1;i<=CHAR_NUM;i++)
{
cout<<hc[i].ch<<":\t"<<hc[i].HfmCode<<endl;
}
}

int Huffman::findcode(char ch)
{
int i;
for (i=1;i<=CHAR_NUM;i++)
if (st[i]==ch)
return i;
return 0;
}

bool Huffman::EnCode(char* fs, char* fd)
{
fstream rf;
fstream wf;
rf.open(fs,ios::in|ios::binary);
wf.open(fd,ios::out|ios::binary);
if (!rf||!wf)
return false;

char ch[2];
int num;

while (!rf.eof())
{
rf.read(ch,1);
if (rf.gcount()==1)
{
ch[1] = 0;
num=findcode(ch[0]);
if (num!=0)
wf.write(hc[num].HfmCode, strlen(hc[num].HfmCode));
else
return false;
}
}
rf.close();
wf.close();
return true;
}

bool Huffman::DeCode(char* fs, char* fd)
{
char cha[2];
HTNode p=ht[2*CHAR_NUM-1]; /*p为根结点*/
fstream rf,wf;

rf.open(fs,ios::in|ios::binary);
wf.open(fd,ios::out|ios::binary);
if (!fs||!wf)
return false;

while (!rf.eof()) /*译码段*/
{
rf.read(cha,1);
//if (rf.gcount()==1)
//{要多读入一次对最后一个字符进行解码
if (p.LChild!=0 || p.RChild!=0)/*如果p有子结点*/
{
if (cha[0]=='0' && p.LChild!=0)
p=ht[p.LChild]; /*如果读出的字符为0,p的左结点不为空p指向p的左结点*/
else
if (cha[0]=='1' && p.RChild!=0)
p=ht[p.RChild];/*如果读出的字符为1,p的右结点不为空p指向p的右结点*/
}
else
{
wf.write((char*)&p.ch,1);
p=ht[2*CHAR_NUM-1]; /*重新让p指向根结点*/
if (cha[0]=='0' && p.LChild!=0) /*同上面*/
p=ht[p.LChild];
else
if (cha[0]=='1' && p.RChild!=0)
p=ht[p.RChild];
}
//}
}
rf.close();
return true;
}

bool SaveAs(char* fn, Huffman& h)//把对象存入一个文件
{
fstream f;
f.open(fn,ios::out|ios::binary);
if (!f)
return false;
f.write((char*)&h, sizeof(h));
f.close();
return true;
}

bool LoadFrom(char* fn, Huffman& h)//从文件读入对象数据
{
fstream f;
f.open(fn,ios::in|ios::binary);
if (!f)
return false;
f.read((char*)&h, sizeof(h));
f.close();
return true;
}

#endif
帅得不敢出门 2009-01-05
  • 打赏
  • 举报
回复
up
xiaoyisnail 2009-01-05
  • 打赏
  • 举报
回复
up
Scofield_zao 2009-01-05
  • 打赏
  • 举报
回复
是滴呀!
Scofield_zao 2009-01-05
  • 打赏
  • 举报
回复
请大家来指教指教,
求能建立最优二叉树函数,并且可以建立函数输入二叉树,并输出其哈夫曼树的源代码!以上代码供参考
davelv 2009-01-05
  • 打赏
  • 举报
回复
看来楼主还没有学会code标签的使用...

//此处是C/C++代码
waizqfor 2009-01-05
  • 打赏
  • 举报
回复
LZ什么意思? 晒代码?
学习学习
OenAuth.Core 2009-01-05
  • 打赏
  • 举报
回复
UP
genius_tong 2009-01-05
  • 打赏
  • 举报
回复
up
davelv 2009-01-05
  • 打赏
  • 举报
回复
我的blog上最新一篇是关于huffman压缩的,注释还比较全面,楼主感兴趣的话可以去看看

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧