数据结构课程设计03

来源:互联网 发布:ubuntu tty 编辑:程序博客网 时间:2024/04/30 18:40

一. 问题描述

在一个加密应用中,要处理的信息来自下面的字符集,各个字符的相关使用频度如下:

字符空格A B C D E F G H I J K L M
频度 180 64 13 23 32103 22 15 47 57 1 5 31 20
字符 N O P Q R S T U V W X Y Z 
频度 55 63 15 1 48 56 80 25 7 18 2 16 1
现请编写程序你实现如下功能:

1)运行时,由用户输入来初始化字符集大小和相应用字符。

2)输入一个要加密的字符串,将其加密。

3)输出解密字符串。

 

二. 问题分析

字符加密,利用哈弗曼编码对其进行加密。确定字符和权值,选择最小两个根子树,筛选致最后一棵树。将其左子树赋值为0,右子树赋值为1,再对哈夫曼树进行遍历,方可得到加密后的字符集。哈夫曼算法Huffman Tree

void HuffmanTree(element huffTree[],int w[],int n)

{

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

{

huffTree[i].parent=-1;

huffTree[i].lchild=-1;

huffTree[i].rchild=-1;

}

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

huffTree[i].weight=w[i];

for(k=n;k<2*n-1;k++)

{

Select(huffTree,i1,i2);

huffTree[i1].parent=k;

huffTree[i2].parent=k;

huffTree[k].weight=huffTree[i1].weight+huffTree[i2].weight;

huffTree[k].lchild=i1;

huffTree[k].rchild=i2;

}

}

 

三.算法设计

给定字符集的哈夫曼树生成后,依次以叶子T[i](0≤i≤n-1)为出发点,向上回溯至根为止。上溯时走左分支则生成代码0,走右分支则生成代码1。每次最小权值的前面两个链表结点中的树结点组成一个子树,子树有合权值,子数的根按权值排序进链表

树的带权路径长度记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。

 

四. 时间复杂度和空间复杂度分析

 (1)时间复杂度:由于采取的是哈弗曼编码,构造哈弗曼树后,得到哈弗曼编码需要遍历每一个结点,在程序设计中共有26个结点,从根节点开始进行前序遍历,因此所花费的时间复杂度为O(n)。

 (2)空间复杂度:空间复杂度是指程序运行所需要的内存空间,我们需要存放的有结点数据及关系,所以所需要内存空间为一个常数,所以空间复杂度为    O(1)。

 

 

.源代码

#ifndef INFO_TREE_H

#define INFO_TREE_H

#include <fstream>

#include <vector>

#include <string>

#include <map>

 

using namespace std;

 

struct TNode

{

string Alph;

unsigned Rate;

TNode *Left;

TNode *Right;

string Code;

bool Flag;

 

TNode(string, unsigned);

TNode(unsigned, TNode*, TNode*);

};

 

class Tree

{

friend class Info;

public:

Tree(ifstream &file);

string Encrypt(string);

string Decrypt(string);

private:

vector<TNode*>::iterator Min();

TNode* Huffman();

void Fill_Table();

 

vector<TNode*> Node;

TNode *Root;

map<string, string> Alpha_Table;

};

 

#endif

#include "Info_Tree.h"

#include "Stack.h"

#include <iostream>

 

TNode::TNode(string alph, unsigned rate) :

Alph(alph), Rate(rate), Left(nullptr), Right(nullptr), Flag(true){}

 

TNode::TNode(unsigned rate, TNode *left, TNode *right) :

Alph("#"), Rate(rate), Left(left), Right(right), Flag(true){}

 

vector<TNode*>::iterator Tree::Min()

{

vector<TNode*>::iterator min, iter;

min = Node.begin();

for (iter = Node.begin(); iter != Node.end(); ++iter)

{

if ((*iter)->Rate < (*min)->Rate)

{

min = iter;

}

}

return min;

}

 

TNode* Tree::Huffman()

{

vector<TNode*>::iterator iter;

TNode *left = nullptr, *right = nullptr;

TNode *r = nullptr;

 

while (Node.size() > 1)

{

iter = Min();

right = *iter;

Node.erase(iter);

 

iter = Min();

left = *iter;

Node.erase(iter);

 

r = new TNode(left->Rate + right->Rate, left, right);

Node.push_back(r);

}

 

return r;

}

 

void Tree::Fill_Table()

{

TNode *t = Root;

Root->Flag = false;

Stack<TNode*> stack;

stack.Push_back(t);

do

{

if (t->Left != nullptr)

{

stack.Push_back(t);

if (t->Left->Flag)

{

t->Left->Code += t->Code + "0"; 

t->Left->Flag = false;

}

t = t->Left;

}

else if (t->Right != nullptr)

{

if (t->Right->Flag)

{

t->Right->Code += t->Code + "1";

t->Right->Flag = false;

}

t = t->Right;

}

else

{

Alpha_Table[t->Alph] = t->Code;

t = stack.Pop();

if (t->Right->Flag)

{

t->Right->Code += t->Code + "1";

t->Right->Flag = false;

}

t = t->Right;

}

} while (!stack.Empty());

}

 

Tree::Tree(ifstream &file) :

Root(nullptr)

{

if (!file)

{

cout << "无法打开字符配置文件" << endl;

system("pause");

exit(-1);

}

TNode *t = nullptr;

string alph;

unsigned rate;

while (!file.eof())

{

file >> alph >> rate;

t = new TNode(alph, rate);

Node.push_back(t);

}

 

Root = Huffman();

Fill_Table();

}

 

string Tree::Encrypt(string key)

{

unsigned iter = 0;

string s;

while (iter != key.size())

{

char k = key[iter++];

string tmp;

if (k > 'a'&&k < 'z')

k -= 32;

tmp += k;

s += Alpha_Table[tmp];

}

return s;

}

 

string Tree::Decrypt(string key)

{

string::iterator iter;

string tmp;

TNode *t = Root;

 

for (iter = key.begin(); iter != key.end() && t != nullptr;)

{

if (*iter == '0'&&t->Left != nullptr)

{

t = t->Left;

++iter;

}

else if (*iter == '1'&&t->Right != nullptr)

{

t = t->Right;

++iter;

}

if (t->Left == nullptr&&t->Right == nullptr)

{

tmp.append(t->Alph);

t = Root;

}

}

 

return tmp;

}

#include "Info_Tree.h"

#include <iostream>

 

using namespace std;

 

int main(void)

{

int select = 1; // 用户功能选择号

char source[256], destination[256]; // 源串与目标串

Encrypt objEncrypt; // 加密类对象

while (select != 3)

{

// 选择菜单

cout << "请选择" << endl;

cout << "1. 加密--将输入的文本串进行加密后输出" << endl;

cout << "2. 解密--将输入的已加密的文本进行解密后输出" << endl;

cout << "3. 退出--退出运行" << endl;

cin >> select;

 

switch (select)

{

case 1: // 加密

cout << "请输入文本串:";

cin >> source; // 输入文本串

strcpy(destination, objEncrypt.Encode(source).CStr()); // 加密

cout << "加密串:" << destination << endl << endl;// 输出加密串

break;

case 2: // 解密

cout << "请输入加密串:";

cin >> source; // 输入文本串

strcpy(destination, objEncrypt.Decode(source).CStr()); // 解密

cout << "解密串:" << destination << endl << endl;// 输出解密串

break;

}

}

 

system("PAUSE"); // 调用库函数system()

return 0; // 返回值0, 返回操作系统

}

#ifndef STACK_H

#define STACK_H

 

template<typename T>

class Stack

{

public:

 

struct SNode

{

T data;

SNode *next;

 

SNode() :next(nullptr){}

};

 

Stack();

~Stack();

bool Empty();

void Push_back(T);

T Pop();

 

private:

SNode *First;

SNode *Rear;

};

 

template<typename T>

Stack<T>::Stack() :

First(nullptr), Rear(nullptr)

{

First = new SNode;

Rear = new SNode;

First->next = Rear;

Rear->next = nullptr;

}

 

template<typename T>

Stack<T>::~Stack()

{

while (!Empty())

{

SNode *d = First;

First = First->next;

delete d;

}

delete First;

delete Rear;

}

 

template<typename T>

bool Stack<T>::Empty()

{

if (First->next == Rear)

return true;

else return false;

}

 

template<typename T>

void Stack<T>::Push_back(T t)

{

SNode *s = new SNode;

s->data = t;

s->next = First->next;

First->next = s;

}

 

template<typename T>

T Stack<T>::Pop()

{

if (!Empty())

{

SNode *s = First->next;

T tmp = s->data;

First->next = s->next;

delete s;

return tmp;

}

else

{

cout << "栈为空,无法弹出" << endl;

system("pause");

exit(-1);

}

}

#endif

 

 

.心得

 

该程序在调试之初有许多错误,但在努力之下和舍友帮助之下都被一一告破,现在操作该程序时已经能根据相关人性化提示进行操作,并得出正确结果。克服了不能调试,不能获得正确结果,不能正确加密等问题,但经过努力已得完善。在该次课程设计中,了解到了许多自身在c++以及数据结构概念理解上的不足,以及自身在程序设计上的不细心;今后还需改进。预祝老师春节快乐。

0 0