#define _CRT_SECURE_NO_WARNINGS 1
随机链表的复制
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,
该指针可以指向链表中的任何节点或空节点。
- 在原链表中插入拷贝节点:将每个节点的拷贝插入到原链表中,这样可以在一次遍历中轻松找到每个节点和其拷贝节点的位置关系。
- 设置拷贝节点的
random
指针 :利用拷贝节点插入原链表后的邻近关系,通过原节点的random
指针,快速找到对应的拷贝节点的random
。 - 拆解链表:恢复原链表,并同时提取出拷贝链表。
typedef struct Node Node;
struct Node {
int val;
struct Node* next;
struct Node* random;
};
struct Node* copyRandomList(struct Node* head) {
// 如果链表为空,直接返回NULL
if (head == NULL)
return NULL;
Node* cur = head;
// 1. 将原链表的每个节点复制一份,插入到原节点后面
while (cur) {
// 创建一个新的节点,值和原节点相同
Node* copy = (Node*)malloc(sizeof(Node));
copy->next = NULL;
copy->random = NULL;
copy->val = cur->val;
// 获取原节点的下一个节点
Node* next = cur->next;
// 将原节点的next指向新节点
cur->next = copy;
// 新节点的next指向原节点的下一个节点
copy->next = next;
// 移动到下一个原节点
cur = next;
}
// 2. 设置每个复制节点的random指针
cur = head;
while (cur) {
Node* copy = cur->next;
// 如果原节点有random指针,复制给新节点
if (cur->random) {
copy->random = cur->random->next; // 随机指针指向复制节点
}
else {
copy->random = NULL; // 如果没有随机指针,设置为NULL
}
// 迭代到下一个原节点
cur = cur->next->next;
}
// 3. 拆解链表,恢复原链表并分离出复制链表
cur = head;
Node* copyHead = head->next; // 复制链表的头节点
while (cur) {
Node* copy = cur->next; // 复制节点
Node* next = copy->next; // 复制节点的next
// 恢复原链表的结构:将原节点的next指向下一个原节点
cur->next = next;
// 将复制节点的next指向复制链表的下一个节点
if (next) {
copy->next = next->next; // 复制节点的next应该指向复制链表中的下一个节点
}
else {
copy->next = NULL; // 如果next为空,表示这是链表的最后一个复制节点
}
// 迭代到下一个原节点
cur = next;
}
// 返回复制链表的头节点
return copyHead;
}

对链表进行插入排序
给定单个链表的头 head ,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。
通过逐步扩展一个已排序部分的链表,将未排序部分的节点按照大小插入到适当位置,确保每一步都保持链表部分有序。
- 初始状态:将链表的第一个节点视为已排序部分,后续节点逐一插入到该有序链表中。
- 每步操作:找到当前节点在有序部分中的正确插入位置,并插入。
- 完成条件:所有节点都被插入到有序链表中。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* insertionSortList(struct ListNode* head) {
if (head == NULL || head->next == NULL)
{
return head;
}
ListNode* sortHead = head;
ListNode* cur = head->next;
sortHead->next = NULL;
while (cur)
{
ListNode* next = cur->next;
//把cur插入到sortHead链表中去,并保持有序
if (cur->val <= sortHead->val)
{
//头插
cur->next = sortHead;
sortHead = cur;
}
else
{
//中间插
ListNode* sortPrev = sortHead;
ListNode* sortCur = sortPrev->next;
while (sortCur)
{
if (cur->val <= sortCur->val)
{
sortPrev->next = cur;
cur->next = sortCur;
break;
}
else
{
sortPrev = sortCur;
sortCur = sortCur->next;
}
}
//尾插
if (sortCur == NULL)
{
sortPrev->next = cur;
cur->next = NULL;
}
}
cur = next;
}
return sortHead;
}

删除排序链表中的重复元素 II
给定一个已排序的链表的头 head ,删除原始链表中所有重复数字的节点,
只留下不同的数字 。返回 已排序的链表 。
-
遍历链表:
- 如果当前节点值和下一节点值相等,则跳过这些重复节点。
- 如果当前节点值不等于下一节点值,则将其保留。
-
处理重复节点:
- 通过内层循环跳过所有值相同的节点,找到第一个与当前值不同的节点。
- 更新指针,删除重复的节点。
-
特殊情况:
- 如果重复节点出现在链表开头,需要更新头指针。
- 在链表尾部需要检查指针是否为
NULL
,防止非法访问。
1.删除中间的情况

2.头相等

3.尾相等

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* deleteDuplicates(struct ListNode* head) {
if(head==NULL || head->next==NULL)
return head;
ListNode* cur=head;
ListNode* next=cur->next;
ListNode* prev=NULL;
while(next)
{
if(cur->val!=next->val)//不相等继续往下走
{
prev=cur;
cur=next;
next=next->next;
}
else
{
while(next && cur->val == next->val) //对next进行解引用,必须保证next不为空才行
{
next=next->next;
}
//已经不相等了
if(prev)
{
prev->next=next;
}
else
{
head=next;
}
//释放
while(cur!=next)
{
ListNode* del=cur;
cur=cur->next;
free(del);
}
if(next)//尾相等的情况下需要判断,不为空才能继续赋值,否则会崩
{
next=cur->next;
}
}
}
return head;
}