前言:
本节博客将讲解单链表的反转,合并有序链表,寻找中间节点及约瑟夫问题
要反转链表,我们需要遍历链表并改变每个节点的 next 指针,使其指向其前一个节点。为了完成这个任务,我们需要三个指针:prev、cur和 next_node。
struct ListNode* reverseList(struct ListNode* head) {
typedef struct ListNode ListNode;
ListNode* prev = NULL;
ListNode* cur = head;
ListNode* next_node = NULL;
while (cur != NULL) {
next_node = cur->next; // 保存当前节点的下一个节点
cur->next = prev; // 更新当前节点的next指针
prev = cur; // 将prev移动到当前节点
cur = next_node; // 移动到下一个节点
}
return prev; // 返回新的头部
}
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//开始阶段
if (!list1) return list2;
if (!list2) return list1;
//初始化合并链表的头
ListNode* mergedHead = NULL; // 合并后的链表头
if (list1->val < list2->val) {
mergedHead = list1;
list1 = list1->next;
} else {
mergedHead = list2;
list2 = list2->next;
}
ListNode* cur = mergedHead; // 指向合并后链表的当前节点
//合并过程
while (list1 && list2) {
if (list1->val <= list2->val) {
cur->next = list1;
list1 = list1->next;
} else {
cur->next = list2;
list2 = list2->next;
}
cur = cur->next;
}
//处理剩余节点
// 如果list1还有剩余节点
if (list1) {
cur->next = list1;
}
// 如果list2还有剩余节点
if (list2) {
cur->next = list2;
}
return mergedHead;
}
这题我们可以使用快慢指针,在循环中,fast 指针每次移动两个节点,而 slow 指针每次只移动一个节点。这意味着,当 fast 指针到达链表的末尾时,slow 指针将位于链表的中间位置。
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
// 定义链表节点结构
typedef struct ListNode ListNode;
// 分配内存并创建一个链表节点,值为x
ListNode* ListBuyNode(int x){
ListNode* node = (ListNode*)malloc(sizeof(ListNode)); // 分配内存
if(node == NULL){ // 检查内存分配是否成功
perror("Malloc fail;");
exit(1); // 分配失败,退出程序
}
node->val = x; // 设置节点的值
node->next = NULL; // 初始化下一个节点为NULL
return node; // 返回创建的节点
}
// 创建一个包含n个节点的单向循环链表
ListNode* CreateList(int n){
ListNode* phead = ListBuyNode(1); // 创建头节点,值为1
ListNode* pTail = phead; // 初始化尾节点为头节点
for(int i = 2; i <= n; i++){ // 从2到n循环创建节点
ListNode* node = ListBuyNode(i); // 创建新节点
pTail->next = node; // 把新节点连接到链表的尾部
pTail = pTail->next; // 更新尾节点为新创建的节点
}
pTail->next = phead; // 将链表的尾部连接到头部,使其成为一个循环链表
return pTail; // 返回链表的尾节点
}
// 约瑟夫环问题的解决函数
int ysf(int n, int m ) {
ListNode* prev = CreateList(n); // 创建一个单向循环链表,并返回尾节点
ListNode* cur = prev->next; // 当前节点从头节点开始
int count = 1; // 计数器初始化为1
while(cur->next != cur){ // 当链表只剩下一个节点时停止循环
if(count == m){ // 当计数器达到m时
prev->next = cur->next; // 删除当前节点
free(cur); // 释放当前节点的内存
cur = prev->next; // 更新当前节点为下一个节点
count = 1; // 重置计数器
}
else{
prev = cur; // 否则,移动到下一个节点
cur = cur->next;
count++; // 增加计数器
}
}
return cur->val; // 返回最后剩下的节点的值
}