您的位置:首页 > 其它

[算法题] 大数减法运算

2017-09-01 09:50 363 查看
 
//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
4000


 

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


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: