数据结构课程设计:任意长整数的加减乘运算(c++)
一、课程设计题目
任意长整数的加减乘运算 说明:设计一个程序实现两个任意长整数的加减乘运算。
操作环境:Visual Studio2019或Code::Blocks16.01
二、课程设计主要内容和要求
1.利用双向循环链表,设计一个实现任意长的整数进行加减乘运算的演示程序。
2.要求输入和输出每四位一组,组间用逗号隔开。如:1,0000,0000,0000,0000。
3.计算器的仿真界面。
三、详细设计
3.1 数据结构
实现任意长整数的加减乘运算操作,为方便未知长度的长整数进行运算和存储,所以使用双向循环链表来存储任意长整数,例一个存储长整数“+123”的链表结构如下:
由图3-1可知,双向循环链表的第一个结点,即“头”结点存储数据的符号位(整型),头结点的后一个结点为第一位数据,头节点的前一个结点为双向循环链表的“尾”,存储的是数据的最后一位。
链表的每一个结点是一个结构体,包含数据部分、前向指针和后向指针三部分。结点结构如下图所示:
结构体详细定义如下:
typedef struct ListNode{ //结构体,双向循环链表结点
int data; //结点数据(特别地符号“+”存储为整型43,“-”存储为整型45)
struct ListNode *pre; //前向指针
struct ListNode *next; //后向指针
}Node, *NodeList;
3.2 功能模块划分
长整数的加减乘运算,主要分为四个大的功能模块,分别为主调程序模块、预处理模块、输入、输出模块和主计算模块。其中,主调程序模块的主要功能就是控制程序的执行流程和界面的输出;预处理模块的主要作用就是一些执行主要操作过程中会调用到的一些功能的实现;输入、输出模块主要包括输入模块和输出模块,实现长整数的输入和输出以及其规范化;主计算模块包括加法操作模块、减法操作模块和乘法操作模块,实现长整数的加减乘运算。
3.3 系统包含的函数
系统主要包含的函数如下:
//预处理模块
int length(NodeList longint) //计算链表长度的函数,参数为链表,返回值为数据部分结点个数;
int compare(NodeList &longint1, NodeList &longint2) //比较两个链表绝对值的大小;
void removen(NodeList &longint) //删除链表(析构);
//输入、输出模块
int check(char a[], int m) //检查键入字符串格式;
void input(NodeList &longint) //输入字符串型长整数,去掉分隔符后在链表中存储,并引用带回;
void output(NodeList &longint) //将参数链表中的数据每四位一组分组,加上分隔符后打印输出;
//主运算模块
void same_add(NodeList &longint1, NodeList &longint2, NodeList &result)
//基本加法操作;
void same_sub(NodeList &longint1, NodeList &longint2, NodeList &result)
//基本减法操作;
void add(NodeList &longint1, NodeList &longint2, NodeList &result)
//有符号的加法操作;
void sub(NodeList &longint1, NodeList &longint2, NodeList &result) //有符号的减法操作;
void multiply(NodeList &longint1, NodeList &longint2, NodeList &result) //乘法操作;
//主调程序模块
void welcome() //打印欢迎界面
void print() //打印操作界面
void handle_do() //主处理函数
int main() //主函数
函数间调用关系如下:

3.4 功能模块详细介绍
3.4.1 系统主要执行流程如下:

3.4.2 输入模块
输入模块的主要功能是实现长整数的键入并将其规范化后存储在链表中,主要流程为先输入字符串型的长整数,以字符数组形式存放,并检查输入格式是否正确,不正确的话提示重新输入,直至输入格式正确为止,然后在将字符数组中除分隔符外的符号位和数据部分存储在双向循环链表中(不存储分隔符是为了后续计算的方便性)。最后进行一些异常数据的处理,如果输入的仅有符号位和分隔符,如(“+,”)则在链表中存储为有符号的0(“+0”或“-0”),如果输入的数据以多位0开头(如“+0000001”)则将数据前的0删除后再存储在链表中(链表中存储“+1”)。
3.4.3 输出模块
输出模块实现的功能主要是将参数链表中的数据加上分隔符以四位一组的形式输出,主要解决的是数据规范化的问题。我的思路是遍历输出链表中的数据,标记需输出分隔符的地方并打印分隔符“,”即可。
3.4.4 加、减法模块
由于加减法代码基本类似且思路相同,这里仅以加法操作为例详细介绍:
加法操作对输入的长整数类型不同共有8中不同情况,假设输入的两个长整数为L1、L2,则:
当两个操作数(L1、L2)符号相同的情况下都为正数时,结果为+(L1+L2);都为负数时,结果为-(L1+L2);
当两个操作数(L1、L2)符号相反L1符号为正、L2符号为负 L1的绝对值大于L2的绝对值,相当于+(L1-L2);L1的绝对值小于L2的绝对值,相当于-(L2-L1);L1的绝对值等于L2的绝对值,结果为0。
当两个操作数(L1、L2)符号相反L1符号为负、L2符号为正且L1的绝对值大于L2的绝对值,相当于-(L1-L2);L1的绝对值小于L2的绝对值,相当于+(L2-L1);L1的绝对值等于L2的绝对值,结果为0。
3.4.5 乘法模块
乘法计算模块实现的功能就是两个长整数的相乘,当两个长整数中有一个存储数据为0时,结果为0。否则,当两个长整数符号相同时结果符号位为+,符号相反时,结果符号位为-,然后定义两个结构体指针,按照我们通常乘法计算的习惯,使orp1指向两个操作数中绝对值较大的一个,orp2指向另一个,然后从orp2的最后一位开始,逐个乘orp1的每一位,将结果存入链表pp1中,使用合适的逻辑,每次循环将pp1适当移位后累加即可得到乘法计算的结果。
四、总结
我觉得双向循环链表的作用大概就是,在进行加减乘法操作的时候,需从两个存放大整数的链表的最后一位开始进行加减乘操作,得到的结果存入结果新链表(事先未知长度)的最后一位。使用s = p->pre,可以直接将结构体指针s定位到链表p最后一位,而不用去遍历链表p,也不用像数组一样事先分配空间,有效的节约了空间和时间。其中,循环的作用体现在,可以操纵事先未知长度的链表;双向的作用体现为插入、删除结点的方便性。
五、附录(代码)
#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
#define MAX 1000
typedef struct ListNode{ //结构体,双向循环链表
int data; //结点数据
struct ListNode *pre; //前向指针
struct ListNode *next;//后向指针
}Node, *NodeList;
//============================================输入======================================================
//-----------------检查键入字符串格式-------------------------
//第一个字符为符号位,其余每一位均在0-9之间或者是逗号,多个分隔符与一个相同
int check(char a[], int m){
if(a[0] == '+' || a[0] == '-'){
for(int i = 1; i < m; i++){
if((int(a[i]) <= 57 && int(a[i]) >= 48) || a[i] == ','){
if(i == m-1)
return 1;
}
else
return -1;
}
}
else
return -1;
}
//-------------------------------输入字符串型长整数,去掉分隔符后存入链表中---------------------------------------
void input(NodeList &longint){
longint = new Node;
longint -> pre = longint; //初始化结构体变量
longint -> next = longint;
int flag1 = 0;
int num = 0;
int len = 0;//字符串长度
string str;
char arr[MAX];//字符数组来存放长整型
cin >> str;//输入一个字符串
len = str.length();
for(int i = 0; i < len; i++){//字符串赋值给字符数组,调用check函数
arr[i] = str[i];
}
flag1 = check(arr, len);
while(flag1 == -1){//当输入格式不正确时提示,直至输入格式正确
cout << "请重新按照格式输入这个长整数! " << endl;
cin >> str;
len = str.length();
for(int i = 0; i < len; i++){
arr[i] = str[i];
}
flag1 = check(arr, len);
}//while
if(arr[0] == '+'){
longint->data = int('+');//字符'+'存储为整型43
}
if(arr[0] == '-'){
longint->data = int('-');//字符'-'存储为整型45
}
NodeList prenode = longint;
for(int i = 1; i < len; i++){//将字符串中每一位使用循环列表存放
if(arr[i] != ','){
num = arr[i] - 48;//字符型转换为整型
NodeList newn = new Node;
newn -> data = num;
newn -> pre = prenode;
newn -> next = longint;
prenode -> next = newn;
longint -> pre = newn;
prenode = newn;
}
}
//一些异常输入处理
if(longint ->next == longint){//当输入的为"+,,,,,,"这种形式时,在链表中存储"+0"
NodeList newn = new Node;
newn -> data = 0;
newn -> pre = longint;
newn -> next = longint;
longint -> next = newn;
longint -> pre = newn;
}
NodeList nextnode = longint ->next;
NodeList oldn;//删除表开头结点的0,如(+0,0001转换为+1保存);若链表值为0时,保存0(如+0,0000保存为+0)
while(nextnode->data == 0 && nextnode->next != longint){
oldn = nextnode;
nextnode = nextnode->next;
longint ->next = nextnode;
nextnode ->pre = longint;
delete(oldn);
}
}
//==========================================预处理==============================================
//------------------参数为链表,返回链表(数据部分)长度--------------------------
int length(NodeList longint){
int sum = 0;
NodeList p = longint->next;
while(p != longint){
sum++;
p = p->next;
}
return sum;
}
//---------------------比较两个链表绝对值大小------------------------------------
//当第一参数大比第二参数绝对值大时返回1,第一参数比第二参数绝对值小时返回-1,否则返回0
int compare(NodeList &longint1, NodeList &longint2){
NodeList p1, p2;
p1 = longint1;
p2 = longint2;
while(p1->next != longint1 && p2->next != longint2){
p1 = p1->next;
p2 = p2->next;
}
if(p1->next != longint1)//第一个链表长,则它的绝对值大
return 1;
else if(p2->next != longint2)//第二个链表长,则它的绝对值大
return -1;
else{//两个链表一样长时,比较两个链表结点存放数据大小判断
p1 = longint1->next;
p2 = longint2->next;
while(p1->data == p2->data && p1->next != longint1){
p1 = p1->next;
p2 = p2->next;
}
if(p1->data > p2->data)
return 1;
else if(p1->data < p2->data)
return -1;
else
return 0;
}
}
//析构,释放链表空间
void removen(NodeList &longint){
NodeList oldn = longint;
NodeList nextnode = longint ->next;
while(nextnode != longint){
oldn = nextnode;
nextnode = nextnode->next;
longint ->next = nextnode;
nextnode ->pre = longint;
delete(oldn);
}
delete(longint);
}
//============================================输出-===========================================
//-----------------------将链表中的结果加上分隔符','后输出;------------------------------
//特别地,当结果为0(+0或-0)时直接输出0即可
void output(NodeList &longint){
NodeList p;
int num = 0;
int sum = length(longint);
int n = sum % 4;
p = longint->next;
if(p->next == longint && p->data == 0){//当计算结果为0(+0或-0)时输出0
cout << "计算结果为: " << 0 << endl;
}else{
if(longint -> data == 43)//先输出首部符号
cout << "计算结果为: " << '+';
else if(longint -> data == 45)
cout << "计算结果为: " << '-';
while(p != longint){//以4为为一组用分隔符分隔,如 (+1,0000,0000,11)
if((num == n || (num - n) % 4 == 0) && num != sum && num!=0)
cout << ',';
cout << p->data;
p = p->next;
num++;
}
}
cout << endl;
}
//============================================加减乘运算===============================================
//-------------基本加法操作------------------
void same_add(NodeList &longint1, NodeList &longint2, NodeList &result){
int carry = 0;//进位
int newdata = 0;
NodeList p1, p2, newn;
p1 = longint1->pre;
p2 = longint2->pre;
NodeList nextnode = result;
while(p1 != longint1 && p2 != longint2){//从两长整数最后开始逐位进行加法运算
newdata = (p1->data + p2->data + carry);
carry = newdata/10;
newn = new Node();
if(carry)
newn->data = (newdata - 10);
else
newn->data = newdata;
newn->pre = result;
newn->next = nextnode;
result->next = newn;
nextnode->pre = newn;
nextnode = newn;
p1 = p1->pre;
p2 = p2->pre;
}
while(p1 != longint1){//当p1前部分还有数据时
newdata = (p1->data + carry);
carry = newdata/10;
newn = new Node();
if(carry)
newn->data = (newdata - 10);
else
newn->data = newdata;
newn->pre = result;
newn->next = nextnode;
result->next = newn;
nextnode->pre = newn;
nextnode = newn;
p1 = p1->pre;
}
while(p2 != longint2){//当p2前部分还有数据时
newdata = (p2->data + carry);
carry = newdata/10;
newn = new Node();
if(carry)
newn->data = (newdata - 10);
else
newn->data = newdata ;
newn->pre = result;
newn->next = nextnode;
result->next = newn;
nextnode->pre = newn;
nextnode = newn;
p2 = p2->pre;
}
if(carry != 0){//计算后,进位不为0时处理
newn = new Node();
newn->data = carry;
newn->pre = result;
newn->next = nextnode;
result->next = newn;
nextnode->pre = newn;
}
//output(result);
}
//-------------基本减法操作------------------
void same_sub(NodeList &longint1, NodeList &longint2, NodeList &result){
int borrow = 0;//借位
int newdata = 0;
NodeList p1, p2, newn;
p1 = longint1->pre;
p2 = longint2->pre;
NodeList nextnode = result;
while(p1 != longint1 && p2 != longint2){//从两长整数最后开始逐位进行减法运算
if(p1->data - p2->data - borrow >= 0){//没有借位产生时
newdata = p1->data - p2->data - borrow;
borrow = 0;
}
else{//有借位产生
newdata = (p1->data - p2->data - borrow + 10);
borrow = 1;
}
newn = new Node();
newn->data = newdata;
newn->pre = result;
newn->next = nextnode;
result->next = newn;
nextnode->pre = newn;
nextnode = newn;
p1 = p1->pre;
p2 = p2->pre;
}//while
while(p1 != longint1){//当p1较长时,前部分还有数据
if(borrow){//如果有借位
if(p1->data - borrow >= 0){
newdata = p1->data - borrow;
borrow = 0;
}
else{
newdata = (p1->data - borrow + 10);
borrow = 1;
}
}
else//没有借位
newdata = p1->data;
newn = new Node();
newn->data = newdata;
newn->pre = result;
newn->next = nextnode;
result->next = newn;
nextnode->pre = newn;
nextnode = newn;
p1 = p1->pre;
}//while
nextnode = result ->next;
NodeList oldn;
while(nextnode->data == 0 && nextnode->next != result){//删除表开头结点的0,如(+0001转换为+1);若链表值为0时,result为(+或-)0
oldn = nextnode;
nextnode = nextnode->next;
result ->next = nextnode;
nextnode ->pre = result;
delete(oldn);
}
//output(result);
}
//---------------------有符号加法操作--------------------------------------
void add(NodeList &longint1, NodeList &longint2, NodeList &result){
result = new Node;//存放结果,初始化
result ->next = result;
result ->pre = result;
if(longint1->data == longint2->data){//大整数L1、L2符号相同
if(longint1->data == 43)//L1、L2都是正数,结果为+(L1+L2)
result->data = 43;
if(longint1->data == 45)//L1、L2都是负数,结果为-(L1+L2)
result->data = 45;
same_add(longint1, longint2, result);
}
else{//L1、L2符号相反
if(longint1->data == 43 && longint2->data == 45){//L1符号为正、L2符号为负
if(compare(longint1, longint2) == 1){//L1的绝对值大于L2的绝对值,相当于+(L1-L2)
result->data = 43;
same_sub(longint1, longint2, result);
}else
if(compare(longint1, longint2) == -1){//L1的绝对值小于L2的绝对值,相当于-(L2-L1)
result->data = 45;
same_sub(longint2, longint1, result);
}else{//L1的绝对值等于L2的绝对值,输出结果为0
NodeList newn = new Node;
newn -> data = 0;
newn -> pre = result;
newn -> next = result;
result -> next = newn;
result -> pre = newn;
//output(result);
}
}
if(longint1->data == 45 && longint2->data == 43){//L1符号为负、L2符号为正
if(compare(longint1, longint2) == 1){//L1的绝对值大于L2的绝对值,相当于-(L1-L2)
result->data = 45;
same_sub(longint1, longint2, result);
}else
if(compare(longint1, longint2) == -1){//L1的绝对值小于L2的绝对值,相当于+(L2-L1)
result->data = 43;
same_sub(longint2, longint1, result);
}else{//L1的绝对值等于L2的绝对值,输出结果为0
NodeList newn = new Node;
newn -> data = 0;
newn -> pre = result;
newn -> next = result;
result -> next = newn;
result -> pre = newn;
//output(result);
}
}
}//else
}
//------------------有符号减法操作-------------------------------
void sub(NodeList &longint1, NodeList &longint2, NodeList &result){
result = new Node;//存放结果,初始化
result ->next = result;
result ->pre = result;
if(longint1->data == longint2->data){//大整数L1、L2符号相同
if(longint1->data == 43){//L1、L2都是正数
if(compare(longint1, longint2) == 1){//L1的绝对值大于L2的绝对值,相当于+(L1-L2)
result->data = 43;
same_sub(longint1, longint2, result);
}else
if(compare(longint1, longint2) == -1){//L1的绝对值小于L2的绝对值,相当于-(L2-L1)
result->data = 45;
same_sub(longint2, longint1, result);
}else{//L1的绝对值等于L2的绝对值,输出结果为0
NodeList newn = new Node;
newn -> data = 0;
newn -> pre = result;
newn -> next = result;
result -> next = newn;
result -> pre = newn;
//output(result);
}
}
if(longint1->data == 45){//L1、L2都是负数
if(compare(longint1, longint2) == 1){//L1的绝对值大于L2的绝对值,相当于-(L1-L2)
result->data = 45;
same_sub(longint1, longint2, result);
}else
if(compare(longint1, longint2) == -1){//L1的绝对值小于L2的绝对值,相当于+(L2-L1)
result->data = 43;
same_sub(longint2, longint1, result);
}else{//L1的绝对值等于L2的绝对值,输出结果为0
NodeList newn = new Node;
newn -> data = 0;
newn -> pre = result;
newn -> next = result;
result -> next = newn;
result -> pre = newn;
//output(result);
}
}
}
else{//L1、L2符号相反
if(longint1->data == 43)//L1符号为正、L2符号为负
result->data = 43;
if(longint1->data == 45)//L1符号为负、L2符号为正
result->data = 45;
same_add(longint1, longint2, result);
}
}
//----------------------乘法操作----------------------------------------
void multiply(NodeList &longint1, NodeList &longint2, NodeList &result){
int num = 0;
int c = 0;
NodeList p1, p2, opr1, opr2;
int carry = 0, newdata = 0;
result = new Node;//存放结果,初始化
result ->next = result;
result ->pre = result;
p1 = longint1->next;
p2 = longint2->next;
if((p1 ->data == 0 && p1 ->next == longint1) || (p2 ->data == 0 && p2 ->next == longint2)){//当两个大整数中有一个为0时结果为0
result -> data = 43;//为结果符号位赋初值(+或-均可)结果为0时不输出符号位
NodeList newn = new Node;
newn -> data = 0;
newn -> pre = result;
newn -> next = result;
result -> next = newn;
result -> pre = newn;
}//if
else{
if(longint1->data == longint2->data)//大整数L1、L2符号相同,结果符号为'+'
result ->data = 43;
else//大整数L1、L2符号不同,结果符号为'—'
result ->data = 45;
if(compare(longint1, longint2) == -1){//使绝对值较大的作为操作数1,进行计算
opr1 = longint2;
opr2 = longint1;
}else{
opr1 = longint1;
opr2 = longint2;
}
NodeList pp2 = new Node;//构造一个pp2链表,内容为(+0),后面进行更新求和
pp2 -> data = 43;//任意
pp2 -> pre = pp2;
pp2 -> next = pp2;
NodeList newn = new Node;
newn -> data = 0;
newn -> pre = pp2;
newn -> next = pp2;
pp2 -> next = newn;
pp2 -> pre = newn;
NodeList pp1 = new Node;//链表pp1
pp1 -> data = 43;//任意
pp1 -> pre = pp1;
pp1 -> next = pp1;
NodeList po1, po2;
po1 = opr1 ->pre;
po2 = opr2 ->pre;
while(po2 != opr2){
carry = 0;
po1 = opr1 ->pre;
NodeList nextnode = pp1;
while(po1 != opr1){//将po2链表中数据,逐个与po1中数据计算相乘,存入链表pp1中
if((po1 ->data * po2 ->data + carry) < 10){
newdata = (po1 ->data) * (po2 ->data) + carry;
carry = 0;
}
else{
newdata = (po1 ->data * po2 ->data + carry) % 10;
carry = (po1 ->data * po2 ->data + carry) / 10;
}
NodeList newnode = new Node;
newnode->data = newdata;
newnode->pre = pp1;
newnode->next = nextnode;
pp1->next = newnode;
nextnode->pre = newnode;
nextnode = newnode;
po1 = po1 ->pre;
}
if(carry != 0){//计算后,进位不为0时处理
newn = new Node();
newn->data = carry;
newn->pre = pp1;
newn->next = nextnode;
pp1->next = newn;
nextnode->pre = newn;
}
c = num;
while(c != 0){//从第二次循环开始每次向左移一位,相当于每个pp1乘以pow(10, num)
NodeList zero = new Node;
NodeList pnode ;
pnode = pp1 ->pre;
zero -> data = 0;
zero -> pre = pnode;
zero -> next = pp1;
pnode -> next = zero;
pp1 -> pre = zero;
c--;
}
same_add(pp2, pp1, result);
//output(result);
//将result的值赋值给pp2进行运算;
//clearlist(pp2);
pp2 ->data = result ->data;
NodeList nextr = result ->next;
NodeList prenode = pp2;
while(nextr != result){
NodeList newnode = new Node;
newnode->data = nextr ->data;
newnode->pre = prenode;
newnode->next = pp2;
prenode->next = newnode;
pp2 ->pre = newnode;
prenode = newnode;
nextr = nextr ->next;
}
num++;
po2 = po2 ->pre;
}
}//else
//output(result);
}
//=======================================主调函数部分==========================================
//------------------------打印欢迎界面---------------------------------
void welcome(){
cout << "********************************************************************" << endl;
cout << "* 任意长整数的加减乘法运算 *" << endl;
cout << "********************************************************************" << endl;
cout << "基本操作要求:" << endl;
cout << "1.输入格式每四组一位,组间用逗号隔开。" << endl;
cout << "2.输入的长整数必须带有符号(+或-),如:+1,0000,000。" << endl;
cout << "3.组间多个分隔符看做一个(如:+1,,,1000 相当于 +1,1000)。" << endl;
cout << "********************************************************************" << endl;
cout << endl;
}
//---------------------------打印操作界面-----------------------------------
void print(){
cout << " ************************************************" << endl;
cout << " ************************************************" << endl;
cout << " 输入1、2、3、4选择操作 " << endl;
cout << " 1、加法 " << endl;
cout << " 2、减法 " << endl;
cout << " 3、乘法 " << endl;
cout << " 4、退出 " << endl;
cout << " ************************************************" << endl;
cout << " ************************************************" << endl;
cout << endl;
}
//------------------------------主处理函数------------------------------
void handle_do(){
char op;
NodeList longint1, longint2, longresult;
//输入两个操作数
cout << "请输入第一个带符号的操作数(如-1,0000,0001或+1,0000,0001): " << endl;
input(longint1);
cout << "请输入第二个带符号的操作数(如-1,0000,0001或+1,0000,0001): " << endl;
input(longint2);
print();//打印操作界面
cout << "请输入你的选择: " << endl;
cin >> op;
while(op > '4' || op < '1'){//当输入选择符号错误时,提示输入正确的选择
cout << "请输入正确的选择: " << endl;
cin >> op;
}
switch(op){//根据选择,匹配执行对应操作
case '1':
add(longint1, longint2, longresult);
output(longresult);
break;
case '2':
sub(longint1, longint2, longresult);
output(longresult);
break;
case '3':
multiply(longint1, longint2, longresult);
output(longresult);
break;
case '4':
exit(0);//退出系统
}
removen(longint1);
removen(longint2);
removen(longresult);
}
//-------------------------主函数----------------------------------
int main()
{
char ch;
int flag = 1;
welcome(); //打印欢迎界面
while(flag){//标志有效时,可以持续执行
handle_do();//调用主处理函数-
cout << endl;
cout << "是否继续?是(y),否(n): " ;
cin >> ch;
cout << endl;
while(ch != 'y' && ch != 'n'){//当键入无效字符时提醒,直至输入有效字符
cout << "请输入正确选择!是(y),否(n): " ;
cin >> ch;
cout << endl;
}
if(ch == 'n'){
flag = 0;
}
}
return 0;
}
更多推荐
所有评论(0)