當前位置:編程學習大全網 - 編程語言 - 1用遞歸實現二叉樹的先序、中序、後序三種遍歷。2哈夫曼樹問題

1用遞歸實現二叉樹的先序、中序、後序三種遍歷。2哈夫曼樹問題

//在嗎? 我給妳。另外我有自己的實驗報告。

//裏面有遞歸遍歷,有叠代遍歷。可以寫文件,可以壓縮編碼。可以讀文件。

//妳不需要什麽功能的話就刪去相應的函數就行了。

//希望加分。

#include<iostream>

#include<fstream>

#include<iomanip>

#include<string>

using namespace std;

const int maxlen = 10000; //結點最大數目

const int maxlen2 = 260; //字符最大數目,葉節點最大數目

const int maxchar = 260; //字符最大數目

#define INTMAX 10000000; //大數,大於任意壹個權值

struct CharSet //程序初始化時保存字符和結點的結構體。

{

char ch;

int weight;

};

struct HaffNode //哈夫曼樹結點結構

{

int weight,parent,lchild,rchild;

char ch;

HaffNode() {weight=0; parent=lchild=rchild=-1; ch='\n';}

};

struct HaffCode //哈夫曼樹字符編碼信息結構

{

unsigned int bit; //通過位運算,用壹個無符號整形來表示壹串二進制編碼。

int startb; //記錄偏移量。

int weight;

char ch;

HaffCode() { bit=0; startb = -1; weight=0; ch='\n';}

HaffCode& operator=(HaffCode & obj) //重載賦值符號

{

bit=obj.bit; startb=obj.startb;

ch=obj.ch; weight=obj.weight;

return *this;

}

};

class HaffmanSystem

{

private:

CharSet cs[maxlen/2]; //保存初始化時的字符和權值信息。

HaffNode hn[maxlen]; //保存哈夫曼樹結點信息。

HaffCode hc[maxlen/2]; //保存哈夫曼樹字符編碼信息。

HaffCode hc2[maxchar]; //索引散列。考慮到字符數少,以字符的十進制數作為下標保存和索引字符編碼信息,時間為O(1);

int head; //根結點的數組下標。

int n;

int leafnum; //葉節點個數,字符個數。

public:

HaffmanSystem() {n=head=leafnum=0;}

void Haffman(); //哈夫曼樹生成函數。

void InitisLization(); //初始化,調用Haffman();

void Encoding(); //對文件"ToBeTran"進行編碼。

void Decoding(); //對文件"CodeFile"譯碼。

void Print(); //印代碼至屏幕。

static void TreePrinting(int pos,int i,int child_flag,HaffmanSystem * p,ofstream & fop);

void TreePrinting(); //輸出哈夫曼樹圖形到屏幕和文件,其中要調用靜態實例函數完成遞歸功能。

void TreeFromFile(); //從文件中獲取哈夫曼樹。

};

void HaffmanSystem::InitisLization()

{

cout<<"字符集大小n,(去掉空格):"<<endl; //讀入字符和權值信息。

cin>>n;

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

{

cout<<"第"<<i+1<<"個字符和權值,用空格隔開:";

cin>>cs[i].ch>>cs[i].weight;

}

cout<<"最後輸入空格的權值(小於等於0表示空格不存在): "<<endl; //對空格特殊處理。

cin>>cs[n].weight;

cs[n].ch=' ';

if(cs[n].weight>0) n++;

this->Haffman(); //調用哈夫曼樹生成函數。

}

//哈夫曼樹生成函數。

void HaffmanSystem::Haffman()

{

leafnum=n;

int i,j,m1,m2,k1,k2;

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

{

hn[i].weight = cs[i].weight;

hn[i].ch = hc[i].ch = cs[i].ch;

}

for(i=0;i<n-1;i++) //n-1個分支節點;

{

m1=m2=INTMAX; k1=k2=0;

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

{

if(m1>hn[j].weight && hn[j].parent==-1)

{

m2 = m1; k2 = k1;

m1 = hn[j].weight ; k1 = j;

}

else

if(m2>hn[j].weight && hn[j].parent==-1)

{

m2 = hn[j].weight; k2 = j;

}

}

hn[k1].parent = n+i; hn[k2].parent = n+i;

hn[n+i].weight = hn[k1].weight+hn[k2].weight;

hn[n+i].lchild = k1; hn[n+i].rchild = k2;

head = n+i;

}

int child,parent;

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

{

hc[i].weight = hn[i].weight;

child = i;

parent = hn[child].parent;

while(parent != -1)

{

if(hn[parent].lchild == child)

{

++hc[i].startb;

}

else if(hn[parent].rchild == child)

{

hc[i].bit = hc[i].bit|(1<<++hc[i].startb);

}

child = parent;

parent = hn[child].parent;

}

hc2[hc[i].ch]=hc[i];

}

char choice='N';

cout<<"是否保存當前哈夫曼樹進hfmTree.dat中?"<<endl;

cin>>choice;

if(choice=='y'||choice=='Y') //把生成的哈弗曼樹保存在文件hfmTree.dat中。

{

ofstream fop;

fop.open("hfmTree.dat",ios::out|ios::binary|ios::trunc);

if(!fop) {cout<<"打開文件錯誤,保存失敗"<<endl; return ;}

fop.write((char*)&leafnum,sizeof(leafnum));

for(i=0;i<2*leafnum-1;i++)

{

fop.write((char*)&hn[i],sizeof(hn[i]));

}

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

{

fop.write((char*)&hc2[i],sizeof(hc2[i]));

}

fop.close();

cout<<"保存成功!"<<endl;

}

}

//編碼函數。

void HaffmanSystem::Encoding()

{

if(leafnum==0) { TreeFromFile(); }

char ch;

int i,num=0,bitTemp, startTemp=-1, temp2=0;

ifstream fip2("ToBeTran.txt",ios::in);

if(!fip2){ cout<<"無法打開指定文件ToBeTran.txt!"<<endl; return ;}

while(fip2.get(ch)) { num++;}

fip2.close();

ofstream fop1("CodeFile.dat",ios::out|ios::trunc|ios::binary);

if(!fop1){ cout<<"無法打開指定文件CodeFile.dat!"<<endl; return ;}

ofstream fop2("CodePrin.txt",ios::out|ios::trunc);

if(!fop2){ cout<<"無法打開指定文件CodePrin.txt!"<<endl; return ;}

ifstream fip1("ToBeTran.txt",ios::in);

if(!fip1){ cout<<"無法打開指定文件ToBeTran.txt!"<<endl; return ;}

fop1.write((char*)& num,sizeof(num)); //先寫入字符數量。

char bitBuf=0; //用壹個字符空間來緩沖二進制數據,每湊滿八位就寫入編碼文件。

cout<<"\n待編碼文件ToBeTran.txt: ";

for(i=7;;i--)

{

if(i==-1)

{

//用壹個字符空間bitBuf來緩沖二進制數據,每湊滿八位就寫入編碼文件。

fop1.write((char*)& bitBuf,sizeof(bitBuf));

i=7; bitBuf=0;//初始字符,使之為二進制“00000000”;

}

if(startTemp<0)

{

if(num--<=0) break;

fip1.get(ch);

cout<<ch;

bitTemp = hc2[ch-0].bit;

startTemp = hc2[ch-0].startb;

}

//位運算,確定某位上是0還是1。

temp2 = (1 & bitTemp>>startTemp--);

if(temp2) fop2<<"1";

else fop2<<"0";

bitBuf = bitBuf | temp2<<i;

//還是位運算,把0或1與原字符相與得到新的編碼信息。如00010000 | 1<<7 =10010000.

}

fop1.write((char*)& bitBuf,sizeof(bitBuf)); //把最後的壹段寫入文件。

fip1.close();

fop1.close(); //關閉文件流。

fop2.close();

cout<<"\n\n編碼成功!"<<endl;

}

//譯碼函數。

void HaffmanSystem::Decoding()

{

if(leafnum==0) { TreeFromFile();}

ofstream fop("TextFile.txt",ios::out|ios::trunc);

if(!fop) {cout<<"無法打開指定文件[TextFile.txt]"<<endl; return ;}

ifstream fip("CodeFile.dat",ios::in);

if(!fip) {cout<<"無法打開指定文件[CodeFile.dat]"<<endl; return ;}

char ch,bitBuf;

int num,bitTemp=-1, startTemp=-1;

int FLAG=0,parent=head;

fip.read((char*)& num,sizeof(num));

cout<<"譯碼結果: ";

for(int i=-1;num>0;i--)

{

if(i==-1)

{

fip.read((char*)& bitBuf,sizeof(bitBuf));

i=7;

}

//譯碼和編碼壹樣,同樣飄逸的位運算處理,可以節省時間和空間。

FLAG=(1<<i)&bitBuf;

if(FLAG==0) //0向左

{

parent = hn[parent].lchild;

}

else //1向右

{

parent = hn[parent].rchild;

}

//自頂向下搜索,碰到葉節點就是所求結點字符。

if(hn[parent].lchild==-1 && hn[parent].rchild==-1)

{

ch=hn[parent].ch;

cout<<ch;

fop <<ch;

parent = head;

num--;

}

}

cout<<endl;

fip.close();

fop.close();

cout<<"譯碼成功!"<<endl;

}

//打印編碼函數。

void HaffmanSystem::Print()

{

ifstream fip("CodePrin.txt",ios::in);

if(!fip) {cout<<"無法打開指定文件[CodePrin.txt]"<<endl; return ;}

int j =0;

char ch;

cout<<"字符形式編碼文件CodePrin.txt: ";

while(fip>>ch)

{

if(j%50==0) cout<<endl; //50個字符換行。

j++;

cout<<ch;

}

cout<<endl;

fip.close();

}

//輸出哈夫曼樹到屏幕和文件TreePrint.txt

void HaffmanSystem::TreePrinting()

{

if(leafnum==0) { TreeFromFile();}

ofstream fop("TreePtint.txt",ios::out|ios::trunc);

if(!fop) {cout<<"無法打開指定文件TreePtint.txt!"<<endl; return;}

cout<<"逆時針90度直觀輸出二叉樹(括號裏面是權值):\n"<<endl;

fop <<"逆時針90度直觀輸出二叉樹(括號裏面是權值):\n"<<endl;

TreePrinting(head,1,2,this,fop); //fop傳遞壹個文件流,用於在遞歸的各個層次對同壹文件輸出。

cout<<endl;

fop.close();

}

//輸出函數,靜態實現,方便遞歸調用。

void HaffmanSystem::TreePrinting(int pos,int i,int child_flag,HaffmanSystem * p,ofstream & fop)

{ //模仿課本輸出二叉樹。

if(pos>=0 && pos<=p->head)

{

TreePrinting(p->hn[pos].rchild,i+1,1,p,fop);

for(int j=0; j<4*(i-1); j++) {cout<<" "; fop<<" ";}

if(child_flag==-1) {cout<<"\\"; fop<<"\\";}

else if(child_flag== 1) {cout<<"/"; fop<<"/";}

if(p->hn[pos].ch=='\n') {cout<<"--NULL"<<endl; fop<<"--NULL"<<endl;}

else

{

cout<<"--"<<p->hn[pos].ch<<"("<<p->hn[pos].weight<<")"<<endl;

fop<<"--"<<p->hn[pos].ch<<"("<<p->hn[pos].weight<<")"<<endl;

}

TreePrinting(p->hn[pos].lchild,i+1,-1,p,fop);

}

}

void HaffmanSystem::TreeFromFile()

{

int i;

cout<<"哈夫曼樹不在內存中,嘗試從文件中讀入哈夫曼樹..."<<endl;

ifstream file;

file.open("hfmTree.dat",ios::in|ios::binary);

if(!file) {cout<<"無法打開指定文件hfmTree.dat!"<<endl; return ;}

if(file.eof()) {cout<<"哈夫曼樹文件空,請初始化!"<<endl; return ;}

file.read((char*)&leafnum,sizeof(leafnum));

head=leafnum*2-2;

for(i=0;i<2*leafnum-1;i++)

{

file.read((char*)&hn[i],sizeof(hn[i]));

}

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

{

file.read((char*)&hc2[i],sizeof(hc2[i]));

}

file.close();

}

//主函數.

int main()

{

HaffmanSystem * T = new HaffmanSystem();

char choice = 'Y';

while(choice!='0')

{

cout<<"-------------------------------------------------------------------------------"<<endl;

cout<<std::left<<setw(12)<<" 1--初始化"<<setw(12)<<"2--編碼 "<<setw(12)<<"3--譯碼 "<<setw(17)<<"4--印代碼文件 "<<setw(15)<<"5--印哈夫曼樹 "<<"0--退出"<<endl;

cout<<"-------------------------------------------------------------------------------"<<endl;

cout<<std::right<<setw(40)<<"操作: ";

cin>>choice;

switch(choice)

{

case '0': { cout<<"系統已經退出"<<endl; return 0;}

case '1': { T->InitisLization(); break;}

case '2': { T->Encoding(); break;}

case '3': { T->Decoding(); break;}

case '4': { T->Print(); break;}

case '5': { T->TreePrinting(); break;}

default :break;

}

}

return 0;

}

  • 上一篇:怎麽樣才能到武當救到顧小纖?
  • 下一篇:matlab中概率情況怎麽編程?
  • copyright 2024編程學習大全網