链表的十进制加法

题目:给定两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表首部。编写函数对这两个整数求和,并用链表形式返回结果。

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








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值