大数减法运算

 

//test.h

#ifndef _TEST_H

#define _TEST_H

#include <stdlib.h>



#define MAXSIZE 50



struct DoubleList

{ 

    int sqlist[MAXSIZE];

    int key;

    int size;

    int data;

} DLIST_S;



typedef struct Node

{

    int data;

    struct Node *plast;

    struct Node *pnext;

} DNODE_S;





#if 1   /* 双链表相关操作 */

/*****************************************************************************

Description   : 遍历打印链表的所有节点

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

void PrintNode(DNODE_S **ppLinkList);



/*****************************************************************************

Description   : 创建双链表,并把第一个节点的数值初始化为data

Input Param   : 

Output Param  : 无

Return Value  : 成功返回0,失败返回-1

*****************************************************************************/

int CreateDoubleLinkList(DNODE_S **ppLinkList, int data);



/*获取链表中节点个数*/

/*****************************************************************************

Description   : 获取链表中节点个数

Input Param   : 

Output Param  : 无

Return Value  : 返回节点个数

*****************************************************************************/

int GetListLength(DNODE_S **ppLinkList);



/*****************************************************************************

Description   : 初始化一个新结点

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

void InitNewNode(DNODE_S **ppNewNode, int data);



/*****************************************************************************

Description   : 获取链表中的最后一个节点

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

void GetLastNode(DNODE_S **ppLinkList, DNODE_S **pLastNode);



/*****************************************************************************

Description   : 在链表第pos个位置插入数据等于data的节点

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

void InsertNode(DNODE_S **ppLinkList, int pos, int data);



/*****************************************************************************

Description   : 删除链表中第pos个节点

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

void MoveNode(DNODE_S **ppLinkList, int pos);

#endif



#if 1   /* 数组和链表转换 */

/*****************************************************************************

Description   : 将数组写入链表中,链表中的数据的先后顺序和数组中的顺序要保持一致 

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

void IntToList(DNODE_S **ppLinkList, int *paiArray, int size);



/*****************************************************************************

Description   : 将链表写入数组中,数组中的数据的先后顺序和链表中的顺序要保持一致 

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

void ListToInt(DNODE_S *pLinkList, int *paiArray);



/*****************************************************************************

Description   : 将字符数组写入链表中,链表中的数据的先后顺序和数组中的顺序要保持一致 

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

void StringToList(DNODE_S **ppLinkList, const char *pcString);



/*****************************************************************************

Description   : 将链表写入字符数组中,数组中的数据的先后顺序和链表中的顺序要保持一致 

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

void ListToString(DNODE_S *pLinkList, char *pcString); 

#endif



#if 1

/*****************************************************************************

Description   : 获取小数的位数,如果是整数返回0

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

int GetDecimalLength(const char *pcNum);



/*****************************************************************************

Description   : 判断字符是否为合法数字

Input Param   : 

Output Param  : 无

Return Value  : 

*****************************************************************************/

bool IsValidNum(char c);

#endif

#endif

 

//test.cpp

#include "stdafx.h"

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <string>

#include "test.h"

using namespace std;



#define ERR -1

#define OK  0

#define TEST 1

#define POSITIVE_NUMBER 0

#define NEGATIVE_NUMBER 1



#if 1

void PrintNode(DNODE_S **ppLinkList)

{

    DNODE_S *node = *ppLinkList;

    printf("\r\n");

    printf("%d ", node->data);

    while (node->pnext != NULL)

    {

        node = node->pnext;

        printf("%d ", node->data);

    }

}



int CreateDoubleLinkList(DNODE_S **ppLinkList, int data)  

{

    DNODE_S *pHeadNode;



    pHeadNode = (DNODE_S *)malloc(sizeof(DNODE_S));

    if (NULL == pHeadNode)

    {

        return ERR;

    }

    pHeadNode->data = data;

    pHeadNode->plast = NULL;

    pHeadNode->pnext = NULL;



    *ppLinkList = pHeadNode;



    return OK;

}



int GetListLength(DNODE_S **ppLinkList)

{

    int count = 1;

    DNODE_S *node = *ppLinkList;

    if (NULL == node)

    {

        return 0;

    }



    while (node->pnext != NULL)

    {

        node = node->pnext;

        count++;

    }

    

    return count;

}



void GetLastNode(DNODE_S **ppLinkList, DNODE_S **pLastNode)

{

    DNODE_S *pTmpNode = *ppLinkList;

    *pLastNode = NULL;

    while (pTmpNode->pnext != NULL)

    {

        pTmpNode = pTmpNode->pnext;

    }

    *pLastNode = pTmpNode;

}



void InitNewNode(DNODE_S **ppNewNode, int data)

{    

    DNODE_S *pNewNode    = NULL;

    /* 初始化新结点 */

    pNewNode = (DNODE_S *)malloc(sizeof(DNODE_S));

    if (NULL == pNewNode)

    {

        return;

    }

    pNewNode->data = data;

    pNewNode->plast = NULL;

    pNewNode->pnext = NULL;

    *ppNewNode = pNewNode;

}



void InsertNode(DNODE_S **ppLinkList, int pos, int data)

{

    int index = 1;

    int iNodeNum = GetListLength(ppLinkList);

    DNODE_S *pPrevNode = *ppLinkList;

    DNODE_S *pNextNode = NULL;

    DNODE_S *pNewNode    = NULL;



    if (pos > iNodeNum || pos < 0)

    {

        return;

    }



    /* 初始化新结点 */

    InitNewNode(&pNewNode, data);



    /* 1、插入头部 */

    if (0 == pos)

    {

        pPrevNode->plast = pNewNode;

        pNewNode->pnext = pPrevNode;

        *ppLinkList = pNewNode;

        return;

    }



    /* 找到插入位置 */

    while (index != pos)

    {

        pPrevNode = pPrevNode->pnext;

        index++;

    }

    pNextNode = pPrevNode->pnext;    

    

    /* 2、插入尾部 */

    if (iNodeNum == pos)

    {

        pPrevNode->pnext = pNewNode;

        pNewNode->plast  = pPrevNode;

        return;

    }



    /* 3、插入中间位置 */

    pNewNode->pnext        = pNextNode;

    pNewNode->plast        = pPrevNode;

    pPrevNode->pnext    = pNewNode;

    pNextNode->plast    = pNewNode;



}



void MoveNode(DNODE_S **ppLinkList, int pos)

{

    DNODE_S *node = *ppLinkList;

    DNODE_S *pPrevNode = NULL;

    DNODE_S *pNextNode = NULL;



    while(pos--)

    {

        node = node->pnext;

    }



    pPrevNode = node->plast;

    pNextNode = node->pnext;

    pPrevNode->pnext = pNextNode;

    pNextNode->plast = pPrevNode;



    free(node);

}



#endif



#if 1    /* 数组和链表转换 */

void IntToList(DNODE_S **ppLinkList, int *paiArray, int size)  

{

    int j = 0;

    int data = 0;

    DNODE_S *s = *ppLinkList;



    s->data = *(paiArray + (size-1));



    for(j = 2; j < (size+1); j++)

    {

        data = *(paiArray + (size-j));

        InsertNode(ppLinkList, 0, data);

    }



    return;

}



void ListToInt(DNODE_S *pLinkList, int *paiArray)

{

    int j = 0;

    DNODE_S *s = pLinkList;



    while(s != NULL)

    {

        *(paiArray + j) = s->data;

        s = s->pnext;

        j++;

    }



    return;

}



bool IsValidNum(char c)

{

    if ('0' <= c && c <= '9')

    {

        return true;

    }

    return false;

}



void StringToList(DNODE_S **ppLinkList, const char *pcString)  

{

    int i = 0;

    int j = 0;

    int data = 0;

    int len = (int)strlen(pcString);

    DNODE_S *s = *ppLinkList;



    s->data = pcString[0] - '0';

    

    for(i = 1, j = 1; i < len; i++)

    {

        if (IsValidNum(pcString[i]))

        {

            data = pcString[i] - '0';

            InsertNode(ppLinkList, j, data);

            j++;

        }

    }

    return;

}



void ListToString(DNODE_S *pLinkList, char *pcString)  

{

    int j = 0;

    DNODE_S *s = pLinkList;



    while(s != NULL)

    {

        *(pcString + j) = s->data + '0';

        s = s->pnext;

        j++;

    }



    return;

}

#endif

#if 1

int CompareNum(char *pcNumA, char *pcNumB)

{

    int lenA = (int)strlen(pcNumA);

    int lenB = (int)strlen(pcNumB);



    if (lenA > lenB)

    {

        return 1;

    }

    else if (lenA < lenB)

    {

        return -1;

    }

    else

    {

        return strcmp(pcNumA, pcNumB);

    }

}



int GetDecimalLength(const char *pcNum)

{

    int i = 0;

    int len = (int)strlen(pcNum);

    while (pcNum[i] != '\0' && pcNum[i] != '.')

    {

        i++;

    }

    if (i == len)

    {

        return 0;

    }

    return len - i - 1;

}



char* EnlargeNum(const char *pcNum, int size)

{

    int i = 0, j = 0, k = 0;

    char pcTemp[1024] = {0};

    int iDecimalLen = GetDecimalLength(pcNum);

    char *pcResult = NULL;



    if (iDecimalLen > size)

    {

        return NULL;

    }

    

    /* 如果是整数,则直接在末尾补上size个'0' */

    if (0 == iDecimalLen)

    {

        memcpy(pcTemp, pcNum, strlen(pcNum));

        memset(pcTemp + strlen(pcNum), '0', size);

        pcResult = (char*) malloc (strlen(pcNum)+size+1);

        memset(pcResult, 0, strlen(pcNum)+size+1);

        memcpy(pcResult, pcTemp, strlen(pcTemp));



        return pcResult;

    }

    /* 如果是小数, 先偏移小数点,如果不够,末尾补'0' */

    while (pcNum[i] != '\0')

    {

        if (pcNum[i] == '.')

        {

            i++;

            k = 0;

            continue;

        }



        pcTemp[j] = pcNum[i];

        i++;

        j++;

        k++;

    }

    memset(pcTemp + j, '0', size - k); 



    /* 如果数字以'0'开头,要去除 */    

    if(pcTemp[0] == '0')

    {

        pcResult = (char*) malloc (strlen(pcTemp));

        memset(pcResult, 0, strlen(pcTemp));

        memcpy(pcResult, pcTemp + 1, strlen(pcTemp)-1);

    }

    else      

    {

        pcResult = (char*) malloc (strlen(pcTemp)+1);

        memset(pcResult, 0, strlen(pcTemp)+1);

        memcpy(pcResult, pcTemp, strlen(pcTemp));

    }

    return pcResult;

}



#endif



#if 1

void OperatePlus(int numA, int numB, int &result, int &carry)

{

    result = numA + numB + carry;

    carry = result / 10;

    result = result % 10;

}



void ExceedPlusAlgorithm(DNODE_S **ppResult, DNODE_S *pLastNode, int carry)

{

    int sum = 0;



    while (pLastNode->plast != NULL)

    {

        pLastNode = pLastNode->plast;

        OperatePlus(pLastNode->data, 0, sum, carry);

        InsertNode(ppResult, 0, sum);           

    }

    if (0 != carry)

    {

        InsertNode(ppResult, 0, carry);  

    }

    return;

}



void BigIntegerPlus(DNODE_S **ppResult, DNODE_S **ppNumA, DNODE_S **ppNumB)

{

    int sum        = 0;

    int carry    = 0;    

    int iLenOfA = 0;

    int iLenOfB = 0;

    DNODE_S *pLastNodeOfA    = NULL;

    DNODE_S *pLastNodeOfB    = NULL;

    DNODE_S *pNewNode        = NULL;



    if (NULL == ppNumA || NULL == ppNumB)

    {

        return;

    }



    iLenOfA = GetListLength(ppNumA);

    iLenOfB = GetListLength(ppNumB);

    if (0 == iLenOfA)

    {

        ppResult = ppNumB;

        return;

    }

    if (0 == iLenOfB)

    {

        ppResult = ppNumA;

        return;

    }

    

    GetLastNode(ppNumA, &pLastNodeOfA);

    GetLastNode(ppNumB, &pLastNodeOfB);



    /* 1、从两个数组最末位开始向前扫描,把对应的位数相加,有进位则加入前一位中 */

    OperatePlus(pLastNodeOfA->data, pLastNodeOfB->data, sum, carry);

    CreateDoubleLinkList(ppResult, sum);

    while (pLastNodeOfA->plast != NULL && pLastNodeOfB->plast != NULL)

    {

        pLastNodeOfA = pLastNodeOfA->plast;

        pLastNodeOfB = pLastNodeOfB->plast;

        OperatePlus(pLastNodeOfA->data, pLastNodeOfB->data, sum, carry);

        InitNewNode(&pNewNode, sum);

        InsertNode(ppResult, 0, sum);        

    }

   

    /* 2、如果P/Q两个数组数字一样多,则判断是否有进位 */

    if (pLastNodeOfA->plast == NULL && pLastNodeOfB->plast == NULL)

    {

        if (0 != carry)

        {

            InsertNode(ppResult, 0, carry);  

        }

        return;

    }



    /* 3、把没有扫描完的数组里的数字全部加入plus数组 */

    if (pLastNodeOfB->plast != NULL)

    {

        ExceedPlusAlgorithm(ppResult, pLastNodeOfB, carry);

        return;

    }

    

    if (pLastNodeOfA->plast != NULL)

    {

        ExceedPlusAlgorithm(ppResult, pLastNodeOfA, carry);

        return;

    }

}

#endif

#if 1

void OperateSub(int numA, int numB, int &result, int &carry)

{

    if (numA + carry >= numB)

    {



        result = numA + carry - numB ;

        carry = 0;

    }

    else

    {

        result = numA + carry + 10 - numB ;

        carry = -1;

    }

}



void ExceedSubAlgorithm(DNODE_S **ppResult, DNODE_S *pLastNode, int carry)

{

    int sum = 0;



    while (pLastNode->plast != NULL)

    {

        pLastNode = pLastNode->plast;

        OperateSub(pLastNode->data, 0, sum, carry);

        InsertNode(ppResult, 0, sum);           

    }

    if (0 != carry)

    {

        InsertNode(ppResult, 0, carry);  

    }

    return;

}









void BigIntegerSub(DNODE_S **ppResult, DNODE_S **ppNumA, DNODE_S **ppNumB)

{

    int sum        = 0;

    int carry    = 0;    

    int iLenOfA = 0;

    int iLenOfB = 0;

    DNODE_S *pLastNodeOfA    = NULL;

    DNODE_S *pLastNodeOfB    = NULL;

    DNODE_S *pNewNode        = NULL;



    if (NULL == ppNumA || NULL == ppNumB)

    {

        return;

    }



    iLenOfA = GetListLength(ppNumA);

    iLenOfB = GetListLength(ppNumB);

    if (0 == iLenOfA)

    {

        ppResult = ppNumB;

        return;

    }

    if (0 == iLenOfB)

    {

        ppResult = ppNumA;

        return;

    }

    

    GetLastNode(ppNumA, &pLastNodeOfA);

    GetLastNode(ppNumB, &pLastNodeOfB);



    /* 1、从两个数组最末位开始向前扫描,把对应的位数相加,有进位则加入前一位中 */

    OperateSub(pLastNodeOfA->data, pLastNodeOfB->data, sum, carry);

    CreateDoubleLinkList(ppResult, sum);

    while (pLastNodeOfA->plast != NULL && pLastNodeOfB->plast != NULL)

    {

        pLastNodeOfA = pLastNodeOfA->plast;

        pLastNodeOfB = pLastNodeOfB->plast;

        OperateSub(pLastNodeOfA->data, pLastNodeOfB->data, sum, carry);

        InitNewNode(&pNewNode, sum);

        InsertNode(ppResult, 0, sum);        

    }



    /* 2、如果P/Q两个数组数字一样多,则判断是否有进位 */

    if (pLastNodeOfA->plast == NULL && pLastNodeOfB->plast == NULL)

    {

        if (0 != carry)

        {

            InsertNode(ppResult, 0, carry);  

        }

        return;

    }



    /* 3、把没有扫描完的数组里的数字全部加入plus数组 */

    if (pLastNodeOfA->plast != NULL)

    {

        ExceedSubAlgorithm(ppResult, pLastNodeOfA, carry);

        return;

    }

   

    return;



}



char* FromatOutpuString(DNODE_S *pstResult, int iMaxDecimal, int flag)

{

    int i        = 0;

    int j        = 0;

    int size    = 0;

    

    char *pcResult    = NULL;

    char *pcResultCopy = NULL;

    

    /* 分配内存,要考虑正负号、小数点和末尾'\0',所以分配大小为size+3 */

    size = GetListLength(&pstResult);

    pcResult = (char*)malloc(size+3);

    memset(pcResult, 0, size+3);

    pcResultCopy = (char*)malloc(size+3);

    

    memset(pcResultCopy, 0, size+3);

    ListToString(pstResult, pcResult);



    /* 去除计算结果前面多余的0,如0345,改为345 */

    while (pcResult[i] != '\0')

    {

        if (pcResult[i] != '0')

        {

            break;

        }

        i++;

        size--;

    }

    memcpy(pcResultCopy, pcResult + i, strlen(pcResult)-i+1);

    memset(pcResult, 0, size+3);

    printf("\r\n 去除前面的0: pcResultCopy = %s", pcResultCopy);



    i = 0;

    j = 0;

    /* 设置正负号 */

    if (1 == flag)

    {

        pcResult[j++] = '-';

    }

    if (iMaxDecimal > 0)

    {

        /* 原操作数有小数,需要还原小数点 */

        while (i < size - iMaxDecimal)

        {

            pcResult[j++] = pcResultCopy[i++];

        }

        memset(pcResult + j, '.', 1);

        memcpy(pcResult + j + 1, pcResultCopy + i, iMaxDecimal);

    }

    else

    {

        /* 若没有小数,直接把结果拷贝给pcResult */

        memcpy(pcResult + j, pcResultCopy, size);

    }

    printf("\r\n 尚未去除尾部的0: pcResultCopy = %s, iMaxDecimal = %d", pcResult

, iMaxDecimal);

    

    /* 消除尾部的0 */

    i = (int)strlen(pcResult) - 1;

    while (i >= 0)

    {

        if (pcResult[i] == '0')

        {

            pcResult[i] = '\0';

        }

        else if (pcResult[i] == '.')

        {

            pcResult[i] = '\0';

            break;

        }

        else

        {

            break;

        }

        i--;

    }

    return pcResult;

}





void BigNumSub(const char *pcMinuend, const char *pcSubtrahend, char **

ppcResult)

{

    int i = 0;

    int j = 0;

    int flag             = 0;

    int compare            = 0;

    int iLenDecimalA    = 0;

    int iLenDecimalB    = 0;

    int iMaxDecimal        = 0;

    DNODE_S *pstNumA    = NULL;

    DNODE_S *pstNumB    = NULL;

    DNODE_S *pstResult    = NULL;



    char *pcTemp = NULL;

    char *pcMinuendEnlarge = NULL;

    char *pcSubtrahendEnlarge = NULL;

    char *pcFinalResult = NULL;



    /* 获取最长小数位数 */

    iLenDecimalA = GetDecimalLength(pcMinuend);

    iLenDecimalB = GetDecimalLength(pcSubtrahend);

    iMaxDecimal = (iLenDecimalA > iLenDecimalB) ? iLenDecimalA : iLenDecimalB;



    /* 按最长小数位数放大两个操作数 */

    pcMinuendEnlarge    = EnlargeNum(pcMinuend,iMaxDecimal);

    pcSubtrahendEnlarge    = EnlargeNum(pcSubtrahend, iMaxDecimal);



    /* 比较数字大小 */

    compare = CompareNum(pcMinuendEnlarge, pcSubtrahendEnlarge);

    if (compare < 0)    /* 被减数小于减数,则交换数字字符串,并把正负标志位置为1 

*/

    {

        pcTemp = pcMinuendEnlarge;

        pcMinuendEnlarge = pcSubtrahendEnlarge;

        pcSubtrahendEnlarge = pcTemp;

        flag = NEGATIVE_NUMBER;

    }

    if (compare == 0)    /* 两数相等,则直接返回结果为0的字符串 */

    {

        pcFinalResult = (char*)malloc(2);

        memset(pcFinalResult, 0, 2);

        pcFinalResult[0] = '0';

        *ppcResult = pcFinalResult;

        return;

    }

#if TEST    

    printf("\r\n ============== Change Num ==============");

    printf("\r\n pcMinuendEnlarge = %s", pcMinuendEnlarge);

    printf("\r\n pcSubtrahendEnlarge = %s", pcSubtrahendEnlarge);

#endif    

    /* 把放大后的两个整数字符串放入链表,然后逐位相减 */

    CreateDoubleLinkList(&pstNumA, 0);

    CreateDoubleLinkList(&pstNumB, 0);

    CreateDoubleLinkList(&pstResult, 0);

    StringToList(&pstNumA, pcMinuendEnlarge);

    StringToList(&pstNumB, pcSubtrahendEnlarge);   

    BigIntegerSub(&pstResult, &pstNumA, &pstNumB);



    /* 恢复小数点,并去除整数前的0和小数尾部的0 */

    pcFinalResult = FromatOutpuString(pstResult, iMaxDecimal, flag);

  

    *ppcResult = pcFinalResult;

    free(pstNumA);

    free(pstNumB);

    free(pstResult);

}

#endif







/*****************************************************************************

Description  : 两个任意长度的正数相减

Prototype    : int Decrease(const char *pMinuend, const char *pSubtrahend, 

char **ppResult)

Input Param  : const char *pMinuend     被减数,以\0表示字符串结束

               const char *pSubtrahend  减数,以\0表示字符串结束

Output       : char **ppResult          减法结果,必须以\0表示字符串结束

Return Value : 成功返回0   失败返回-1

*****************************************************************************/

int Decrease(const char *pcMinuend, const char *pcSubtrahend, char **ppResult)

{

#if TEST

    printf("\r\n ============== Origin Num ==============");

    printf("\r\n pcMinuend = %s", pcMinuend);

    printf("\r\n pcSubtrahend = %s", pcSubtrahend);

#endif   

    BigNumSub(pcMinuend, pcSubtrahend, ppResult);

    printf("\r\n ppResult = %s", *ppResult);



    return 0;

}



int main(void)

{

    char str1[] = "999999";

    char str2[] = "11111111111";

    char *str3 = NULL;

    Decrease(str1, str2, &str3);

    return 0;

}

 

你可能感兴趣的:(运算)