用C语言合并两个按递增排序的链表

本文介绍如何使用C语言创建两个递增排序的链表并将其合并为一个新链表,新链表保持递增排序。通过示例代码展示了链表的创建、输入、输出以及合并过程。

       最近通过对数据结构的学习,对链表有了更深的认识.在单向链表中,关键是确定下一结点的指针.现在通过一题目详细说明(在VC6.0,WINXP PRO SP2上调试通过)

题目要求:建立两个存放整数的链表,按递增的顺序输入数据.将两个链表合并成一个链表,新链表上中的数据仍然按照递增排序. 

程序如下:

#include <stdio.h>
#include <stdlib.h>

typedef struct intnumber
{
 int n;
 struct intnumber *next;
}INTNUM;

INTNUM *creat(int num)/*建立链表*/
{
 INTNUM *p1,*p2,*head;
 int i;
 p1 = (INTNUM *)malloc(sizeof(INTNUM));
 head = p1;
 p2 = p1;
 for(i = 0;i < num - 1;i++)
 {
  p1 = (INTNUM *)malloc(sizeof(INTNUM));
  p2 ->next = p1;
  p2 = p1;
 }
 p1 ->next = NULL;
 return head;
}

void input(INTNUM *head)/*输入链表数据*/
{
 INTNUM *p;
 p = head;
 while(p ->next != NULL)
 {
  scanf("%d",&(p ->

### 3.1 算法设计思路 合并两个有序链表的核心思想是利用两个指针分别遍历两个链表,每次选择当前较小的节点插入到新链表中,从而保证最终链表的有序性。若其中一个链表提前遍历完,则将另一个链表的剩余部分直接链接到结果链表末尾 [^3]。 该算法的关键在于: - 使用一个虚拟头节点(dummy node)来简化链表操作,避免处理空指针等边界条件。 - 维护一个指向结果链表尾部的指针(tail),以便于在每次插入节点时更新链表末尾。 - 在循环中比较两个链表当前节点的值,并将较小的节点连接到结果链表。 - 若其中一个链表已经遍历完毕,则直接将另一个链表的剩余部分链接到结果链表。 ### 3.2 C语言实现代码 以下是使用C语言实现的两个有序链表合并排序算法: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构体 typedef struct Node { int val; struct Node* next; } Node; // 创建新节点的函数 Node* createNode(int val) { Node* node = (Node*)malloc(sizeof(Node)); node->val = val; node->next = NULL; return node; } // 合并两个有序链表函数 Node* mergeSort(Node* list1, Node* list2) { // 创建一个虚拟头节点,用于方便处理 Node dummy; Node* tail = &dummy; dummy.next = NULL; // 循环比较两个链表的节点值,并将较小的节点加入结果链表 while (list1 && list2) { if (list1->val <= list2->val) { tail->next = list1; list1 = list1->next; } else { tail->next = list2; list2 = list2->next; } tail = tail->next; } // 链接剩余数据 tail->next = list1 ? list1 : list2; // 如果有一个链表NULL,直接链接另一个链表的剩余部分 [^4] // 返回合并后的链表头节点 return dummy.next; } ``` ### 3.3 测试与验证 为了验证算法的正确性,可以构造如下测试用例: - 构造两个递增顺序的链表,例如 `1 -> 3 -> 5` `2 -> 4 -> 6`,合并后应为 `1 -> 2 -> 3 -> 4 -> 5 -> 6`。 - 构造一个链表一个非空链表合并后应返回非空链表。 - 构造两个链表,其中一部分节点值相等,如 `2 -> 2 -> 3` `2 -> 4 -> 5`,合并后应保持有序且值顺序正确 [^3]。 以下是一个简单的测试示例: ```c int main() { // 构造第一个有序链表:1 -> 3 -> 5 Node* list1 = createNode(1); list1->next = createNode(3); list1->next->next = createNode(5); // 构造第二个有序链表:2 -> 4 -> 6 Node* list2 = createNode(2); list2->next = createNode(4); list2->next->next = createNode(6); // 合并两个链表 Node* mergedList = mergeSort(list1, list2); // 打印合并后的链表 Node* current = mergedList; while (current != NULL) { printf("%d ", current->val); current = current->next; } return 0; } ``` 输出结果应为: ``` 1 2 3 4 5 6 ``` ### 3.4 时间与空间复杂度分析 - **时间复杂度**:整个过程需要遍历两个链表的所有节点一次,因此时间复杂度为 `O(m + n)`,其中 `m` `n` 分别为两个链表的长度。 - **空间复杂度**:仅使用常数级别的额外空间(如虚拟头节点、尾指针等),因此空间复杂度为 `O(1)`。 ### 3.5 注意事项与常见问题 - 若输入的链表排序,则需先对链表进行排序再执行合并操作,否则无法保证合并后的链表有序。 - 必须确保链表节点内存分配功,否则可能导致程序崩溃。 - 虚拟头节点的使用可简化边界条件处理,但在返回结果时应注意跳过该节点。 - 当两个链表中存在相同值的节点时,算法允许任意一个节点优先插入,不影响最终有序性 [^4]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值