LeetCode 两数相加 链表操作的思考

LeetCode 两数相加 链表操作的思考

题目描述:
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

遇到的问题:
样例执行似乎没有问题,但是提交就出错:

Line 22: Char 22: runtime error: member access within null pointer of type 'struct ListNode' (solution.c)

经过检查发现,当 p 的 next 域为空时,此时建立新节点,然后再将其添加到链表尾端,比较麻烦,因为需要记住前一个节点,将其指针域指向刚刚创建的新节点。于是乎,经过分析,我们可以这样解决这个问题:

  • 为了此操作不会影响到链表的状态,我们决定牺牲一些内存资源,创建一个新的带头节点的链表,注意是带头节点的,这样后续操作会方便一些。

  • 将进位 carry 初始化为 0。

  • 将 p 和 q 分别初始化为列表 l1 和 l2 的头部(就是第一个节点,本题中的链表是不带头节点的)。

  • 遍历列表 l1 和 l2 直至到达它们的尾端。

  • 将 x 设为结点 p 的值。如果 p 已经到达 l1 的末尾,则将其值设置为 0 (这里可以理解为将两个长度不一致链表用 0 扩展为相等的,这一点很重要、很关键、很巧妙,反正我当时没想到)。

  • 将 y 设为结点 q 的值。如果 q 已经到达 q 的末尾,则将其值设置为 0 (与上一步类似)。

  • 设定 sum=x+y+carry。

  • 更新进位的值,carry=sum/10

  • 创建一个数值为 (sum mod 10) 的新结点,并将其设置为当前结点的下一个结点,然后将当前结点前进到下一个结点。

  • 将 p 和 q 前进到下一个结点。

  • 检查 carry=1carry = 1carry=1 是否成立,如果成立,则向返回列表追加一个含有数字 111 的新结点。

  • 返回头指针的下一个结点,因为我们创建的是一个带有头结点的链表。

  • 结束
    源码(已经全部写好,可以直接调试运行):

#define _CRT_SECURE_NO_WARNINGS	/*vs 下写的, scanf 会出错,忽略*/
#include <stdio.h>
#include <stdlib.h>

struct ListNode 
{
      int val;
	  int len;
      struct ListNode *next;
};
 
struct ListNode *creatList()
{
	int i = 0 , n = 0;
	puts("enter number of list:\n");
	scanf("%d", &n);

	struct ListNode *head = NULL, *rear = NULL, *behind = NULL;
	for (i = 0; i < n; i++)
	{
		behind = (struct ListNode *) malloc(sizeof(struct ListNode));	/*申请存储空间*/
		/*填充一个结点的信息*/
		puts("enter data zone:");
		scanf("%d", &behind->val);
		if (i == 0)	/*链表为空则把新结点存入头指针*/
		{
			rear = behind;
			head = behind;
		}
		else
		{
			rear->next = behind;    /*链表不空则把新结点连到前一结点的后面*/
			head->len++;
		}
		behind->next = NULL;		/*使新结点的指针域为空*/
		rear = behind;				/* rear移动到新结点上*/
	}
	return  head;                   /*返回链表头指针*/
}

void output(struct ListNode *head)
{
	struct ListNode *p = head;
	puts("list data:\n");
	while (p)
	{
		printf("%-3d", p->val);
		p = p->next;
	}
	puts("\n");
}

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2)
{
	struct ListNode *p = l1, *q = l2;
	struct ListNode *newHead = (struct ListNode *)malloc(sizeof(struct ListNode));
	struct ListNode *curr = newHead;

	int carry = 0;

	while (p != NULL || q != NULL)
	{
		int x = (p != NULL) ? p->val : 0;
		int y = (q != NULL) ? q->val : 0;
		int sum = x + y + carry;
		carry = sum / 10;
		struct ListNode *node = (struct ListNode *)malloc(sizeof(struct ListNode));
		node->next = NULL;
		node->val = sum % 10;
		curr->next = node;
		curr = curr->next;
		if (p != NULL)
			p = p->next;
		if (q != NULL)
			q = q->next;
	}
	if (carry > 0)
	{
		struct ListNode *node = (struct ListNode *)malloc(sizeof(struct ListNode));
		node->next = NULL;
		node->val = 1;
		curr->next = node;
	}
	return newHead->next;
}

int main(void)
{
	struct ListNode *ListHead1 = creatList();
	struct ListNode *ListHead2 = creatList();
	output(ListHead1);
	output(ListHead2);

	output(addTwoNumbers(ListHead1, ListHead2));
	return 0;
}

总结

对于指针的操作,一定要谨慎再谨慎。开始改的受,只是将 curr 的next 域指向了新节点,但是并没有将 curr 本身后移一位,造成只能输出最后一位,单步调试后才发现了这个问题。所以一定要会调试,顺便说一下,VS 真的很强大。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值