鏈表的十進制加法

題目:給定兩個用鏈表表示的整數,每個結點包含一個數位。這些數位是反向存放的,也就是個位排在鏈表首部。編寫函數對這兩個整數求和,並用鏈表形式返回結果。

示例 輸入:(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);
}








發佈了147 篇原創文章 · 獲贊 18 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章