1. 两个有序链表的合并
有序链表合并问题可以分成两个问题来考虑:第一个问题是如何将链表中的元素按照大小顺序合并,第二个问题是如何将两个有序链表合并成一个有序链表。
对于第一个问题,我们可以利用递归的思想,从链表的头节点开始,逐个比较链表中的元素大小,将较小的元素放到前面,直到链表排完为止。具体实现代码如下所示:
// 定义节点结构体
struct ListNode {
int val;
struct ListNode *next;
};
// 递归实现链表排序
struct ListNode* mergeSort(struct ListNode* l1, struct ListNode* l2) {
if (l1 == NULL) return l2;
if (l2 == NULL) return l1;
if (l1->val < l2->val) {
l1->next = mergeSort(l1->next, l2);
return l1;
} else {
l2->next = mergeSort(l1, l2->next);
return l2;
}
}
对于第二个问题,即如何合并两个有序链表,我们可以分别从两个链表的头节点开始进行比较,将较小的元素加入新链表中,并将指针向后移动。具体实现代码如下所示:
// 迭代实现链表合并
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
struct ListNode dummy;
dummy.next = NULL;
struct ListNode* tail = &dummy;
while (l1 != NULL && l2 != NULL) {
if (l1->val < l2->val) {
tail->next = l1;
l1 = l1->next;
} else {
tail->next = l2;
l2 = l2->next;
}
tail = tail->next;
}
if (l1 != NULL) {
tail->next = l1;
}
if (l2 != NULL) {
tail->next = l2;
}
return dummy.next;
}
2. 问题分析与解决方案
2.1 问题分析
假设有两个有序链表A和B,它们的长度分别为n和m,现在我们要将它们合并成一个新的有序链表C。具体来说,就是将A和B中的元素按从小到大的顺序逐个加入C中。例如:
A链表:1 -> 3 -> 5 -> 7
B链表:2 -> 4 -> 6 -> 8
C链表:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
为了方便,我们假设节点中存储的是整数类型的元素。在C语言中,我们可以通过定义链表节点结构体来表示链表中的一个节点,如下所示:
// 定义节点结构体
struct ListNode {
int val;
struct ListNode *next;
};
其中,val表示节点中存储的元素,next表示指向下一个节点的指针。由于是单向链表,因此只需要指向下一个节点的指针即可。
在实现链表合并算法之前,我们需要对问题进行进一步分析。在合并链表时,我们需要对比A和B中的元素大小,将较小的元素加入C中。因此,我们需要定义一个比较函数来比较节点的值大小,具体实现代码如下:
int cmp(struct ListNode* a, struct ListNode* b) {
return a->val - b->val;
}
然后,我们就可以使用链表排序和链表合并算法来解决问题了。
2.2 解决方案
我们可以先对A和B中的元素进行排序,然后再进行合并。具体的流程如下:
先定义一个指向链表节点的指针p,初始值为头节点。
将A和B中的所有节点依次加入一个数组中(可以使用动态数组来实现),然后对数组进行排序,排序完成后依次将节点加入新的链表中。
在将节点加入新的链表C时,需要注意链表的头节点和尾节点的处理。
具体实现代码如下所示:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
/**
* Compare function used when sorting the array of nodes.
*/
int cmp(const void* a, const void* b) {
struct ListNode* node1 = *(struct ListNode**)a;
struct ListNode* node2 = *(struct ListNode**)b;
return node1->val - node2->val;
}
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
// If either list is empty, return the other list.
if (l1 == NULL) {
return l2;
}
if (l2 == NULL) {
return l1;
}
// Build an array of nodes from the input lists.
int len1 = 0, len2 = 0;
struct ListNode* p1 = l1;
while (p1 != NULL) {
len1++;
p1 = p1->next;
}
struct ListNode* p2 = l2;
while (p2 != NULL) {
len2++;
p2 = p2->next;
}
struct ListNode** arr = (struct ListNode**)malloc(sizeof(struct ListNode*) * (len1 + len2));
int i = 0;
p1 = l1;
while (p1 != NULL) {
arr[i++] = p1;
p1 = p1->next;
}
p2 = l2;
while (p2 != NULL) {
arr[i++] = p2;
p2 = p2->next;
}
// Sort the array of nodes.
qsort(arr, len1 + len2, sizeof(struct ListNode*), cmp);
// Build the output list from the sorted array.
struct ListNode* head = arr[0];
struct ListNode* tail = arr[0];
for (int i = 1; i < len1 + len2; i++) {
tail->next = arr[i];
tail = tail->next;
}
tail->next = NULL;
// Free the array of nodes.
free(arr);
// Return the head of the output list.
return head;
}
3. 总结
本篇文章介绍了如何合并两个有序链表的算法。具体来说,我们可以使用链表排序和链表合并算法来解决问题。在实现过程中,需要定义一个比较函数来比较节点的值大小,然后对A和B中的元素进行排序,最后依次将节点加入新的链表中。