Huffman编码(数据结构--未完成代码)

类别:编程语言 点击:0 评论:0 推荐:

#include <iostream.h>
#include <fstream.h>
#include <string.h>

class Data {
public:
 char ch;
 Data(){
  ch = NULL;
 }
};

typedef class Huffman {
public:
 Data data;
 int weight;
 int parent, lchild, rchild;
 Huffman(){
  weight = parent = lchild = rchild = NULL;
 }
} * HuffmanTree;

typedef char ** HuffmanCode;

// 在数组中选择两个小的权的数据
void Select(int *tw, int n, int &s1, int &s2)
{
 // 建立临时变量temp_w,用来存放最小的weight
 int temp_w, i = 1;
 while(!tw[i])
 {
  i++;
 }
 temp_w = tw[i];
 s1 = i;
 // 第一遍先确定s1
 for(; i<=n; i++)
 {
  if(temp_w > tw[i])
  {
   if(tw[i] != NULL)
   {
    temp_w = tw[i];
    s1 = i;
   }// ifin
  }// if
 }//for
 i = 1;
 while(!tw[i] || i == s1)
 {
  i++;
 }
 temp_w = tw[i];
 s2 = i;
 for(; i<=n; i++)
 {
  if(i == s1)
   goto loop;
  if(temp_w > tw[i])
  {
   if(tw[i])
   {
    temp_w = tw[i];
    s2 = i;
   }// ifin
  loop:;
  }// if
 }// for
 // 使权小的放到s1
 if(tw[s1]>tw[s2])
 {
  temp_w = s1;
  s1 = s2;
  s2 = temp_w;
 }// if
 // 取得两个小的位置后,将备用temp_array_w位置上的权抹去,表示已经被访问
 tw[s1] = tw[s2] = NULL;
 tw[0] = tw[0]-2;
}

void Initialization (HuffmanTree &HT, HuffmanCode &HC, int n)
{
 // 给文件一编码个数的个标记,放在HT[0]行中
 HT[0].weight = n;
 HT[0].data.ch = 3;
 int i;
 // 建立一个辅助建立树用的权组
 int *temp_array_w = new int[2*n];
 // 初始化数组里的权都为0
 for(i = 1; i<=2*n -1; i++)
  temp_array_w[i] = 0;
 for(i = 1; i<=n; i++)
 {
  cout << "输入字符: ";
  cin >> HT[i].data.ch;
  if(HT[i].data.ch == '\32')
   HT[i].data.ch = '|';
  cout << "输入权: ";
  cin >> HT[i].weight;
  // 把辅助权组赋和权一样的值
  temp_array_w[i] = HT[i].weight;
  // 用不用的0号单元记录个数
  temp_array_w[0] = i;
 }// for
 // 建立标志s1和s2
 int s1, s2;
 s1 = s2 = NULL;
 // 建立huffman树
 for(i = n + 1; i<=2*n - 1; i++)
 {
  Select(temp_array_w, i-1, s1, s2);
  cout << s1 << "//" << s2 << endl;
  HT[i].weight = temp_array_w[i] = HT[s1].weight + HT[s2].weight;
  HT[i].lchild = s1;
  HT[i].rchild = s2;
  HT[s1].parent = HT[s2].parent = i;
  HT[i].data.ch = '#';
 }// for
 cout << "\tData\tweight\tparent\tlchild\trchild" << endl;
 for(i = 1; i<=2*n - 1; i++)
  cout << "\t" << HT[i].data.ch << "\t" << HT[i].weight << "\t" << HT[i].parent << "\t" << HT[i].lchild << "\t" << HT[i].rchild << endl;
 // 建立好了树后打印输出到文件humTree中
 ofstream HumTreeOut("humTree.dll");
 // 把个数记录到文件开始
 HumTreeOut << HT[0].weight << endl;
 for(i = 1; i<=2*n -1; i++)
 {
  HumTreeOut << HT[i].data.ch << "\n" << HT[i].weight << "\n" << HT[i].parent << "\n" << HT[i].lchild << "\n" << HT[i].rchild << endl;

 }
 HumTreeOut.close();
}// void

// 通过树给字符编码,并且把编码输入到CodeFile中
void Encoding (HuffmanCode &HC, HuffmanTree &HT, int n, ifstream &tobetranfile)
{
 char *cd = new char[n];
 cd[n-1] = '\0';
 int i = 1;
 for(; i<=n; i++)
 {
  int start = n -1;
  int c, f;
  for(c = i, f = HT[i].parent; f!=0; c = f, f = HT[f].parent)
   if(HT[f].lchild == c)
    cd[--start] = '0';
   else
    cd[--start] = '1';
  HC[i] = new char[n-start];
  strcpy(HC[i], &cd[start]);
 }
 delete cd;
 char temp_file_ch;
 ofstream CodeOut("CodeFile.txt", ios::ate); // ios::ate表示一个open模式,是在文件后面续写
 while(!tobetranfile.eof()) // 一旦文件到了末尾,eof()函数会返回一个非零值
 {
  tobetranfile.get(temp_file_ch);
  for(i = 1; i<=n; i++)
  {
   if(temp_file_ch == HT[i].data.ch) // 如果相等,便用编码替换
    CodeOut << HC[i];
  }
 }
 CodeOut.close();
}

void Decoding (HuffmanTree &HT, ifstream &CodeFile, int n)
{
 ofstream TextOut("TextFile.txt", ios::ate);
 char temp_code_ch;
 int temp_num = 2*n - 1;
 while(!CodeFile.eof())
 {
  CodeFile.get(temp_code_ch);
  if(temp_code_ch == '1')
   if(!HT[temp_num].rchild)
   {
    TextOut << HT[temp_num].data.ch;
    temp_num = 2*n - 1;
   }
   else
   {
    temp_num = HT[temp_num].rchild;
    if(!HT[temp_num].rchild) //其实随便一个孩子为空就代表是叶子节点
    {
     TextOut << HT[temp_num].data.ch;
     temp_num = 2*n - 1;
    }
   }
  else
   if(!HT[temp_num].lchild)
   {
    TextOut << HT[temp_num].data.ch;
    temp_num = 2*n - 1;
   }
   else
   {
    temp_num = HT[temp_num].lchild;
    if(!HT[temp_num].lchild) //其实随便一个孩子为空就代表是叶子节点
    {
     TextOut << HT[temp_num].data.ch;
     temp_num = 2*n - 1;
    }
   }
 }
 TextOut.close();
 cout << "已经翻译到Text.txt文件中" << endl;
}

// 通过已存在的humtree.dll建立新的树
bool CreatNewHum(HuffmanTree &HT, int &n)
{
  char *ch_name = new char[30];
  // 存放从文件中读取的字符
  int temp_n;
  char temp_ch;
  int i = 1;
  cout << "Please Inputing the File name :";
  cin >> ch_name;
  ifstream HuffmanTreeIn(ch_name);
  if(HuffmanTreeIn.fail())
  {
   HuffmanTreeIn.close();
   cout << "不能打开文件" << endl;
   return false;
  }
  // HuffmanTree HT_TEMP = HT;
  // HuffmanTreeIn.getline(temp_line, 9);
  HuffmanTreeIn >> temp_n; // 一个单词为单位输入
  HuffmanTreeIn.get(temp_ch);
  // HuffmanTreeIn.seekg(1);
  HT = new Huffman[2*temp_n];
  // delete HT_TEMP;
  // 通过读入文件中的数据给HT赋值
  /*
   for(;i<20;i++)
  {
   HuffmanTreeIn.get(temp_ch);
   cout << temp_ch;
  }
  //*/
  //*
  int j = 1;
  while(!HuffmanTreeIn.eof())
  { 
   if(i%5 == 1)
   {
    HuffmanTreeIn >> HT[j].data.ch;
    HuffmanTreeIn.get(temp_ch); // 用于回收回车符号
    i++;
   }
   if(i%5 == 2)
   {
    HuffmanTreeIn >> HT[j].weight;
    HuffmanTreeIn.get(temp_ch);
    i++;
   }
   if(i%5 == 3)
   {
    HuffmanTreeIn >> HT[j].parent;
    HuffmanTreeIn.get(temp_ch);
    i++;
   }
   if(i%5 == 4)
   {
    HuffmanTreeIn >> HT[j].lchild;
    HuffmanTreeIn.get(temp_ch);
    i++;
   }
   if(i%5 == 0)
   {
    HuffmanTreeIn >> HT[j].rchild;
    HuffmanTreeIn.get(temp_ch);
    i++;
   }
  
   // i自加到5的倍数后j++
   if(i%5 == 1)
    j++;
   // 防止输入最后一个定位符号
   if(i > (2*temp_n -1)*5)
    break;
  }// while
  //*/
  // 从指定文件里读入树型
  HuffmanTreeIn.close();
  n = temp_n;
  return true;
}

void PrintCode ()
{
 char *name_ch = new char[51];
 ifstream FileIn("CodeFile.txt");
 ofstream FileOut("CodePrin.txt", ios::ate);
 if(FileIn.fail())
  cout << "文件打开错误!" << endl;
 while(!FileIn.eof())
 {
  FileIn.getline(name_ch, 51);
  cout << name_ch << endl;
  FileOut << name_ch << endl;
 }
 FileIn.close();
 FileOut.close();
}

void TreePrint ()
{
}

void TitalPrinT() {
 cout << "\t=========================================================" << endl;
 cout << endl;
 cout << "\t=\t\t\tHUFFMANTREE\t\t\t=" << endl;
 cout << endl;
 cout << "\t=\t\tI:INITIAL A HUFFMAN TREE\t\t=" << endl;
 cout << endl;
 cout << "\t=\t\tE:ENCODEING THE DATA\t\t\t=" << endl;
 cout << endl;
 cout << "\t=\t\tD:DECODEING THE DATA\t\t\t=" << endl;
 cout << endl;
 cout << "\t=\t\tQ:QUIT\t\t\t\t\t=" << endl;
 cout << endl;
 cout << "\t=========================================================" << endl;
}
// 把几个运算的函数全都放到一个里面去,主函数main就只调用下运算函数

void ComputeHuffman ()
{
 // 建立个临时输入存放选项的变量
 char temp_input = NULL;
 TitalPrinT();
 // 记录要给几个编码
 int n = 0;
 // 先是主体界面 直到按Q才退出
 while(temp_input != 'Q')
 {
  // 建立操作变量
  char temp_choise = 0;
  HuffmanTree HT;
  HuffmanCode HC;
  // 用switch/case来判断到底按了哪个选项
  cout << "CHOOSE WHICH DO YOU SELECT..." << endl;
  cin >> temp_input;
  switch(temp_input)
  {
  case 'I':
   cout << "How many numbers need to be initialized: ";
   cin >> n;
   // 建立数组存放数据
   HT = new Huffman[2*n];
   Initialization (HT, HC, n);
   break;
  case 'E':
   {
    //*
    cout << "Inputing the HumffmanTree from the (F)ile or (M)emory : ";
    cin >> temp_choise;
    switch(temp_choise)
    {
    case 'F':
     if(!CreatNewHum(HT, n))
      continue;
     break;
    case 'M':
     // 什么都不做
     break;
    default:
     cout << "Please Pess F or M..." << endl;
     continue;
    }// switch
    //*/
    cout << "Translating in (F)ile or (P)ressing: ";
    cin >> temp_choise;
    switch(temp_choise)
    {
    case 'F':
     break;
    case 'P':
     {
      cout << "由于本人精力限制,现在最多只能输入80个字符" << endl;
      char *temp_press_word = new char[81];
      cin >> temp_press_word;
      // 可以覆盖以前的ToBeTran.txt文件
      ofstream CodeFileOut("ToBeTran.txt");
      CodeFileOut << temp_press_word;
      break;
     }
    }
    HC = new char*[n+1];
    ifstream ToBeTranFile("ToBeTran.txt");
    Encoding(HC, HT, n, ToBeTranFile);
    ToBeTranFile.close();
    for(int i = 1; i<=n; i++)
     cout << HT[i].data.ch << "<-->" << HC[i] << endl;
   }
   // 利用建立好的huffman树(如果不在内存则从文件humTree中读入),对文件
   // ToBeTran中的正文进行编码,然后将结果寸入CodeFile.txt文件中.
   break;
  case 'D':
   {
    // 可以通过不同的树来翻译
    cout << "Inputing the HumffmanTree from the (F)ile or (M)emory : ";
    cin >> temp_choise;
    switch(temp_choise)
    {
    case 'F':
     {
     if(!CreatNewHum(HT, n))
      continue;
     HC = new char*[n+1];
     /*
     ifstream ToBeTranFile("ToBeTran.txt");
     Encoding(HC, HT, n, ToBeTranFile);
     ToBeTranFile.close();
     */
     }
     break;
    case 'M':
     // 什么都不做
     break;
    default:
     cout << "Please Pess F or M..." << endl;
     continue;
    }// switch
    ifstream CodeFile("CodeFile.txt");
    Decoding(HT, CodeFile, n);
    CodeFile.close();
   }
   // 利用建立好的haffman树将文件codefile中的代码进行翻译.结果寸入文件TextFile.txt中
   break;
  case 'P':
   PrintCode();
   // 打印代码,50个每行,并且将此字符形式的编码文件写入CodePrin中
   break;
  case 'T':
   // 印huffman树,将已经在内存的huffman树以直观的方式显示,同时将此字符形式的huffman树写
   // 入文件TreePrint中
   break;
  case 'Q':
   return;
  default:
   cout << "Please inputing in \" I E D Q \"..." << endl;
   continue;
  }// switch
  // 回到主菜单
  TitalPrinT();
 }// while
}// ComputerHuffman

void main()
{
 ComputeHuffman();
}

本文地址:http://com.8s8s.com/it/it24189.htm