2010-03-02 2 views
2
// Huffman Tree.cpp 

#include "stdafx.h" 
#include <iostream> 
#include <string>//Necessary to do any string comparisons 
#include <fstream> 
#include <iomanip> 
#include <cstdlib>//for exit() function 

using namespace std; 

class BinaryTree{ 

private: 
    struct treenode{ 
     char data; 
     int weight;  
     treenode *LChild; 
     treenode *RChild; 
    }; 
    treenode * root; 
    int freq[256]; 
    treenode* leaves[256]; 
    string path[256]; 
    string longestpath; 
    void BuildHuffmanStrings(treenode *p, string path); 

public: 
    void InitializeFromFile(string FileName); 
    void EncodeFile(string InFile, string OutFile); 
    void DecodeFile(string InFile, string OutFile); 


BinaryTree() 
{ 
    for(int i=0;i<256;i++){ 
     freq[i]=0; 
     leaves[i] = new treenode; 
    } 
    root=NULL; 
} 
};//Class end 

    /*Takes supplied filename and builds Huffman tree, table of encoding strings, etc. 
    Should print number of bytes read.*/ 
void BinaryTree::InitializeFromFile(string Filename){ 
    int CHAR_RANGE = 256; 
    ifstream inFile; 
    inFile.open(Filename.c_str(), fstream::binary); 
    if(inFile.fail()){ 
     cout<<"Error in opening file "<<Filename; 
     return; 
    } 
    char c; 
    inFile.get(c); 
    int bytesread = 0; 
    while(!inFile.eof()){ 
     bytesread++; 
     freq[(int)c] ++; 
     inFile.get(c); 
    } 
    for(int i=0;i<CHAR_RANGE;i++){//makes a leafnode for each char 
     leaves[i]->weight=freq[i]; 
     leaves[i]->data=(char)i; 
    } 
    int wheremin1, wheremin2, min1, min2; 
    /*Builds the Huffman Tree by finding the first two minimum values and makes a parent 
    node linking to both*/ 
    for(int k=0;k<256;k++){ 
     wheremin1=0; wheremin2=0; 
     min1 = INT_MAX; min2 = INT_MAX; 
     //Finding the smallest values to make the branches/tree 
     for(int i=0;i<CHAR_RANGE;i++){ 
      if(leaves[i] && freq[i]<min1){ 
       min1=leaves[i]->weight; wheremin1=i; 
      } 
     }for(int i=0;i<CHAR_RANGE;i++){ 
      if(leaves[i] && freq[i]<min2 && i!=wheremin1){ 
       min2=leaves[i]->weight; wheremin2=i; 
      } 
     } 
     if(leaves[wheremin1] && leaves[wheremin2]){ 
      treenode* p= new treenode; 
      p->LChild=leaves[wheremin1]; p->RChild=leaves[wheremin2];//Setting p to point at the two min nodes 
      p->weight=min1 + min2; 
      leaves[wheremin2]=NULL; 
      leaves[wheremin1]=p; 
      root=p; 
     } 
    }//end for(build tree) 
    cout<<" Bytes read: "<<bytesread; 
    cout<<" Weight of the root: "<<root->weight; 
} 

/*Takes supplied file names and encodes the InFile, placing the result in OutFile. Also 
checks to make sure InitializeFromFile ran properly. Prints in/out byte counts. Also 
computes the size of the encoded file as a % of the original.*/ 
void BinaryTree::EncodeFile(string InFile, string OutFile){ 

} 

/*Takes supplied file names and decodes the InFile, placing the result in OutFile. Also 
checks to make sure InitializeFromFile ran properly. Prints in/out byte counts.*/ 
void BinaryTree::DecodeFile(string InFile, string OutFile){ 

} 

int main(array<System::String ^> ^args){ 
    BinaryTree BT; 
    BT.InitializeFromFile(filename); 
    return 0; 
} 

따라서이 코드의 끝 부분에서 내 bytesread var = 약 5mil 바이트이지만 루트의 가중치는 0입니다. .내가 허프만 트리를 만든 후에 5 메가의 데이터를 읽을 때 루트의 가중치가 700k입니다.

당신이 알아낼 수 없다면 (나는 침대에서 벌레를 찾고있는 적어도 다른 시간을 보내고있을 것입니다.) 효율성을 향상시키기위한 조언을 줄 수 있습니까?

편집 : 문제는 if(freq[i]<min1)입니다. 먼저 잎이 [i] -> min1에 대한 가중치 비교가되어야합니다. 왜냐하면 그 배열이 실제로 나무를 만들기 위해 조작하고 있기 때문입니다 (freq []는 treenode 포인터가 아닌 가중치를가집니다). 문제를 해결하기 위해 그 라인과 if 구문을 다음과 같이 작성했습니다. if(leaves[i] && leaves[i]->weight<=min1)if(leaves[i] && (leaves[i]->weight)<=min2 && i!=wheremin1)

내 코드를 정리할 제안이 더 많으면 (예 : 특정 위치에 주석 추가, 다른 방법 비교 등) 제발 제안 해주세요. 나는 훌륭한 코더가 아니지만 나는되고 싶고 좋은 코드를 가지고 일하려고 노력하고있다.

편집 2 : 새/고정 코드를 게시했습니다. 루트의 가중치가 이제 bytesread와 같습니다. 나는 아직도이 코드를 정리할 제안을하고있다. 내가 찾을 수

+1

저는 학교에서 똑같은 일을하고 있습니다. 무게가 0 인 경우 어떻게 처리합니까? 트리를 만들 때 0 값을 무시할 수 있어야합니다. – Maynza

+0

나는 나무에 던지기 만하고있다. 지금도 효율성에 대해 걱정하지 않아도됩니다. – Azreal

답변

3

거의 일 :

if(freq[i]<min1){ 

당신이 모든 당신 주파수가 INT_MAX보다 될 것입니다 확실히 말할 기운으로

if(freq[i]<=min1){ 

해야한다. 마찬가지로 :

if(freq[i]<min2 && i!=wheremin1){ 

는 같아야도 동일 할 수

if(freq[i]<=min2 && i!=wheremin1){ 

min1 같이 min2.

노드 결합을 시작하면 결합 노드를 삭제하고 leaves 배열을 변경하여 결합 된 새 노드를 삽입합니다. 그러나 삭제 된 노드의 빈도가 다시 참여하지 않도록 Well로 변경해야하는 freq 배열을 변경하지 않습니다.

1

아직 해결 방법이 없지만 몇 가지 의견이 있습니다. 이것은 꽤 긴 코드입니다. 그리고 솔직히 조금 서투른. 적절한 방법으로 코드를 리팩토링하는 것이 좋습니다. (리팩토링 동안 여러 번 문제는 해결된다!) 예를 들어

, BinaryTree에서 다음 줄 :: InitializeFromFile()

for(int i=0;i<256;i++){ 
    freq[i]=0; 
    leaves[i] = new treenode; 
} 

이 BinaryTree 생성자에 더 적합 할 수있다. 또한 BinaryTree에 다음 두 가지가 있습니다.

treenode * root; 
treenode * leaves[256] 

어떤 것을 위해 무엇을 언급 할 수 있습니까? 매직 넘버는 256 개가 여러 곳에 있습니다. 그것에 대해 적절하게 명명 된 변수를 가질 수 있습니까?

2

몇 가지 힌트 :

1) cout을로 (출력을 생성하는 기능 "DumpState()"를 쓰기) 대략 다음과 같이보고 :

============START================== 
freq[0] = <some number> 
freq[1] = <some number> 
... 
freq[255] = <some number> 
leaves[0] = null 
leaves[1] = { data = 'B', weight = 3 } 
... 
leaves[255] = null 
============= END ================ 

귀하의 메인 루프 전에이 기능을 넣어, 한 번 반복 한 후, 두 번 반복 한 후 등.

2) 정말 간단하게 입력 파일을 만듭니다. 예 :

aabc 

프로그램을 실행하고 로그 파일 (위의 1로 생성)을 저장하십시오. 을 통해 작업하십시오.은 첫 번째 루프 전에 발생해야합니다. 첫 번째 루프 등에서 로그 파일과 비교하십시오. 은 실제로입니다. 다른 변수도 인쇄 할 수 있습니다 (min1, min2, wheremin1, wheremin2).