求助C语言编写哈夫曼树

qerqerqer 2010-05-22 05:55:42
在源代码基础上,要求编程一段程序,实现:
1.画出Huffman树
2.求与等长编码相比时的压缩比

#include <dos.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{unsigned int weight; //结点权值
unsigned int parent,lchild,rchild; //结点的父指针,左右孩子指针
}HTNode,*HuffmanTree; //动态分配数组存储哈夫曼树
typedef char **HuffmanCode; //动态分配数组存储哈夫曼编码表
void CreateHuffmanTree(HuffmanTree &,unsigned int*,int ); //生成哈夫曼树
void HuffmanCoding(HuffmanTree,HuffmanCode &,int ); //对哈夫曼树进行编码
void PrintHuffmanCode(HuffmanCode,unsigned int*,int); //显示哈夫曼编码
void Select(HuffmanTree,int,int&,int&); //在数组中寻找权值最小的两个结点
void main()
{HuffmanTree HT; //哈夫曼树HT
HuffmanCode HC; //哈夫曼编码表HC
int n,i; //n是哈夫曼树叶子结点数
unsigned int *w; //w存放叶子结点权值
char j='y';
//程序解说
printf("演示构造哈夫曼树.\n");
printf("输入需要进行编码的字符数目.\n例如:8\n");
printf("然后输入每个字符出现的次数/权值.\n");
printf("例如:5 29 7 8 14 23 3 11\n");
printf("自动构造一棵哈夫曼树并显示哈夫曼编码.\n");
printf(" 5---0110\n 29---10\n 7---1110\n 8---1111\n 14---110\n");
printf(" 23---00\n 3---0111\n 11---010\n");
while(j!='N'&&j!='n')
{printf("请输入字符数目:");
scanf("%d",&n); //输入字符数目
if(n<=1) {printf("该数不合理!\n");continue;}
w=(unsigned int*)malloc(n*sizeof(unsigned int)); //开辟空间存放权值
printf("请输入各字符出现的次数/权值:\n");
for(i=0;i<n;i++) scanf("%d",&w[i]); //输入各字符出现的次数/权值
CreateHuffmanTree(HT,w,n); //生成哈夫曼树
HuffmanCoding(HT,HC,n); //进行哈夫曼编码
PrintHuffmanCode(HC,w,n); //显示哈夫曼编码
printf("哈夫曼树构造完毕,还要继续吗?(Y/N)");
scanf(" %c",&j);
}
}

void CreateHuffmanTree(HuffmanTree &HT,unsigned int *w,int n)
{//w存放n个结点的权值,将构造一棵哈夫曼树HT
int i,m;
int s1,s2;
HuffmanTree p;
if(n<=1) return;
m=2*n-1; //n个叶子结点的哈夫曼树,有2*n-1个结点
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); //开辟2*n各结点空间
for(p=HT+1,i=1;i<=n;++i,++p,++w) //进行初始化
{p->weight=*w;
p->parent=0;
p->lchild=0;
p->rchild=0;
}
for(;i<=m;++i,++p)
{p->weight=0;
p->parent=0;
p->lchild=0;
p->rchild=0;
}
for(i=n+1;i<=m;++i) //建哈夫曼树
{Select(HT,i-1,s1,s2);
//从HT[1...i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
HT[s1].parent=i; HT[s2].parent=i; //修改s1和s2结点的父指针parent
HT[i].lchild=s1; HT[i].rchild=s2; //修改i结点的左右孩子指针
HT[i].weight=HT[s1].weight+HT[s2].weight; //修改权值
}
}
void HuffmanCoding(HuffmanTree HT,HuffmanCode &HC,int n)
{//将有n个叶子结点的哈夫曼树HT进行编码, 所编的码存放在HC中
//方法是从叶子到根逆向求每个叶子结点的哈夫曼编码
int i,c,f,start;
char *cd;
HC=(HuffmanCode)malloc((n+1)*sizeof(char *)); //分配n个编码的头指针向量
cd=(char *)malloc(n*sizeof(char)); //开辟一个求编码的工作空间
cd[n-1]='\0'; //编码结束符
for(i=1;i<=n;++i) //逐个地求哈夫曼编码
{start=n-1; //编码结束位置
for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent) //从叶子到根逆向求编码
if(HT[f].lchild==c) cd[--start]='0'; //若是左孩子编为'0'
else cd[--start]='1'; //若是右孩子编为'1'
HC[i]=(char *)malloc((n-start)*sizeof(char)); //为第i个编码分配空间
strcpy(HC[i],&cd[start]); //将编码从cd复制到HC中
}
free(cd); //释放工作空间
}
void PrintHuffmanCode(HuffmanCode HC,unsigned int *w,int n)
{//显示有n个叶子结点的哈夫曼树的编码表
int i;
printf("HuffmanCode is :\n");
for(i=1;i<=n;i++)
{printf(" %3d---",w[i-1]);
puts(HC[i]);
}
printf("\n");
}
void Select(HuffmanTree HT,int t,int&s1,int&s2)
{//在HT[1...t]中选择parent不为0且权值最小的两个结点,其序号分别为s1和s2
int i,m,n;
m=n=10000;
for(i=1;i<=t;i++)
{if(HT[i].parent==0&&(HT[i].weight<m||HT[i].weight<n))
if(m<n)
{n=HT[i].weight;s2=i;}
else {m=HT[i].weight;s1=i;}

}
if(s1>s2) //s1放较小的序号
{i=s1;s1=s2;s2=i;}
}
...全文
1451 3 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
zsc2010 2010-05-23
  • 打赏
  • 举报
回复
哈夫曼树是 算法?
chaoliu1024 2010-05-22
  • 打赏
  • 举报
回复
再给一个
#include <iostream>   
#include <stdlib.h>
#include <string.h>
using namespace std;

class HuffmanNode
{
private:
// char ch;
unsigned int weight;
unsigned int parent,lchild,rchild;
public:
HuffmanNode();
void SetChild(unsigned,unsigned,unsigned);
void SetParent(unsigned);
unsigned GetParent();
unsigned GetLchild();
void SetWeight(unsigned);
unsigned GetWeight();

};

class HuffmanCoding
{
private:
HuffmanNode* HuffmanTree;
int n;
char** HuffmanCode;
public:
HuffmanCoding(int,int*);
~HuffmanCoding();
void Coding();
void Print(char*);

};

// Implement of class HuffmanNode--------------------------------------------
HuffmanNode::HuffmanNode() {weight = parent = lchild = rchild = 0;}

void HuffmanNode::SetChild(unsigned l,unsigned r,unsigned w)
{
lchild = l;
rchild = r;
weight = w;
}

void HuffmanNode::SetParent(unsigned p) {parent = p; }

unsigned HuffmanNode::GetWeight() {return weight; }

void HuffmanNode::SetWeight(unsigned w) {weight = w; }

unsigned HuffmanNode::GetParent() {return parent;}

unsigned HuffmanNode::GetLchild() {return lchild;}


// Implement of class HuffmanCoding------------------------------------------
HuffmanCoding::HuffmanCoding(int _n,int* w)
{
n = _n;
if(!(HuffmanTree = new HuffmanNode[2*n-1])){
cout<<"Out of memory!"<<endl;
exit(1);
}
for(int i=0;i<n;i++)
HuffmanTree[i].SetWeight(w[i]);
}

HuffmanCoding::~HuffmanCoding()
{
delete[] HuffmanTree;
for(int i=0;i<n;i++)
delete[]HuffmanCode[i];
n = 0;
}

void HuffmanCoding::Coding()
{
int i,j;
int s1=0,s2=0;
unsigned w1,w2;

// Create Huffman Tree
for(i=n;i<2*n-1; i++){
w1 = w2 = 65536;
s1 = s2 = 0;
for(j=0;j<i;j++){
if(!HuffmanTree[j].GetParent()){
unsigned tmp = HuffmanTree[j].GetWeight();
if(tmp>=w1&&tmp<w2){w2 = tmp;s2 = j;}
if(tmp<w1){
w2 = w1; s2 = s1;
w1 = tmp; s1 = j;
}
}
}

HuffmanTree[s1].SetParent(i);
HuffmanTree[s2].SetParent(i);
HuffmanTree[i].SetChild(s1,s2,w1+w2);
}

// Coding...
int start,c,f;
HuffmanCode = new char*[n];
char* cd = new char[n];
cd[n-1] = '\0';

for(i=0;i<n;i++){
start = n-1;
for(c=i,f=HuffmanTree[i].GetParent();f!=0;c=f,f=HuffmanTree[f].GetParent())
if(HuffmanTree[f].GetLchild()==c) cd[--start]='0';
else cd[--start] = '1';
HuffmanCode[i] = new char[n-start];
strcpy(HuffmanCode[i],&cd[start]);
}
delete cd;
}

void HuffmanCoding::Print(char* s)
{
for (int i=0;i<n;i++)
cout<<s[i]<<":"<<HuffmanCode[i]<<"\n";
}


int main()
{
cout<<"* *"<<endl;
cout<<"* *"<<endl;
cout<<"* 班级: *"<<endl;
cout<<"* 学号: *"<<endl;
cout<<"* 姓名: *"<<endl;
cout<<"* *"<<endl;
cout<<"* *"<<endl;
char s[] = {'a','b','c','d','f','g','h','i'};
int weight[] = {10,20,5,15,25,10,10,5};

HuffmanCoding hc(8,weight);
hc.Coding();
hc.Print(s);

return 0;
}
chaoliu1024 2010-05-22
  • 打赏
  • 举报
回复
网上找的代码,楼主参考下
#include <iostream.h> 
#include <stdio.h>
#include <string.h>
const long wordnum = 1000;//最大不同单词数
const long code_len = wordnum/10;
const long wordlen = 30;//单词最长长度
const long codemax = 10000;//最大haffuman编码长度
const long wordmax = 10000;//最大单词数
//str类定义
class str
{
public:
str();
bool operator<(str obj);//运算符重载方便对str的排序使用二分搜索模板
bool operator>(str obj);
str operator=(char p[]);
str operator++(int);//重载后缀方式的++
char *getword();
long getfre();
protected:
private:
char word[wordlen];
long frequence;
};
str::str()
{
frequence = 0;
}
//以下为重载str类中的运算符
bool str::operator<(str obj)
{
if(strcmp(word,obj.word) < 0)
return true;
else
return false;
}
bool str::operator>(str obj)
{
if(strcmp(word,obj.word) > 0)
return true;
else
return false;
}
str str::operator=(char p[])
{
strcpy(word,p);
return *this;
}
str str::operator++(int x)
{
frequence ++;
return *this;
}
char * str::getword()
{
return word;
}
long str::getfre()
{
return frequence;
}
//str类定义结束

//Node类定义
class Node
{
public:
Node();
bool operator<(Node obj);//运算符重载方便对Node的排序使用堆模板
bool operator<=(Node obj);
bool operator>(Node obj);
Node operator=(str obj);
Node operator+(Node &obj);
Node *leftp();//类外获取指向当前节点的孩子的指针
Node *rightp();
char *getword(Node *p);//类外获取节点信息
long getfrequence();
protected:
private:
char word[wordlen];
long frequence;
Node *left, *right;
};

Node::Node()
{
strcpy(word,"NULL");
left = NULL;
right = NULL;
}
//以下为重载Node类中的运算符
bool Node::operator<(Node obj)
{
if(frequence < obj.frequence)
return true;
else
return false;
}
bool Node::operator<=(Node obj)
{
if(frequence <= obj.frequence)
return true;
else
return false;
}
bool Node::operator>(Node obj)
{
if(frequence > obj.frequence)
return true;
else
return false;
}
Node Node::operator+(Node &obj)
{
Node sum;
sum.frequence = frequence + obj.frequence;//指针指向了NULL
sum.left = this;
sum.right = &obj;
return sum;
}
Node Node::operator=(str obj)
{
strcpy(word,obj.getword());
frequence = obj.getfre();
return *this;
}
Node * Node::leftp()
{
return left;
}
Node * Node::rightp()
{
return right;
}
char * Node::getword(Node *p)
{
return p->word;
}
long Node::getfrequence()
{
return frequence;
}
//Node类定义结束

//str类专门用于统计词频使用,Node则用于构造huffman树,由于两者使用的key不同,前者是word的字典序
//后者是词频,于是使用了两个类来实现。

class huffman
{
public:
huffman();
template<typename entry>
friend bool binarysearch(entry list[wordnum],entry target,long bottom,long top,long &position);
template<typename entry>
friend void buidheap(entry a[wordnum], long number);
template<typename entry>
friend void heapify(entry a[wordnum], long high, long low);
template<typename entry>
friend void swap(entry a[wordnum], long i, long j);
bool Stat();
void Encode();
bool Decode(char code[]);
Node update(long end);
void produce_code();
void Inorder(Node *current, char currentcode[], long &num);
protected:
private:
Node SortedNode[wordnum];//从中产生huffman树
char NodeCode[wordnum][wordnum/10];//相应编码
Node root;
bool sign;//用于标记是否已经建立了huffman树
long n;//叶子节点个数
};
huffman::huffman()
{
sign = false;
}

//二分用于统计词频
template<typename entry>
bool binarysearch(entry list[wordnum], entry target, long bottom, long top, long &position)
{
while(bottom <= top)
{
position = (bottom + top)/2;
if(list[position] < target)
bottom = position + 1;
else if(list[position] > target)
top = position - 1;
else
return true;
}
return false;
}

//建立最小堆及调整为最小堆
template<typename entry>
void swap(entry a[wordnum], long i, long j)
{
entry s;
s = a[i];
a[i] = a[j];
a[j] = s;
}

template<typename entry>
void buidheap(entry a[wordnum], long number)
{
long i ,j;
for(i = number/2; i >= 1; i--)
{
j = i;
while(j <= number/2)
{
if(a[j] > a[2*j] || (a[j] > a[2*j + 1] && 2*j + 1 <= number))
{
if(a[2*j] > a[2*j + 1] && 2*j + 1 <= number)
{
swap(a, j, 2*j+1);
j = 2*j + 1;
}
else
{
swap(a, j ,2*j);
j = 2*j;
}
}
else
break;
}
}
}

template<typename entry>
void heapify(entry a[wordnum], long high, long low)
{
long j = low;
while(j <= high/2)
{
if(a[j] > a[2*j] && a[j] > a[2*j + 1])
{
if(a[2*j] > a[2*j + 1] && 2*j + 1 <= high)
{
swap(a, j, 2*j+1);
j = 2*j + 1;
}
else if(2*j <= high)
{
swap(a, j, 2*j);
j = 2*j;
}
}
else if(a[j] <= a[2*j] && a[j] > a[2*j + 1] && 2*j + 1 <= high)
{
swap(a, j, 2*j+1);
j = 2*j + 1;
}
else if(a[j] <= a[2*j + 1] && a[j] > a[2*j] && 2*j <= high)
{
swap(a, j, 2*j);
j = 2*j;
}
else
break;
}
}
//词频统计函数Stat()
bool huffman::Stat()
{
long i,position;
char p[wordmax],*get;
str s[wordnum],current;
n = 0;
while(gets(p) != NULL && strcmp(p,"@") != 0)
{
get = strtok(p," ,.!/-:;?");
while(get != NULL)
{
current = get;
if(binarysearch(s,current,0,n,position) == true && n < wordnum - 1)
s[position] ++;
else
{
n ++;
if(n < wordnum - 1)
{
if(s[position] < current && current.getfre() < s[position].getfre())
position ++;
for(i = n; i >= position; i --)
s[i+1] = s[i];
s[position] = current;
s[position] ++;
}
}
get = strtok(NULL," ,.!/-:;?");
}
}
for(i = 1; i <= n && i < wordnum; i ++)
SortedNode[i] = s[i-1];
if(n < wordnum)
return true;
else
{
n = wordnum - 1;
return false;
}
}

//建立huffman树函数
void huffman::Encode()
{
int i;
sign = true;
buidheap(SortedNode,n);
for(i = 1; i < n; i ++)
root = update(n-i+1);
}

Node huffman::update(long end)
{
Node *p,*q;
Node newNode;
p = new Node;
q = new Node;
*p = SortedNode[1];
swap(SortedNode,1,end);
heapify(SortedNode,end-1,1);//取出了一个最小元,然后将堆进行了调整
*q = SortedNode[1];
newNode = *p + *q;
SortedNode[1] = newNode;
heapify(SortedNode,end-1,1);//又取出最小元,并且把新节点赋为SortedNode[1],调整了堆
return SortedNode[1];
}

//解码函数
bool huffman::Decode(char code[codemax])
{
int i;
Node *find = &root;
Node *l = NULL,*r = NULL;
bool flag = true;
if(sign == true)
{
for(i = 0; code[i] != '\0' && flag == true; i ++)
{
l = find->leftp();
r = find->rightp();
if(code[i] == '0' && l != NULL)
find = l;
else if(code[i] == '1' && r != NULL)
find = r;
else flag = false;
if(find->leftp() == NULL && find->rightp() == NULL)
{
printf("%s ",find->getword(find));
find = &root;
}
}
if(!((find->leftp() == NULL && find->rightp() == NULL) || find == &root))
{
cout << "There are some wrong codes in th input!" << endl;
flag = false;
}
}
else
flag = false;
return flag;
}

void huffman::Inorder(Node *current, char currentcode[], long &num)
{
Node *l, *r;
char cl[code_len], cr[code_len];
if(current != NULL)
{
l = current->leftp();
r = current->rightp();
strcpy(cl,currentcode);
strcat(cl,"0");
strcpy(cr,currentcode);
strcat(cr,"1");
Inorder(l, cl, num);
if(l == NULL && r == NULL)
{
SortedNode[num] = *current;
strcpy(NodeCode[num],currentcode);
num ++;
}
Inorder(r, cr, num);
}
}
void huffman::produce_code()//利用中序遍历来得到相应的编码
{
char current[code_len] = "";
long num = 1;
Inorder(&root, current,num);
for(long i = 1; i <= n; i ++)
{
cout << SortedNode[i].getword(&SortedNode[i]) << "----" << NodeCode[i]<<" " ;
if(i%3 == 0) cout << endl;
}
}

int main()
{
huffman test;
char code[codemax];
char order;
cout << "显示编码(Show)" << " "<< "解码(Decode)" << " " <<"退出(Quit)" << endl;
cout << "Input the passage, to end with a single @ in a single line:" << endl;
test.Stat();
test.Encode();
cout << "Encoded!" << endl;
while(cin >> order)
{
if(order == 's' || order == 'S')
{
test.produce_code();
cout << "Produced!" << endl;
}
else if(order == 'd' || order == 'D')
{
cout << "Input the codes:" << endl;
cin >> code;
while(test.Decode(code))
cin >> code;
}
else if(order == 'q' || order == 'Q')
break;
}
return 0;
}

70,020

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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