[算法题] 大数减法运算

 

//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;
}

 

posted @ 2014-06-16 21:51  静默虚空  阅读(842)  评论(0编辑  收藏  举报