合并两个排序链表(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;
 }

步骤图:(从左往右看

 

 

 法二:双指针

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

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
合并两个有序链表可以使用归并排序的思想,具体步骤如下: 1. 新建一个头结点,用于指向合并后的链表。 2. 分别用指针 p1 和 p2 指向两个有序链表的头结点。 3. 新建一个指针 p3,用于指向合并链表的尾结点。 4. 比较 p1 和 p2 结点的值,将较小的结点插入到 p3 的后面,并将 p1 或 p2 指针后移一位。 5. 重复步骤 4 直到两个链表中有一个为空。 6. 将另一个非空链表接到合并链表的尾部。 下面是 C 语言实现的代码示例: ```c #include <stdio.h> #include <stdlib.h> typedef struct ListNode { int val; struct ListNode* next; } ListNode; ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode* dummy = (ListNode*)malloc(sizeof(ListNode)); // 新建头结点 ListNode* p3 = dummy; // p3 指向合并链表的尾结点 while (l1 && l2) { // 比较 l1 和 l2 结点的值,将较小的结点插入到 p3 的后面 if (l1->val < l2->val) { p3->next = l1; l1 = l1->next; } else { p3->next = l2; l2 = l2->next; } p3 = p3->next; } if (l1) p3->next = l1; // 将另一个非空链表接到合并链表的尾部 if (l2) p3->next = l2; return dummy->next; // 返回头结点的下一个结点 } int main() { // 新建两个有序链表 ListNode* l1 = (ListNode*)malloc(sizeof(ListNode)); l1->val = 1; ListNode* l1_1 = (ListNode*)malloc(sizeof(ListNode)); l1_1->val = 2; ListNode* l1_2 = (ListNode*)malloc(sizeof(ListNode)); l1_2->val = 4; l1->next = l1_1; l1_1->next = l1_2; l1_2->next = NULL; ListNode* l2 = (ListNode*)malloc(sizeof(ListNode)); l2->val = 1; ListNode* l2_1 = (ListNode*)malloc(sizeof(ListNode)); l2_1->val = 3; ListNode* l2_2 = (ListNode*)malloc(sizeof(ListNode)); l2_2->val = 4; l2->next = l2_1; l2_1->next = l2_2; l2_2->next = NULL; // 合并两个有序链表 ListNode* merged = mergeTwoLists(l1, l2); // 输出合并后的链表 ListNode* p = merged; while (p) { printf("%d ", p->val); p = p->next; } printf("\n"); return 0; } ``` 输出结果为:1 1 2 3 4 4。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值