C++使用双向循环链表实现两个任意长的整数运算

一、需求分析

【问题描述】设计一个程序实现两个任意长的整数运算。
【基本要求】
(1)要求基于int类型实现任意长度整数。
(2)设计方案尽可能高效:运算快、所耗内存小。
(3)代码完成后需进行正确性和可用性测试。
【逻辑操作】
1、构造一个空的任意长度整数
2、在任意长度整数中插入一个新的数据元素
3、在任意长度整数中删除 一个数据元素
4、任意长度整数的 加法
5、输出任意长度整数。
【输入输出要求】

  1. 加数和被加数从Addent.txt和Augent.txt文件中获得,相加结果写入Sum.txt文件中。
  2. 要插入的数从Insert.txt中获得,插入位置由Position.txt中获得,结果写入Number.txt中。
  3. 要删除的数从Remove.txt中获得,删除位置由Position.txt中获得,结果写入Rest.txt中。
  4. 在性能测试中,加和函数的时间和空间数据写入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;
		}
	}
}

  1. 减法函数
// 做减法
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;
}

四、文件列表

文本文件列表:
在这里插入图片描述

程序相关文件列表:
在这里插入图片描述

  • 4
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值