zoukankan      html  css  js  c++  java
  • [算法题] 大数减法运算

    //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("
    ");
        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] != '' && 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] != '')
        {
            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;
        
        /* 分配内存,要考虑正负号、小数点和末尾'',所以分配大小为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] != '')
        {
            if (pcResult[i] != '0')
            {
                break;
            }
            i++;
            size--;
        }
        memcpy(pcResultCopy, pcResult + i, strlen(pcResult)-i+1);
        memset(pcResult, 0, size+3);
        printf("
     去除前面的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("
     尚未去除尾部的0: pcResultCopy = %s, iMaxDecimal = %d", pcResult
    , iMaxDecimal);
        
        /* 消除尾部的0 */
        i = (int)strlen(pcResult) - 1;
        while (i >= 0)
        {
            if (pcResult[i] == '0')
            {
                pcResult[i] = '';
            }
            else if (pcResult[i] == '.')
            {
                pcResult[i] = '';
                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("
     ============== Change Num ==============");
        printf("
     pcMinuendEnlarge = %s", pcMinuendEnlarge);
        printf("
     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     被减数,以表示字符串结束
                   const char *pSubtrahend  减数,以表示字符串结束
    Output       : char **ppResult          减法结果,必须以表示字符串结束
    Return Value : 成功返回0   失败返回-1
    *****************************************************************************/
    int Decrease(const char *pcMinuend, const char *pcSubtrahend, char **ppResult)
    {
    #if TEST
        printf("
     ============== Origin Num ==============");
        printf("
     pcMinuend = %s", pcMinuend);
        printf("
     pcSubtrahend = %s", pcSubtrahend);
    #endif   
        BigNumSub(pcMinuend, pcSubtrahend, ppResult);
        printf("
     ppResult = %s", *ppResult);
    
        return 0;
    }
    
    int main(void)
    {
        char str1[] = "999999";
        char str2[] = "11111111111";
        char *str3 = NULL;
        Decrease(str1, str2, &str3);
        return 0;
    }
  • 相关阅读:
    关于might_sleep的一点说明---CONFIG_DEBUG_ATOMIC_SLEEP【转】
    让你的软件飞起来:RGB转为YUV【转】
    Linux终端彩色打印+终端进度条【转】
    Linux中实现一个简单的进度条【转】
    Linux内核官方文档atomic_ops.txt【摘自Linux 内核文档】
    Linux 内核链表的使用及深入分析【转】
    Linux2.6.32内核笔记(5)在应用程序中移植使用内核链表【转】
    spin_lock & mutex_lock的区别? 【转】
    Linux c括号作用域【原创笔记】
    linux C 中的volatile使用【转】
  • 原文地址:https://www.cnblogs.com/jingmoxukong/p/3791737.html
Copyright © 2011-2022 走看看