单链表重新排列
题目:
给定一个单链表 L(a1, a2, a3, …, an),将其重新排列为 (a1, an, a2, an-1, …)
思路:
- 首先找到链表的中点,将链表分为前后两部分。
- 然后反转后半部分链表。
- 最后交替合并前半部分和反转后的后半部分链表。
整体代码:
// 定义链表节点结构体
typedef struct LNode {
int data; // 节点存储的数据
struct LNode *next; // 指向下一个节点的指针
} LNode, *Linklist;
// 函数声明,用于反转链表
Linklist divrev(Linklist &L) {
LNode *p = L, *q = L;
// 寻找中点,p 和 q 初始指向头节点,q 每次移动两步,p 每次移动一步
while (q != NULL && q->next != NULL) {
p = p->next;
q = q->next->next;
}
// 创建新节点,用于反转后链表的头节点
LNode *L1 = new LNode;
L1->next = p->next;
p->next = NULL; // 断开前半部分和后半部分的连接
// 反转后半部分链表
LNode *p1 = L1->next, *r;
L1->next = NULL; // 初始化新链表头节点的 next 指针
while (p1 != NULL) {
r = p1->next; // 保存下一个节点
p1->next = L1->next; // 反转当前节点的指针
L1->next = p1; // 将当前节点加入到新链表中
p1 = r; // 移动到下一个节点
}
return L1; // 返回新链表的头节点
}
// 函数声明,用于合并两个链表
void merge(Linklist &L) {
LNode *r, *s;
// 调用 divrev 函数反转链表 L
LNode *L1 = divrev(L);
LNode *p = L->next, *q = L1->next;
L1->next = NULL; // 重置 L1 的 next 指针
// 交替合并两个链表
while (q != NULL) {
r = p->next;
s = q->next;
p->next = q; // 将 q 节点插入到 p 节点之后
q->next = r; // 调整 r 节点的前驱指针
p = r; // 移动 p 到下一个待插入位置
q = s; // 移动 q 到下一个待合并节点
}
}