題目:給定兩個用鏈表表示的整數,每個結點包含一個數位。這些數位是反向存放的,也就是個位排在鏈表首部。編寫函數對這兩個整數求和,並用鏈表形式返回結果。
示例 輸入:(7->1->6) +(5->9->2),即617+295
輸出:2->1->9,即912。
進階 假設這些數位是正向存放的,請再做一遍。
示例 輸入:(6->1->7) + (2->9->5),即617+295.
輸出:9->1->2,即912。
先考慮前一個問題,由於鏈表是從低位開始的,所以可以直接相加保存進位。但是需要注意兩個鏈表的長度可能不相等。如果不使用額外的內存空間,可以把結果保存在較長的鏈表中,如果確定保存在第一個鏈表中,那麼需要記錄上一次相加的結點。因爲當第一個鏈表已經走完而第二個鏈表還沒有結束時,可以將第一個鏈表的上一個結點(即最後一個結點)指向第二個鏈表,後面的相加結果保存在第二個鏈表中。
ListNode* ListAdd(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL)
return pHead2;
if(pHead2 == NULL)
return pHead1;
int carry = 0;
ListNode* node1, *ListEnd;
node1 = ListEnd = pHead1;
ListNode* node2 = pHead2;
while(node1 != NULL || node2 != NULL)
{
if(node1 != NULL && node2 != NULL)
{
node1->m_nValue = node1->m_nValue + node2->m_nValue + carry;
if(node1->m_nValue >= 10)
{
node1->m_nValue = node1->m_nValue - 10;
carry = 1;
}
else
carry = 0;
ListEnd = node1;
node1 = node1->m_pNext;
node2 = node2->m_pNext;
}
else
{
if(node1 == NULL)
{
ListEnd->m_pNext = node2;
node2->m_nValue = node2->m_nValue + carry;
if(node2->m_nValue >= 10)
{
node2->m_nValue = node2->m_nValue - 10;
carry = 1;
}
else
carry = 0;
ListEnd = node2;
node2 = node2->m_pNext;
}
else
{
node1->m_nValue = node1->m_nValue + carry;
if(node1->m_nValue >= 10)
{
node2->m_nValue = node1->m_nValue - 10;
carry = 1;
}
else
carry = 0;
ListEnd = node1;
node1 = node1->m_pNext;
}
}
}
if(carry != 0)
{
ListNode* End = CreateListNode(carry);
ListEnd->m_pNext = End;
}
return pHead1;
}
可以看到上面的方法實在過於繁瑣,不使用輔助空間而且不用遞歸就得在代碼複雜度上做出犧牲,下面利用遞歸併且允許新建鏈表保存結果的情況下,代碼精簡很多。
<span style="font-size:10px;">ListNode* AddCore(ListNode* node1, ListNode* node2, int carry)
{
if(node1 == NULL && node2 == NULL && carry == 0)
return NULL;
ListNode* result = CreateListNode(0);
int value = carry;
if(node1 != NULL)
value += node1->m_nValue;
if(node2 != NULL)
value += node2->m_nValue;
result->m_nValue = value % 10;
ListNode* nextNode = AddCore(node1==NULL?NULL:node1->m_pNext, node2==NULL?NULL:node2->m_pNext, value>=10?1:0);
result->m_pNext = nextNode;
return result;
}
ListNode* ListAdd(ListNode* pHead1, ListNode* pHead2)
{
return AddCore(pHead1, pHead2, 0);
}</span>
下面分析第二個問題,由於第二個問題中的鏈表只是前面問題中的鏈表的反序,因此可以將鏈表反轉,利用前面的算法,最後求得的結果仍然是反序的,再反轉結果,最後就是問題的正向解。
ListNode* AddCore(ListNode* node1, ListNode* node2, int carry)
{
if(node1 == NULL && node2 == NULL && carry == 0)
return NULL;
ListNode* result = CreateListNode(0);
int value = carry;
if(node1 != NULL)
value += node1->m_nValue;
if(node2 != NULL)
value += node2->m_nValue;
result->m_nValue = value % 10;
ListNode* nextNode = AddCore(node1==NULL?NULL:node1->m_pNext, node2==NULL?NULL:node2->m_pNext, value>=10?1:0);
result->m_pNext = nextNode;
return result;
}
ListNode* ReverseListAdd(ListNode* pHead1, ListNode* pHead2)
{
return AddCore(pHead1, pHead2, 0);
}
ListNode* ReverseList(ListNode* pHead)
{
if(pHead == NULL || pHead->m_pNext == NULL)
return pHead;
ListNode* prev = NULL;
ListNode* curr = pHead;
while(curr != NULL)
{
ListNode* next = curr->m_pNext;
curr->m_pNext = prev;
prev = curr;
curr = next;
}
return prev;
}
ListNode* ForwardListAdd(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL)
return pHead2;
if(pHead2 == NULL)
return pHead1;
return ReverseList(ReverseListAdd(ReverseList(pHead1), ReverseList(pHead2)));
}
如果不利用前面一問的結果,正向的鏈表相加也是可以解的。從鏈表的前面結點開始相加,由於前面結點代表高位,它需要低位結點相加的進位,但是低位結點不可能先於高位結點訪問到,這時候就需要用遞歸的辦法了,通過遞歸嵌套出低位來額進位,實際上還是從低位開始先加。同樣需要注意鏈表不等長的問題,如果直接從高位往低位遞歸,就出現了錯位問題,譬如不同表長的兩個鏈表首結點代表的權值是不同的,不應該由他們倆相加。這是後可以考慮在較短鏈表的前面補零的辦法,使兩個鏈表等長。
int AddNodes(ListNode* node1, ListNode* node2)
{
if(node1->m_pNext == NULL && node2->m_pNext == NULL)
node1->m_nValue = node1->m_nValue + node2->m_nValue;
else
node1->m_nValue = node1->m_nValue + node2->m_nValue + AddNodes(node1->m_pNext, node2->m_pNext);
if(node1->m_nValue >= 10)
{
node1->m_nValue = node1->m_nValue - 10;
return 1;
}
else
return 0;
}
ListNode* AddCore(ListNode* pHead1, ListNode* pHead2)
{
if(AddNodes(pHead1, pHead2) == 1)
{
ListNode* newHead = CreateListNode(1);
newHead->m_pNext = pHead1;
return newHead;
}
else
return pHead1;
}
ListNode* ForwardListAdd(ListNode** pHead1, ListNode** pHead2)
{
if(pHead1 == NULL || pHead2 == NULL)
return NULL;
if(*pHead1 == NULL)
return *pHead2;
if(*pHead2 == NULL)
return *pHead1;
//短鏈表補零
int size1, size2;
size1 = size2 = 0;
for(ListNode* node1 = *pHead1; node1 != NULL; node1 = node1->m_pNext,++size1);
for(ListNode* node2 = *pHead2; node2 != NULL; node2 = node2->m_pNext,++size2);
if(size1 != size2)
{
for(int i = 0; i < abs(size1 - size2); ++i)
{
ListNode* newHead = CreateListNode(0);
if(size1 < size2)
{
newHead->m_pNext = *pHead1;
*pHead1 = newHead;
}
else
{
newHead->m_pNext = *pHead2;
*pHead2 = newHead;
}
}
}
return AddCore(*pHead1, *pHead2);
}