leetcode 21. 合并两个有序链表(c++解法+相关知识点复习)
目录
题目
所需知识点复习
1.链表
1.1单链表
1.2哑结点(Dummy Node)
解答过程
1.循环+双指针解法
2.递归解法
2025.4.29想到其他知识点会后续再继续补充。
题目
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
提示:
- 两个链表的节点数目范围是
[0, 50]
-100 <= Node.val <= 100
l1
和l2
均按 非递减顺序 排列
所需知识点复习
1.链表
链表(Linked List)是一种线性数据结构,由一系列的节点(Node)组成,每个节点包含:
1.数据域(val):存储数据
2.指针域(next):指向下一个节点
与数组不同,链表的内存不是连续存储的,而是通过指针连接各个节点。
1.1单链表
-
每个节点包含val和next指针
-
只能单向遍历(从头到尾)
- 代码示例
-
struct ListNode {int val;ListNode *next;ListNode(int x) : val(x), next(nullptr) {} };
-
判断链表是否为空:list1==nullptr
-
在 C++ 中运算符的使用:
- 当变量是对象实例时(如
ListNode dummy
),使用.
运算符访问成员(如dummy.next
) - 当变量是指向对象的指针时(如
ListNode* l1
),使用->
运算符访问成员(如l1->val
)
- 当变量是对象实例时(如
1.2哑结点(Dummy Node)
哑结点(Dummy Node)是链表操作中常用的技巧,他是一个不存储实际数据的辅助节点,通常作为临时头节点,用于简化链表操作,尤其是在处理边界情况(如空链表、头节点变化等)时非常有用。(常用技巧,可以多加记忆!)
哑结点作用:
- 避免空指针异常:当链表可能为空时,使用哑结点可以确保始终有一个初始节点。
- 简化插入/删除操作:不需要单独处理头节点的特殊情况,所有操作都可以统一处理。
- 方便返回结果:最终返回
dummy.next
即可得到合并后的链表头,无需额外判断。
ListNode dummy(0); // 创建一个哑结点,值为 0(值不重要)
ListNode* p = &dummy; // p 是遍历指针,初始指向哑结点
-
dummy
是一个临时头节点,p
用于逐个连接l1
和l2
的节点。 -
最终返回
dummy.next
,因为dummy.next
才是合并后的链表的真正头节点。
解答过程
毫无疑问,我自己没做出来,对链表知识点不熟悉了,紧急复习知识点,并学习了哑结点的使用。
我自己做是,想到了之前两个数组的排序采用的双指针,但是链表是不一样的。
采用循环+双指针的方法进行。方法二就是递归,这个也需要我好好理解一下。
1.循环+双指针解法
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if(l1==nullptr) return l2;if(l2==nullptr) return l1;ListNode dummy(0);//哑结点用来简化操作ListNode* p=&dummy;//当前节点指针while(l1!=nullptr && l2!=nullptr){if(l1->val>=l2->val){//l1大于l2时,结果指向l2的值p->next=l2;//要移动的应该是指针,而不是直接赋值:eg:p=l2.val是错的。应该创建新节点并连接l2=l2->next;}else{//l1小于l2,结果指向l1的值p->next=l1;l1=l1->next;}p=p->next;}// if(l1!=nullptr){// p->next=l1;// }// if(l2!=nullptr){// p->next=l2;// }p->next=(l1!=nullptr)?l1:l2;//替换上面6行代码return dummy.next;}
};
2.递归解法
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if(l1==nullptr) return l2;if(l2==nullptr) return l1;if(l1->val<l2->val){l1->next=mergeTwoLists(l1->next,l2);return l1;}l2->next=mergeTwoLists(l1,l2->next);return l2;}
};