合并两个排序链表(C语言)

先看题,其实题目很明白:

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

示例1:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

这道题有递归和非递归做法,主要学习的是递归的想法。

题目的函数:

struct ListNode *mergeTwoLists(struct ListNode *l1, struct ListNode *l2){}

法一:递归

我们以下面这个例子来看怎么做递归:

1->6->7 头指针l1

2->5->8 头指针l2

l1的值比l2小,所以l1应该排在l2后面,但是不能直接就把l1->next指向l2,因为l2和l1->next的节点的值还没比过,所以得出结论,l1的next应该指向l2或者还是l1->next。

所以我们再次调用本函数,并且写成 l1->next=mergeTwoLists(l1->next,l2);

所以现在我们就可以写出一个条件判断语句了:

 if (l1->val < l2->val)
         l1->next = mergeTwoLists(l1->next, l2);
     else
         l2->next = mergeTwoLists(l1, l2->next);

一直递归调用函数,直到l1或者l2有一个是NULL,这时候我们可以写递归出口了。如果l1是空,那么上一个l1的值其实就比l2小了,l2应该排在最后面,这时不管l2到没到链表最后也没事,l2后面的节点的值都比l1的大,那么就直接返回l2。

if (l1 == NULL || l2 == NULL)
         return l1 == NULL ? l2 : l1;

把递归出口放在函数开头。

但是我们这个函数返回的是指针类型,最后总归要return一个指针,return谁?

看看我们什么时候调用的:l1->next = mergeTwoLists(l1->next, l2);

如果是这个情况,mergeTwoLists(l1->next, l2)应该返回谁?我们之前分析的是l1的next应该指向l2或者还是l1->next。其实就是指向对应val小的那一个,所以我们要比较l1->next和l2的val的值谁小,而在递归函数中,l1->next被传值赋成了l1,所以就是比较下一个递归函数中l1,l2谁的val小,谁小就return谁。

return l1->val < l2->val ? l1 : l2;

合并我们上面给出的代码:

struct ListNode *mergeTwoLists(struct ListNode *l1, struct ListNode *l2) {
	 if (l1 == NULL || l2 == NULL)
		 return l1 == NULL ? l2 : l1;
	 if (l1->val < l2->val)
		 l1->next = mergeTwoLists(l1->next, l2);
	 else
		 l2->next = mergeTwoLists(l1, l2->next);
	 return l1->val < l2->val ? l1 : l2;
 }

步骤图:(从左往右看

 

合并两个排序链表(C语言)_第1张图片合并两个排序链表(C语言)_第2张图片

合并两个排序链表(C语言)_第3张图片合并两个排序链表(C语言)_第4张图片

 合并两个排序链表(C语言)_第5张图片合并两个排序链表(C语言)_第6张图片

 法二:双指针

 简单提一下双指针,就是l1和l2不停比较然后迭代,这个不详细说了,详情去看网上的题解吧。

你可能感兴趣的:(链表,c语言,数据结构,leetcode)