1.合并两个升序链表
问题:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
代码实现:
ListNode* lowlisthead=(ListNode*)malloc(sizeof(ListNode));
新颖之处就是创建头节点(哨兵位)能够减少代码,不用每次都判断链表是否为NULL,
注意的是:最后函数的返回值是头节点的下一个地址(lowlisthead->next)
//========1.合并两个升序链表(创建头节点 简化代码)==========
typedef int SLTDataType;
typedef struct SListnode
{
SLTDataType val;
struct SListnode* next;
}ListNode;
ListNode* createNode(SLTDataType val)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
perror("malloc");
exit(1);
}
newnode->val = val;
newnode->next = NULL;
return newnode;
}
ListNode* mergeTwoLists(ListNode* L1, ListNode* L2)
{
ListNode* lowlisthead=(ListNode*)malloc(sizeof(ListNode));
ListNode* pcur = lowlisthead;
while (L1 && L2)
{
if (L1->val < L2->val)
{
pcur->next = L1;
pcur = pcur->next;
L1 = L1->next;
}
else
{
pcur->next = L2;
pcur = pcur->next;
L2 = L2->next;
}
//pcur = pcur->next; 不能将判断语句里面的节点指针的移动 放在这里 ,确保在每次链接节点后正确地移动当前指针 pcur
}
if (L1)
{
pcur->next = L1;
}
if (L2)
{
pcur->next = L2;
}
return lowlisthead->next;
}
int main()
{
ListNode* list1, * list2;//创建两个链表
list1 = createNode(1);
list1->next = createNode(2);
list1->next->next = createNode(4);
list2 = createNode(1);
list2->next = createNode(3);
list2->next->next = createNode(5);
ListNode* head = mergeTwoLists(list1, list2);
while (head)
{
printf("%d ", head->val);
head = head->next;
}
return 0;
}
//2.合并两个升序链表(不创建头节点)
typedef int SLTDataType;
typedef struct SListnode
{
SLTDataType val;
struct SListnode* next;
}ListNode;
ListNode* createNode(SLTDataType val)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
perror("malloc");
exit(1);
}
newnode->val = val;
newnode->next = NULL;
return newnode;
}
//ListNode* mergeTwoLists(ListNode* L1, ListNode* L2)
//{
// ListNode* lowlisthead, * highlisthead;
// lowlisthead = highlisthead = NULL;
//
// ListNode* pcur1, *pcur2;
// pcur1 =lowlisthead;
// pcur2 = highlisthead;
// while(L1 && L2)
// {
// if (L1->val < L2->val)
// {
// if (lowlisthead == NULL)
// {
// lowlisthead = L1;
// }
// else
// {
// pcur1->next = L1;
// pcur1 = pcur1->next;
// }
// L1 = L1->next;
// }
// else
// {
// if (highlisthead == NULL)
// {
// highlisthead = L2;
// }
// else
// {
// pcur2->next = L2;
// pcur2 = pcur2->next;
// }
// L2 = L2->next;
// }
// }
// if (L1)
// {
// pcur1->next = L1;
// }
// if (L2)
// {
// pcur2->next = L2;
// }
//
//}
ListNode* mergeTwoLists(ListNode* L1, ListNode* L2)
{
ListNode* lowlisthead, * pcur;
pcur = lowlisthead= NULL;
while (L1 && L2)
{
if (L1->val < L2->val)
{
if (lowlisthead == NULL)
{
lowlisthead = pcur = L1;
}
else
{
pcur->next = L1;
pcur = pcur->next;
}
L1 = L1->next;
}
else
{
if (lowlisthead == NULL)
{
lowlisthead = pcur = L2;
}
else
{
pcur->next = L2;
pcur = pcur->next;
}
L2 = L2->next;
}
//pcur = pcur->next; 不能将判断语句里面的节点指针的移动 放在这里 ,确保在每次链接节点后正确地移动当前指针 pcur
}
if (L1)
{
pcur->next = L1;
}
if (L2)
{
pcur->next = L2;
}
return lowlisthead;
}
int main()
{
ListNode* list1,*list2;//创建两个链表
list1 = createNode(1);
list1->next= createNode(2);
list1->next->next = createNode(4);
list2 = createNode(1);
list2->next = createNode(3);
list2->next->next = createNode(5);
ListNode* head = mergeTwoLists(list1, list2);
while(head)
{
printf("%d ", head->val);
head = head->next;
}
return 0;
}
2.移除链表元素
问题:
给你一个链表的头节点
head
和一个整数val
,请你删除链表中所有满足Node.val == val
的节点,并返回 新的头节点 。
代码实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLTDataType;
typedef struct SListnode
{
SLTDataType val;
struct SListnode* next;
}ListNode;
ListNode* createNode(SLTDataType val)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
perror("malloc");
exit(1);
}
newnode->val = val;
newnode->next = NULL;
return newnode;
}
struct ListNode* removeElements(struct ListNode* head, int val)
{
ListNode* pur = head;
ListNode* newhead, *newtail;//创建新链表
newhead = newtail = NULL;//表头 表尾初始化
while (pur)
{
if (pur->val != val)
{
if (newhead == NULL)
{
newhead = newtail = pur;
}
else
{
newtail->next = pur;
newtail = newtail->next;
}
}
pur = pur->next;
}
if (newtail)
{
newtail->next=NULL;
}
return newhead;
}
int main()
{
ListNode* node1, * node2, * node3, * node4, * node5, * node6, * node7;
node1 = createNode(1);
node2 = node1->next = createNode(2);
node3 = node2->next = createNode(6);
node4 = node3->next = createNode(3);
node5 = node4->next = createNode(4);
node6 = node5->next = createNode(5);
node7 = node6->next = createNode(6);//创建一个链表
ListNode* newhead = removeElements(node1, 6);//移除链表元素:6
while (newhead)
{
printf("%d ", newhead->val);
newhead = newhead->next;
}
return 0;
}
3. 反转链表
问题:
给你单链表的头节点 head,请你反转链表,并返回反转后的链表。
代码实现:
//3.反转链表
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLTDataType;
typedef struct SListnode
{
SLTDataType val;
struct SListnode* next;
}ListNode;
ListNode* createNode(SLTDataType val)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
perror("malloc");
exit(1);
}
newnode->val = val;
newnode->next = NULL;
return newnode;
}
struct ListNode* reverseList(struct ListNode* head)
{
if (head == NULL)
{
return head;
}
ListNode* n1,*n2,*n3 ;
n1= NULL, n2=head, n3=n2->next;//创建三个节点
while (n2)
{
n2->next = n1;// 指针逆向
n1 = n2;
n2 = n3;
if (n3)
{
n3 = n3->next;
}
}
return n1;
}
int main()
{
ListNode* node1, * node2, * node3, * node4, * node5;
node1 = createNode(1);
node2 = node1->next = createNode(2);
node3 = node2->next = createNode(3);
node4 = node3->next = createNode(4);
node5 = node4->next = createNode(5);//创建一个链表
ListNode* newhead = reverseList(node1);//反转链表
while (newhead)
{
printf("%d ", newhead->val);
newhead = newhead->next;
}
return 0;
}
4. 查找链表的中间结点
问题:
给你单链表的头结点
head
,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
代码实现:
//4.查找链表的中间结点
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLTDataType;
typedef struct SListnode
{
SLTDataType val;
struct SListnode* next;
}ListNode;
ListNode* createNode(SLTDataType val)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
perror("malloc");
exit(1);
}
newnode->val = val;
newnode->next = NULL;
return newnode;
}
struct ListNode* middleNode(struct ListNode* head)
{
if (head == NULL)
{
return head;
}
ListNode* slow, * fast;
slow = fast= head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
int main()
{
ListNode* node1, * node2, * node3, * node4, * node5, * node6;
node1 = createNode(1);
node2 = node1->next = createNode(2);
node3 = node2->next = createNode(3);
node4 = node3->next = createNode(4);
node5 = node4->next = createNode(5);
//node6 = node5->next = createNode(6);//创建一个链表
ListNode* node = middleNode(node1);
printf("%d", node->val);
return 0;
}
5.分割链表
问题:
给你一个链表的头节点
head
和一个特定值x
,请你对链表进行分隔,使得所有 小于x
的节点都出现在 大于或等于x
的节点之前。你不需要 保留 每个分区中各节点的初始相对位置
代码实现:
//5.分割链表
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLTDataType;
typedef struct SListnode
{
SLTDataType val;
struct SListnode* next;
}ListNode;
ListNode* createNode(SLTDataType val)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
perror("malloc");
exit(1);
}
newnode->val = val;
newnode->next = NULL;
return newnode;
}
struct ListNode* partition(struct ListNode* head, int x)
{
ListNode* pcur = head;
ListNode* Lhead = (ListNode*)malloc(sizeof(ListNode));
ListNode* Hhead = (ListNode*)malloc(sizeof(ListNode));
ListNode* L1 = Lhead;
ListNode* L2 = Hhead;
while (pcur)
{
if (pcur->val < x)
{
L1->next = pcur;//L1相当于Lhead的末尾结点指针(初始状态都是链表的头),每进循环一次,往前走一步
L1 = L1->next;
}
else
{
L2->next = pcur;//L2相当于Hhead的末尾结点指针(初始状态都是链表的头),每进循环一次,往前走一步
L2 = L2->next;
}
pcur = pcur->next;
}
L2->next = NULL;//修改Hhead链表 末尾节点指向的指针进行初始化,如果没有这个,代码可能就会出现死循环 因为不确定head最后一个节点是否为Hhead链表的最后一个节点,为了保险起见 就使L2->next = NULL
L1->next = Hhead->next;
return Lhead->next;
}
int main()
{
ListNode* node1, * node2, * node3, * node4, * node5, * node6;
node1 = createNode(1);
node2 = node1->next = createNode(4);
node3 = node2->next = createNode(3);
node4 = node3->next = createNode(2);
node5 = node4->next = createNode(5);
node6 = node5->next = createNode(5);//创建一个链表
ListNode* newhead = partition(node1, 3);
while (newhead)
{
printf("%d ", newhead->val);
newhead = newhead->next;
}
return 0;
}
6.环形链表的约瑟夫问题
问题:
编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数,报到 m 的人离开。
下一个人继续从 1 开始报数。
n-1 轮结束以后,只剩下一个人,问最后留下的这个人编号是多少?
数据范围: 1≤𝑛,𝑚≤100001≤n,m≤10000
进阶:空间复杂度 𝑂(1)O(1),时间复杂度 𝑂(𝑛)O(n)
代码实现:
//6.环形链表的约瑟夫问题
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLTDataType;
typedef struct SListnode
{
SLTDataType val;
struct SListnode* next;
}ListNode;
ListNode* createNode(SLTDataType val)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
perror("malloc");
exit(1);
}
newnode->val = val;
newnode->next = NULL;
return newnode;
}
//创建带环链表
ListNode* createCircleList(int n)
{
ListNode* phead= createNode(1);
ListNode* ptail = phead;
for (int i = 2; i <= n; i++)
{
ptail->next = createNode(i);
ptail = ptail->next;
}
ptail->next = phead;//首尾相连,链表成环
return ptail;
}
int person_num(int n,int m)
{
ListNode* ptail = createCircleList(n);
ListNode* pcur = ptail->next;
int count = 1;
while (ptail->next != ptail)
{
if (count == m)//销毁节点
{
ptail->next = pcur->next;
free(pcur);
pcur = ptail->next;
count = 1;
}
else
{
ptail = ptail->next;//等价于ptail = pcur;
pcur = pcur->next;
count++;
}
}
return ptail->val;
}
int main()
{
int person = person_num(5, 2);
printf("%d", person);
return 0;
}