一、需求分析
【问题描述】设计一个程序实现两个任意长的整数运算。
【基本要求】
(1)要求基于int类型实现任意长度整数。
(2)设计方案尽可能高效:运算快、所耗内存小。
(3)代码完成后需进行正确性和可用性测试。
【逻辑操作】
1、构造一个空的任意长度整数
2、在任意长度整数中插入一个新的数据元素
3、在任意长度整数中删除 一个数据元素
4、任意长度整数的 加法
5、输出任意长度整数。
【输入输出要求】
- 加数和被加数从Addent.txt和Augent.txt文件中获得,相加结果写入Sum.txt文件中。
- 要插入的数从Insert.txt中获得,插入位置由Position.txt中获得,结果写入Number.txt中。
- 要删除的数从Remove.txt中获得,删除位置由Position.txt中获得,结果写入Rest.txt中。
- 在性能测试中,加和函数的时间和空间数据写入Add性能测试.txt中,插入函数的时间和空间数据写入Insert性能测试.txt中,删除函数的时间和空间数据写入Remove性能测试.txt中。
二、概要设计
一、选择采用带头结点的双向循环链表;
双向循环链表类的定义:
template<class T>
struct DblNode //链表节点类定义
{
T data; //链表结点数据
DblNode<T> *lLink, *rLink; //链表前驱、后继指针
DblNode(DblNode<T> *left=NULL,DblNode<T>*right=NULL):lLink(left),rLink(right){} //构造函数
DblNode(T value,DblNode<T>*left=NULL,DblNode<T>*right=NULL):data(value),lLink(left),rLink(right){} //构造函数
};
template<class T>
class DblList{
public:
DblList(T uniqueVal);
void Clear();//删除链表,释放空间
int Length()const;
bool IsEmpty() { return first->rLink == first; }
void setHead(DblNode<T>*ptr) { first = ptr; }
DblNode<T>*Search(const T&x);
DblNode<T>*Locate(int i, int d);
bool Insert(int i, const T&x, int d);
bool Remove(int i, T&x, int d);
//bool print();
void CreatDblList( string str);//用从文件中读出的字符串初始化链表
void Insert(const int&x); //向链表尾部插入值为x的结点
void show(ostream &os); //将链表写入文件中
DblList<T>*Add(DblList<T>*p,DblList<T>*q); //加法
DblList<T>*Sub(DblList<T>*p, DblList<T>*q); //减法
DblList<T>*Solve(DblList<T>*p, DblList<T>*q); //根据符号判断是做加法还是减法
DblList<T>*compare(DblList<T>*p, DblList<T>*q); //比较大小,以此判断被减数
void print();
private:
DblNode<T>*first;
};
二、功能的逻辑设计
1.从文件中读取大数,存入字符串中,再将字符串中的字符一个一个插入链表中。
2.我们的大数的正负号存于first头结点的数据中,令起始的数值为0,如果大数为负数,我们将first结点的值置为1,并抹去字符串中的符号,以方便计算。
2.加法功能:我们首先比较两个链表的first中的值是否一致,若一致则说明符号相同,进行加法运算;若不一致则进行减法运算,在减法运算之前我们还判断两数大小,结果的符号和数值大的那个数一致,并且数值大的那个数做被减数,数值小的那个做减数,以此来保证我们链表中的结点不会出现负号。
3.插入和删除功能:首先对操作的位置进行定位,使用current指针,指向要操作的位置,再进行插入或删除操作。
三、详细设计
long int typecount = 0; //计算程序所需字节数,在性能测试中用到
“双向循环链表.h”
1.构造函数
template<class T>
DblList<T>::DblList(T uniqueVal) {
first = new DblNode<T>(uniqueVal);
if (first == NULL) { cerr << "存储分配错误!" << endl; exit(1); }
first->rLink = first->lLink = first;
//因为最终会清除first结点,所以此处不计入内存
}
2.释放空间函数//主要在性能测试中防止内存不够而使用
template<class T>
void DblList<T>::Clear()//清除
{
DblNode<T>* curr = first->rLink;
while (curr!=first)
{
DblNode<T>* del = curr;
curr = curr->rLink;
delete del;
del = NULL;
}
delete first;
}
3.长度函数
template<class T>
int DblList<T>::Length()const {
DblNode<T>*current = first->rLink; int count = 0;
while (current != first) { current = current->rLink; count++; }
typecount += 4;
return count;
}
4.搜索函数
template<class T>
DblNode<T>*DblList<T>::Search(const T&x) {
DblNode<T>*current = first->rLink;
typecount += 4;
while (current != first && current->data != x)
current = current->rLink;
if (current != first)
return current; //搜索成功
else
{
return NULL; //搜索失败
}
}
5.定位函数
template<class T>
DblNode<T>*DblList<T>::Locate(int i, int d) {
DblNode<T>* current=new DblNode<T>();
//typecount += 4; //在最后删除了这个new出来的结点,故不计入内存
if (first->rLink == first || i == 0)
return first;
else {
if (d == 0) current = first->lLink;
else
current = first->rLink;
for (int j = 1; j < i; j++)
if (current == first)break;
else
{
if (d == 0)current = current->lLink;
else
{
current = current->rLink;
}
}
if (current != first)return current;
else
{
return NULL;
}
}
delete current;
}
6.链表初始化函数
//初始化链表,并将字符串转换成整数
template<class T>
void DblList<T>::CreatDblList(string str)
{
DblNode<T>*curr=first;
int len = str.length();
typecount += 8;
if (str[0] == '-')
{
first->data = 1;
str.erase(0, 1);
len--;
}
for (int i =0; i < len; i++)
{
Insert(str[i]-'0'); //新建链表时主要调用插入函数一
//typecount = typecount + 4 * len;
//最后会清除链表,故不计入内存
}
}
7.插入函数一
//新建链表时在链表末端插入结点
template<class T>
void DblList<T>::Insert(const int&x) {
DblNode<T> *curr = first->lLink;
DblNode<T> *newNode = new DblNode<T>(x);
assert(newNode != NULL);
newNode->rLink = first;
newNode->lLink = curr;
curr->rLink = newNode;
first->lLink = newNode;
typecount += 8;
}
8.插入函数二
//在已有的链表中可选择位置进行插入
template<class T>
bool DblList<T>::Insert(int i, const T&x, int d)
{
DblNode<T>*current = Locate(i, d);
if (current == NULL)return false;
DblNode<T>*newNode = new DblNode<T>(x);
typecount += 8;
if (newNode == NULL) { cerr << "存储分配失败!" << endl; exit(0); }
if (d == 0) //前驱插入
{
newNode->lLink = current->lLink;
current->lLink = newNode;
newNode->lLink->rLink = newNode;
newNode->rLink = current;
}
else { //后继插入
newNode->rLink = current->rLink;
current->rLink = newNode;
newNode->rLink->lLink = newNode;
newNode->lLink = current;
}
return true;
}
9.删除函数
template<class T>
bool DblList<T>::Remove(int i, T&x, int d) {
DblNode<T>*current = Locate(i, d);
//typecount += 4;
if (current == NULL)return false;
current->rLink->lLink = current->lLink;
current->lLink->rLink = current->rLink;
x = current->data; delete current;
return true;
}
10.写入文件函数
//将结果写入文件中
template<class T>
void DblList<T>::show(ostream &os) {
typecount += 8;
int len = 0;
DblNode<T> *tmp = first->rLink;
while (tmp != first) {
len++;
tmp = tmp->rLink;
}
tmp = first;
tmp = tmp->rLink;
if (first->data == 1)os << '-';
while (tmp != first) {
if (tmp == first->rLink&&tmp->data == 0)
tmp = tmp->rLink;
else {
os << tmp->data;
tmp = tmp->rLink;
}
}
}
11.输出函数
// 输出链表的结果
template<class T>
void DblList<T>::print()
{
int len = 0;
DblNode<T> *tmp = first->rLink;
while (tmp != first) {
len++;
tmp = tmp->rLink;
}
tmp = first->rLink;
if (first->data == 1) cout << '-';
while (tmp != first) {
if (tmp==first->rLink&&tmp->data == 0)
tmp = tmp->rLink;
else {
cout << tmp->data;
tmp = tmp->rLink;
}
}
typecount += 8;
cout << endl;
}
12.加减选择函数,依加数和被加数的符号而定,符号相同做加法,符号相异做减法
template<class T>
DblList<T>*DblList<T>::Solve(DblList<T>*p, DblList<T>*q)
{
if (p->first->data == q->first->data)
return Add(p, q);
else
return Sub(p, q);
}
13.加法函数
// 做加法
template<class T>
DblList<T>*DblList<T>::Add(DblList<T>* p,DblList<T>* q)
{
DblNode<T>*current1 = p->first->lLink;
DblNode<T>*current2 = q->first->lLink;
int e = 0; //记录进位
typecount += 12;
if (p->Length() >= q->Length())
{
while (current2 != q->first)
{
int temp = current1->data + current2->data+e;
if (temp > 9)
{
current1->data = temp % 10;
e=1;
}
else
{
current1->data = temp;
e=0;
}
current1 = current1->lLink;
current2 = current2->lLink;
}
while (current1 != p->first)
{
int temp = current1->data + e;
if (temp > 9)
{
current1->data = temp % 10;
e = 1;
}
else
{
current1->data = temp;
e = 0;
}
current1 = current1->lLink;
}
if (e)
{
p->Insert(0, e, 1);
}
return p;
}
else
{
while (current1 != p->first)
{
int temp = current1->data + current2->data+e;
if (temp > 9)
{
current1->data = temp % 10;
e = 1;
}
else
{
current1->data = temp;
e = 0;
}
current1 = current1->lLink;
current2 = current2->lLink;
}
while (current2 != q->first)
{
int temp = current2->data + e;
if (temp > 9)
{
current2->data = temp % 10;
e = 1;
}
else
{
current2->data = temp;
e = 0;
}
current2 = current2->lLink;
}
if (e)
{
q->Insert(0, e, 1);
}
return q;
}
}
14.两数大小比较函数,在做减法时使用
template<class T>
DblList<T>*DblList<T>::compare(DblList<T>*p, DblList<T>*q)
{
if (p->Length() > q->Length())return p;
if (p->Length() < q->Length())return q;
if (p->Length() == q->Length())
{
DblNode<T>*curr1 = p->first->rLink;
DblNode<T>*curr2 = q->first->rLink;
typecount += 8;
while (1)
{
if (curr1->data > curr2->data)return p;
if (curr2->data > curr1->data)return q;
if (curr1->data == curr2->data)
{
curr1 = curr1->rLink;
curr2 = curr2->rLink;
}
//if (curr1 == first)return p;
}
}
}
- 减法函数
// 做减法
template<class T>
DblList<T>*DblList<T>::Sub(DblList<T>* p, DblList<T>* q)
{
DblNode<T>*current1 = p->first->lLink;
DblNode<T>*current2 = q->first->lLink;
int b = 0; //借位记为b
typecount += 12;
if (this->compare(p, q) == p)
{
while (current2 != q->first)
{
if (current1->data - b < current2->data)
{
current1->data += 10;
current1->data = current1->data - b - current2->data;
b = 1;
}
else
{
current1->data = current1->data - b - current2->data;
b = 0;
}
current1 = current1->lLink;
current2 = current2->lLink;
}
return p;
}
else
{
while (current1 != p->first)
{
if (current2->data - b < current1->data)
{
current2->data += 10;
current2->data = current2->data - b - current1->data;
b = 1;
}
else
{
current2->data = current2->data - b - current1->data;
b = 0;
}
current1 = current1->lLink;
current2 = current2->lLink;
}
return q;
}
}
“AlgPerf.h”性能测试头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <windows.h>
# include <iostream>
#include <fstream>
#include"双向循环链表.h"
string str(const int len) //生成字符串
{
string str="";
int i;
for (i = 0; i < len; i++)
{
str += rand() % 10;
}
return str;
}
void AddTest() //加法性能测试
{
ofstream Add;
Add.open("Add性能测试.txt");
for (int j = 0; j < 120; j++)
{
int num = 10000 + 10000 * j;
typecount = 0;
string a = str(num);
string b = str(num);
DblList<int> list1(0);
DblList<int> list2(0);
(&list1)->CreatDblList(a);
(&list2)->CreatDblList(b);
DblList<int>* listz(0);
LARGE_INTEGER freq;
LARGE_INTEGER startCount, endCount;
double elapsed;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&startCount);// 统计运行总时间
// 统计操作时间和累加空间字节数
for (int t = 0; t < 200; t++)
{
listz = listz->Solve(&list1, &list2);
}
// 停止计时器
QueryPerformanceCounter(&endCount);
// 返回计时器经过时间(单位:毫秒)
elapsed = (double)(endCount.QuadPart - startCount.QuadPart) / freq.QuadPart;
elapsed *= 1000;
Add << elapsed << "ms," << typecount;
Add << endl;
a.~basic_string();
b.~basic_string();
(&list1)->Clear();
(&list2)->Clear();
//listz->Clear();
}
Add.close();
}
void InsertTest() //插入性能测试
{
ofstream Ins;
Ins.open("Insert性能测试.txt");
for (int j = 0; j < 120; j++)
{
int num = 10000 + 10000 * j;
typecount = 0;
string a = str(num);
DblList<int> listi(0);
(&listi)->CreatDblList(a);
//string b = str(num);
LARGE_INTEGER freq;
LARGE_INTEGER startCount, endCount;
double elapsed;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&startCount);// 统计运行总时间
// 统计操作时间和累加空间字节数
for (int t = 0; t < 200; t++)
{
(&listi)->Insert(rand()%100, rand()%10, 1);
}
// 停止计时器
QueryPerformanceCounter(&endCount);
// 返回计时器经过时间(单位:毫秒)
elapsed = (double)(endCount.QuadPart - startCount.QuadPart) / freq.QuadPart;
elapsed *= 1000;
Ins << elapsed << "ms," << typecount;
Ins << endl;
a.~basic_string();
(&listi)->Clear();
}
Ins.close();
}
void RemoveTest() //删除性能测试
{
ofstream Rem;
Rem.open("Remove性能测试.txt");
for (int j = 0; j < 120; j++)
{
int num = 10000 + 10000 * j;
typecount = 0;
string a = str(num);
int b = 0; typecount += 4;
DblList<int> listr(0);
(&listr)->CreatDblList(a);
//string b = str(num);
LARGE_INTEGER freq;
LARGE_INTEGER startCount, endCount;
double elapsed;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&startCount);// 统计运行总时间
// 统计操作时间和累加空间字节数
for (int t = 0; t < 200; t++)
{
(&listr)->Remove(100, b, 1);
}
// 停止计时器
QueryPerformanceCounter(&endCount);
// 返回计时器经过时间(单位:毫秒)
elapsed = (double)(endCount.QuadPart - startCount.QuadPart) / freq.QuadPart;
elapsed *= 1000;
Rem << elapsed << "ms," << typecount;
Rem << endl;
a.~basic_string();
(&listr)->Clear();
}
Rem.close();
}
“任意长度整数相加.cpp”
#include<iostream>
#include<stdlib.h>
#include<string>
#include <fstream>
#include<assert.h>
//#include"双向循环链表.h"
#include"AlgPerf.h"
using namespace std;
int main()
{
//性能测试
AddTest();
InsertTest();
RemoveTest();
cout << "Got it!" << endl;
//准确性测试
ifstream Augent, Addent, Pos, Insert,Remove;
ofstream Sum,Num,Rest;
string tmpAug, tmpAdd, tmpinsert, tmpPos,tmpRemove;
string a, b,in,re;
int r=0,ipos;
int count = 0;
Augent.open("Augent.txt");
Addent.open("Addent.txt");
Pos.open("Position.txt");
Insert.open("Insert.txt");
Remove.open("Remove.txt");
Num.open("Number.txt");
Sum.open("Sum.txt");
Rest.open("Rest.txt");
do {
if (Augent.is_open()) {
getline(Augent, tmpAug);
}
if (tmpAug.empty())
break;
if (Addent.is_open()) {
getline(Addent, tmpAdd);
}
if (tmpAdd.empty())
break;
if (Insert.is_open()) {
getline(Insert, tmpinsert);
}
if (tmpinsert.empty())
break;
if (Pos.is_open()) {
getline(Pos, tmpPos);
ipos = atoi(tmpPos.c_str());
}
if (Remove.is_open()) {
getline(Remove, tmpRemove);
}
if (tmpRemove.empty())
break;
count++;
cout << count << endl;
a = tmpAug;
b = tmpAdd;
DblList<int> list1(0);
DblList<int> list2(0);
(&list1)->CreatDblList(a);
(&list2)->CreatDblList(b);
DblList<int>* listz(0);
listz=listz->Solve(&list1,&list2); //求和测试
listz->show(Sum);
Sum << endl;
cout << "求和结果为:";
listz->print();
DblList<int> listi(0); //插入测试
in = tmpinsert;
(&listi)->CreatDblList(in);
(&listi)->Insert(ipos, 1, 1);
(&listi)->show(Num);
Num << endl;
cout << "插入结果为:";
(&listi)->print();
DblList<int> listr(0); //删除测试
re = tmpRemove;
(&listr)->CreatDblList(re);
(&listr)->Remove(ipos, r, 1);
(&listr)->show(Rest);
Rest << endl;
cout << "删除结果为:";
(&listr)->print();
} while (1);
Augent.close();
Addent.close();
Num.close();
Pos.close();
Sum.close();
Insert.close();
Remove.close();
Rest.close();
system("pause");
return 0;
}
四、文件列表
文本文件列表:
程序相关文件列表: