Data Structure Course Design

Curriculum design

I, entitled

In an encrypted application, to information processing from the following characters, each character associated frequency of use as follows: A B C D E F. G H the I J K L M , frequency: 180 , 64  , 13 23 32 103 , 22 , 15 47 57 , 15 31 20 ; character  N O P Q R & lt S T the Y X-W is the Z the U-V  , frequency: 55 6,315,148,568,025,718,216. 1  . Now you write a program to achieve the following functions:

( 1 ) run by the user to input the initial size of the character set and with the respective characters.

( 2 ) Enter a string to be encrypted, it is encrypted. ( Huffman coding 1/0 )

( 3 ) outputs the decrypted string.

Second, the functional analysis

(1) run by the user to input the initial size of the character set and with the respective characters.

After long, long time, I would understand, the so-called initial character set is the original initialization code table. In other words, the code table is constructed by constructing a Huffman tree. In other words again, no Huffman tree structure can never get coding table. So, again simply, is - constructed Huffman tree ! ! ! ! !

Really "profound" in the subject, until not understand, the result has been not under the hand. Of course, a lot of the wrong way to go.

(2) Enter a string to be encrypted, it is encrypted.

This is easy to understand and more, in a word, is the Huffman coding process.

On this, the following will describe in detail.

( 3 ) outputs the decrypted string.

In short, the 1/0 encoding and decoding process.

Third, analysis

Two words understood from the title of "string encryption" and "frequency", can only be achieved with Huffman tree. Of course, if there is no "frequency" of the word, then it is another matter. In short, to do it two: encoding and decoding. That is, encryption is achieved through the character encoding.

Program is divided into eight sections:

1, the main function portion; 2, build the Huffman tree portion; 3 constructed Huffman coding table; 4, tree Huffman encoding section; 5, the Huffman decoding section tree; 6, Huffman tree data storage structure (linear structure); 7, character counts Huffman tree; 8, destructor Huffman tree (tree structure approach).

This is the Huffman coding process are basic requirements, so the programming Huffman tree mostly similar.

The main function is not to say, as a typical binary tree, Huffman tree constructors and destructors are necessary, we can not directly set a default destructor to free memory space, because it is a list of characters structure.

Secondly, we must realize there must be encoded coding table , as if the secret power of the country from time to time on the military, or to encrypt the contents of the secret power of crack must hold this password, the coding table is this "code book." So, we sort 1/0 Huffman tree construction process in sequence obtained is code table.

It is then encoded and decoded portions of which are derived from the above credentials coding table.

So, for Huffman coding, access code table is the key.

Again is the storage structure , the link between the data base of the tree. That is to say, the role of structure becomes evident.

As for character statistics, of course, he did not actually play a key role, but it is also important to assist. The importance does not need to say much.

Then look at the detailed breakdown of program code.

Start construction Huffman tree talk.

The key achievements is the second comparison value, the first is a comparison between the sub-tree, and the second is a summary of the most point of the parent node intended to be a child node of the tree back in its re-compare the value of the collection . So the two loop structures appear.

Secondly , Huffman tree is part of the destructor.

Here two steps, one step is to remove the Huffman tree node, step is to delete the coding table (because the code table is accompanied by tree exists).

Both are common in that the value given by the place of the pointer to the structure that they have been removed, while he is positioned to act as a virtual pointer moves, and to obtain the release of the memory space narrowing purpose. I.e., the form Node * p = q; q ++; delete p;

The third is to create a code table, coding and decoding.

Create a table of the encoding process is actually constantly parent node node promote the role of the conversion process to the child. When the parent node is constantly advancing the process is not empty, starting from the root node down from advancing toward the bottom of the leaf is located. In this process, the left subtree, compared with 0, 1, compared with the right subtree until it reaches the leaf nodes, a set of coded only as an element into the array.

Encoding and decoding the same principle, are just shining code table for conversion. Because the character set and encoding table bound together, so it is the same or the same character encoding, transformation can be found in the corresponding object.

The fourth is a data storage structure, build tree mostly first come, first built. Therefore, the queue would be more appropriate.

Specific analysis of the code has been written in the notes, this is only the principle of analysis, as follows:

#include<iostream>
#include <cstring>
using namespace std;
//哈夫曼编码结点
struct Code
{
 char data;     //字符串
 char code [100];
};

//哈夫曼树结点
struct TNode
{
 int weight;  //结点权值
 int parent;  //双亲指针
 int lchild;  //左孩子指针
 int rchild;  //右孩子指针
};

//构造树表和编码操作的类
class Huffman
{
 public:
 TNode*Tree;  //哈夫曼树
 Code*CodeTable; //哈弗曼编码表
 void CreateTree(int a[],int n);//创建哈夫曼树
 void CreateTable(char b[],int n);//创建编码表
 void Encoding (char*s,int n);//编码
 void Decoding (char*s,char*d,int n);//解码
 void DestroyTree(int n);//析构
};

void Huffman::DestroyTree(int n)        //n,极限
{
 for(int i=0;i<2*n-3;i++)//析构哈夫曼树
 {
  TNode*p=Tree;    //值传递,转存
  Tree++;          //指针后移
  delete p;         //删除
 }
 for(int j=0;j<n-5;j++)//析构编码表
 {
  Code*q=CodeTable;
  CodeTable++;
  delete q;
 }
}

void Huffman::CreateTable(char b[],int n)//创建编码表,关键
{
 CodeTable=new Code [n];  //与后文相似,n为动态数据存放空间(用户自定义的数据的存储范围)
 for (int i=0;i<n;i++)
 {
  CodeTable[i].data=b[i];//生成编码表,数组字符串传递
  int child=i;  //结点数量赋为子树值,即子树结点下标初始化
  int parent=Tree[i].parent;//赋值定义,初始化,使parent!=-1,生成双亲指针
  int k=0;
  /////////////////////////////////////////////////
  while (parent!=-1)        //定义规则
  {
   if(child==Tree[parent].lchild)      //所有的1/0被存储在code[]一维数组中
    CodeTable[i].code[k]='0';//左孩子标‘0’;
   else
    CodeTable[i].code[k]='1';//右孩子标‘1’;
   k++;                         //k<n<==>i<n
   child=parent;             //front->next=front->next->next,child=front->next
   parent=Tree[child].parent;          //child->parent,孩子结点变为双亲结点,front=front->next
  }
  ////////////////////////////////////////////////////////
  CodeTable[i].code[k]='\0';       //定义最后的空间NULL被赋予'\0'
  char*b=new char[k];   //申请k个字符变量空间,没有赋初值,并定义一个整型指针a指向该地址空间开始处
  //k个空间,即从根到叶子的一条路线
  ////////一条哈夫曼编码开始构建
  for(int j=0;j<k;j++)  //k为字符串终值,null
  {
   b[j]=CodeTable[i].code[k-1-j];  //----->n-1-i,下标,code[]空间缩小或者说code[]的下标在递减,
  }
  /////////////////////////b[]的空间在增大,编码数组在形成,仅仅起着聚合编码字符的作用
  for(int jj=0;jj<k;jj++)               //b[j]即b[jj]被传递到code[]
  {
   CodeTable[i].code [jj]=b[jj];           //编码数组重新赋予编码表结构体的code[]数组,以便下面的参数传递
  }                             //这是一个多维数组
 }
}
//字符->code[]->b[]->HCodeTable[].code[]

void Huffman::Encoding(char*s,int n)            //对字符串进行编码
{
 while(*s!='\0')        //数组不为空
 {
  for(int i=0;i<n;i++)
  {
   if(*s==CodeTable[i].data)
   {
    cout<<CodeTable[i].code;
    s++;
   }
  }
 }
 cout<<endl;
}

void Huffman::Decoding(char*s,char*d,int n)//s为编码串,数组指针,将编码还原为字符串
{
 while(*s!='\0')
 {
  int parent=2*n-1-1;       //根结点在HTree中的下标,因为有2n-1个结点,根结点下标自然是(2n-1)-1
  while(Tree[parent].lchild!=-1)
  {
   if(*s=='0')
    parent=Tree[parent].lchild;            //Tree[2]->next
   else
    parent=Tree[parent].rchild;
   s++;
  }
  *d=CodeTable[parent].data;
  cout<<*d;
  d++;

 }
 cout<<endl;
}

void Huffman::CreateTree(int a[],int n)    //创建哈夫曼树,假定哈弗曼树是完全二叉树
{
 Tree=new TNode [2*n-1];   //因为右孩子必然存在,n个结点会衍生2n-1个哈弗曼树结点
 for(int i=0;i<n;i++)   //初始化所有哈弗曼树结点
 {
  Tree[i].weight=a[i]; //a[i]存储的数组变量,统计权值,初始化n个空间,相当于n棵只有根结点的树,零图
  //双亲及孩子结点蓄势待发,先抢个沙发
  Tree[i].lchild=-1;   //哈夫曼树结点结构体数组指针初始化
  Tree[i].rchild=-1;
  Tree[i].parent=-1;
 }
 //////////////////////////////////////////////////////////////
 static int k=0;//选择权值最小的两个结点,静态定义变量
 int b2[1000];
 static int x;
 static int y;
 int min=1000;
  for(int j2=0;j2<n;j2++)   //j2是树数组结点下标
  {
    if(Tree[j2].weight<min)        //多个子树之和
    {
        min=Tree[j2].weight;           //权值赋予min,x为暂时存储数据的变量
        x=j2;           //下标传递参数,静态存储
    }
  }
  b2[k]=x;      //得到最小值的下标x
  k++;
  int _min=1000;
  //多次循环以获取最小值
  for(int j3=0;j3<n;j3++)
  {
   int k2;
   for( k2=0;k2<k;k2++)         //以最小值下标k为上极限,

   {
    if(j3==b2[k2])              //b2[]为数组下标值
     k2=k+2;
   }
   if(k2==k)
   {
    if(Tree[j3].weight>=Tree[x].weight)
    {
     if(Tree[j3].weight<_min)
     {
      _min=Tree[j3].weight;
      y=j3;

     }

    }
   }
  }
  b2[k]=y;
  k++;
  Tree[x].parent=Tree[y].parent=n;
  Tree[n].weight=Tree[x].weight+Tree[y].weight;  //权值之和
  Tree[n].lchild=x;
  Tree[n].rchild=y;
  Tree[n].parent=-1;
  //和上文相同的做法,
 for(int i2=n+1;i2<2*n-1;i2++) //开始创建哈夫曼树,二次构造
 {
   min=1000;

  for(int j2=0;j2<i2;j2++)
  {
   int k2;
   for( k2=0;k2<k;k2++) //
   {
    if(j2==b2[k2])
     k2=k+2;
   }
   if(k2==k)
   {
    if(Tree[j2].weight>=Tree[y].weight )
    {
     if(Tree[j2].weight<min)
     {
      min=Tree[j2].weight;
      x=j2;

     }
    }
   }
  }
  b2[k]=x;
  k++;
  int _min=1000;
  for(int j3=0;j3<i2;j3++)
  {
   int k2;                             //
   for( k2=0;k2<k;k2++)
   {
    if(j3==b2[k2])
     k2=k+2;
   }
   if(k2==k)
   {
    if(Tree[j3].weight>=Tree[x].weight)
    {
     if(Tree[j3].weight<_min)
     {
      _min=Tree[j3].weight;
      y=j3;

     }
    }
   }
  }
  b2[k]=y;
  k++;
  Tree[x].parent=Tree[y].parent=i2;
  Tree[i2].weight=Tree[x].weight+Tree[y].weight;
  Tree[i2].lchild=x;
  Tree[i2].rchild=y;
  Tree[i2].parent=-1;
 }
}


struct Node
{
 char data;
 int weight;
 Node *next;
};
//队列存储,链表结构,统计哈弗曼树
class Linklist
{
public:
 Linklist(){rear=new Node ;rear=rear->next;}    //尾插法构造新结点,
 void Construct(char s[]);                      //构造链表
 int Getlength();                               //统计哈弗曼树的子树个数
 Node*rear;

};
void Linklist::Construct(char s[])  //构造链表
{
 rear=new Node;
 rear->next=rear;   //尾插法
 for(unsigned int i=0;i<strlen(s);i++)  //strlen()函数统计字符串个数,但不包括结束标志'\0',
{                                     //strlen(s)为之前预先构造的哈弗曼树结点数
  if(rear->next==rear)  //指针指向自己,构造新结点,初始化
  {
   Node *p=new Node;
   p->data=s[0];
   p->weight=1;
   p->next=rear->next ;//------------------ //
   rear->next=p;       //p结点插入到        //
      rear=p;          //终端结点rear之后   //
                       //------------------ //
  }
  else
  {
   Node *q=rear->next->next;
   while(q!=rear->next )
   {
    if(q->data==s[i])
    {
     q->weight++;
     break;
    }
    else
     q=q->next;
   }
   if(q==rear->next )
   {
    Node *r=new Node;
    r->data=s[i];
    r->weight=1;
    r->next =rear->next ;
    rear->next =r;
    rear=r;
   }
  }
 }
}

 int Linklist::Getlength () ////统计哈夫曼树的子树个数
 {
 int n=0;
  Node*t=rear->next->next ;
  while(t!=rear->next )
  {
   t=t->next ;
   n++;
  }
  return n;
 }

void main()
{

 cout<<"请输入你所需要编码的字符串: "<<endl;
 char s[1000]={'\0'};
 gets(s);    //gets(字符指针)函数,输入字符串,头文件stdio.h(c中),c++不需包含此头文件
             //功能:从stdin流中读取字符串,直至接受到换行符或EOF时停止,
             //并将读取的结果存放在buffer指针所指向的字符数组中。换行符不作为读取串的内容,
             //读取的换行符被转换为null值,并由此来结束字符串。
 Linklist aa;//定义类Linklist的对象aa
 aa.Construct (s);//构造链表
 int n=aa.Getlength ();//得到哈夫曼树的子树个数
 int*a=new int[n];//申请n个整型变量空间,没有赋初值,并定义一个整型指针a指向该地址空间开始处
 char*b=new char[n];
 Node *v=aa.rear ->next ->next ;
 for(int i=0;i<n;i++)//初始化哈夫曼树
 {
  a[i]=v->weight ;
  b[i]=v->data ;
  v=v->next;
 }
 Huffman aaa;//定义Huffman类的对象
 aaa.CreateTree (a,n);//构建Huffman树
 aaa.CreateTable (b,n);//创建编码表
 cout<<"************************************************"<<endl;
 cout<<"生成的字符编码表是******************************"<<endl;
 cout<<"字符"<<"\t"<<"编码"<<"\t"<<"权值"<<endl;
 for(int ii=0;ii<n;ii++)//打印编码表
 {
  cout<<aaa.CodeTable [ii].data <<"\t"<<aaa.CodeTable[ii] .code<<"\t"<<a[ii]<<endl;
 }

 aaa.Encoding (s,n); //编码
 char ss[1000]={'\0'};
 char d[1000]={'\0'};
 cout<<"*************************************************"<<endl;
 cout<<"请输入一串由0和1构成的哈夫曼编码"<<endl;
 gets(ss);                      //1/0编码输入
 cout<<"最终解码为:"<<endl;
 aaa.Decoding (ss,d,n);         //译码,根据字符集编码将输入的编码还原为字符串
}

Fourth, harvest, experience and inadequate

Harvest: Huffman coding has always been my weakness, on specific details of the construction inside of fact, I always in the ignorant state. Therefore, this design practice to deepen my understanding of Huffman coding, which is a great achievement.

 

Inadequate: the design, the construction of the tree is still the biggest problem, even if the principle of the tree of understanding. But in fact, the details still know little, thus causing a lot of distress to the programming. Especially through the tree, only to understand the principle of four kinds of traversal methods, but the structure of the practice of tree still helpless, at the same time there are many details in serious ignorance on programming.



Guess you like

Origin blog.csdn.net/z1094219402/article/details/42685239