[算法题] 大数减法运算
//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; }