数据结构:长整数的四则运算

题目:设计一个实现任意长的整数的加法运算的演示程序

一、需求分析

本演示程序中,利用双向循环链表来实现长整数的储存,每个节点含一个整型变量。输入和输出形式按照中国对于长整数的表示习惯,每四位一组,组间用逗号隔开;其中输入的两个长整数用 ';' (英语输入法)结尾,允许逗号位置错误,并在输入非法字符是提示错误。

2.测试数据

(1)0;0;应输出“0”。
(2)-2345,6789;-7654,3211;应输出“-1,0000,0000”
(3)-9999,9999;1,0000,0000,0000;应输出“9999,0000,0001”
(4)1,0001,0001;-1,0001,0001;应输出“0”
(5)1,0001,0001;-1,0001,0000;应输出“1”
(6)-9999,9999,9999;-9999,9999,9999;应输出“-1,9999,9999,9998”
(7)1,0000,9999,9999;1;应输出“1,0001,0000,0000”

二、概要设计

1.数据结构

为实现上述程序功能,采用双向循环链表来储存长整数。
双向循环链表的储存结构:

typedef struct node{
    int info;
    struct node *prior,*next;
}DLink;

利用头结点的数据域符号来表示长整数的符号,大小表示长整数长度。
2.使用函数
DLink *Dcreat()
操作结果:初始化储存长整数的双向循环链表
DLink *addition(DLink *a, DLink *b)
操作结果:实现同符号长整数的加法操作
DLink *subtraction(DLink *a, DLink *b)
操作结果:实现异号号长整数的加法操作
void printDlink(DLink *head)
操作结果:实现长整数的中国表示方法输出
void main()
操作结果:主函数,调用以上函数进行加法运算

三、详细设计

1.读入数据初始化双向循环链表函数

采用getchar()从屏幕上读取字符,定义flag变量表示输入是否合法,对于不合法的输入将链表头结点数据域(head->info)置为0;对于正规输入构成链表的头结点数据域为:长整数长度×符号,长整数长度(len)在循环读入字符时确定,将读入的','以及'-'外每一位字符转化为int型,存在链表节点的数据域中,实现如下:

DLink *Dcreat()
{
    DLink *head,*p,*last;
    int flag = 0; //输入是否合法
    char c;
    int num;
    int len = 0;//长整数长度
    head=(DLink *)malloc(sizeof(DLink));
    head->next = NULL;
    head->prior = NULL;
    head->info = 1;//起始符号位为1
    last = head;
    while((c=getchar())!=';')
    {
        if(c=='-')
        {
            head->info = -1;//符号位
            continue;
        }
        if(c==',')
        {
            continue;
        }
        num = c - '0';
        if(num > 9 || num <0){
            flag = 1; //输入不合法
            break;
        }
        p = (DLink*)malloc(sizeof(DLink));
        p->info = num;
        len++;
        if(head->next == NULL)
        {
            head->next = p;
            p->prior = head;
            last = p;
        }
        else
        {
            p->prior = last;
            last->next = p;
            last = p;
        }
    }
    if(flag == 0)
    {
        last->next = NULL;
        head->prior = last;
        head->info = (head->info)*len; 
    }
    else
    {
       head->info = 0;
    }
    return head;
}

2. 加法函数(同号相加)

读取两个链表头结点数据域的数值,判断符号和整数长度,较长的整数作为被加数(upper),从被加数的尾节点(个位)开始向前遍历,两个链表对应节点的数据域数值相加,有进位(carry=1)情况前一节点运算时要加上进位值,判断最高位有进位的时候在头结点与其之间插入新的节点,并更新头结点数据域数值,实现如下:

DLink *addition(DLink *a, DLink *b)
{
    int symbol = abs(a->info)/(a->info);
    int len_a = abs(a->info);
    int len_b = abs(b->info);
    DLink *upper,*lower;
    if(len_a > len_b)
    {
        upper = a;
        lower = b;
    }
    else
    {
        upper = b;
        lower = a;
    }
    int len_up = abs(upper->info);
    int len_low = abs(lower->info);
    int cnt = 0;
    int carry = 0; //进位            
    while (cnt != len_up)
    {
        upper = upper->prior; //个位开始
        lower = lower->prior;
        if (cnt < len_low)
        {
            upper->info = upper->info + lower->info + carry;
        }
        else
        {
            upper->info = upper->info + carry;
        }
        carry = 0;
        if (upper->info >= 10) 
        {
            upper->info -= 10, carry = 1;   
        }
        ++cnt;
    }
    if (carry)
    {
        DLink *p;
        p = (DLink *)malloc(sizeof(DLink));
        p->info = carry;
        p->prior = upper->prior;
        upper->prior->next = p;
        p->next = upper;
        upper->prior = p;
        upper = p;
        ++len_up;
    }
    upper = upper->prior;
    upper->info = symbol*len_up;
    return upper;
}

3. 减法函数(异号相加)

减法函数与加法函数原理基本相同,不同点主要为:需要找到两个数中绝对值较大的数作为被减数(upper),通过条件语句和对两链表从头节点向后遍历比较各节点元素来实现,因为是绝对值较大数减去绝对值较小数(lower),最高位不会产生借位操作,在向前遍历进行运算的过程中,节点有借位情况(carry=1)情况时,前一节点运算时要减去借位值,实现如下:

DLink *subtraction(DLink *a, DLink *b)
{
    int len_a = abs(a->info);
    int len_b = abs(b->info);
    DLink *upper, *lower;       
    if(len_a > len_b)
    {
        upper = a;
        lower = b;
    }
    else if(len_a < len_b)
    {
        upper = b;
        lower = a;
    }
    else
    {
        DLink *tmp1 = a, *tmp2 = b;
        int cnt = 0;
        tmp1 = tmp1->next;
        tmp2 = tmp2->next;
        while (cnt != len_a)
        {
            if(tmp1->info > tmp2->info)
            {
                upper = a;
                lower = b;
                break;
            }
            else if(tmp1->info < tmp2->info)
            {
                upper = b;
                lower = a;
                break;
            }
            tmp1 = tmp1->next;
            tmp2 = tmp2->next;
            ++cnt;
        }
        if(cnt == len_a)
        { 
            upper = a;
            lower = b;
        }
    }
    int len_up = abs(upper->info);          
    int len_low = abs(lower->info);           
    int symbol = abs(upper->info)/(upper->info);
    int cnt = 0;
    int carry = 0;  // 借位
    while (cnt != len_up)
    {
        upper = upper->prior;
        lower = lower->prior;
        if (cnt < len_low)
        {
           upper->info = upper->info - lower->info - carry; 
        }
        else
        {
            upper->info = upper->info - carry;
        }
        carry = 0;
        if (upper->info < 0)
        {
          upper->info += 10, carry = 1;  
        }
        ++cnt;
    }
    upper = upper->prior;       
    upper->info = symbol*len_up;      
    return upper;
}

4. 输出

根据头结点的符号确定结果是否以’-’开始,由于减法函数处理后从头结点到存储有效数字的节点间可能会有0值,需要从头节点向后循环判断是否为0并输出(同时考虑结果仅是0的情况),在循环过程中计算还未输出的位数(len),能被4整除时则输出’,’达到输出中国表示习惯长整数的目的,实现如下:

void printDlink(DLink *head)
{
    DLink *p;
    p = head;
    int len = abs(p->info);
    int cnt = 1;
    if(p->info < 0)
    {
        printf("-");
    }
    p = p->next;
    while(p->info == 0 && p->next != NULL)
    {
        p = p->next;
        --len;
    }
    while(len)
    {
        printf("%d", p->info);
        p = p->next;
        --len;
        if(!(len%4) && len) putchar(',');
    }
}

5. 主函数

提示输入格式,并通过所构成链表头结点的数据判断输入是否合法(不合法进行提示),对合法输入判断采用函数种类,计算输出,实现如下:

void main()
{   
    printf("请输入需要计算的两个长整数,以分号隔开(如:-9999,9999;1,0000,0000)\n");
    DLink *a;
    a = Dcreat();
    if(a->info == 0)
    {
        printf("invalid input");
    }
    else
    {
        DLink *b;
        b = Dcreat();
        if(b->info == 0)
        {
            printf("invalid input");
        }
        else
        {
            DLink *c;
            if((a->info)*(b->info)<0)
                {
                    c = subtraction(a,b);
                }
            else
                {
                    c = addition(a,b);
                }
            printDlink(c);
        }
    }
}

6. 程序的层次结构

层次结构.png

五、用户手册

  1. 本程序的运行环境为DOS操作系统,执行文件为:longadd.exe
  2. 进入程序按提示操作,注意两数字间和结束用分号(英文输入法)隔开
  3. 输入后按回车符即显示结果

六、测试结果

测试.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343