链表
单链表 双链表 循环链表
链表_stl-优快云博客
虚拟头结点
反转链表
删除链表元素
方法一: 直接使用原来的链表来进行删除操作。
头节点是否为空
头链表的值是否为要删除的值
头结点删除后,新的头节点是否依旧要删除 ,删除后的,新头节点可能是空结点
方法二: 设置一个虚拟头结点在进行删除操作。
ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
dummyHead->next = head; // 将虚拟头结点指向head,这样方便后面做删除操作
ListNode* cur = dummyHead;
while (cur->next != NULL) {
if(cur->next->val == val) {
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
} else {
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;
return head;
}
设置一个虚拟头结点,这样原链表的所有节点就都可以按照统一的方式进行移除
203. 移除链表元素 - 力扣(LeetCode)
// 危险操作!
1.直接操作原始头指针
2.造成空指针解引用 (先访问
head->val会触发尸变)
3.需要确保在删除节点后立即更新指针,避免悬空指针的使用
反转链表
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode*cur=head;
ListNode*pre=nullptr;
ListNode*next;
while(cur){
next=cur->next;
cur->next=pre;
pre=cur;
cur=next;
}
return pre;
}
};
递归
( 从后往前翻转指针指向 )
ListNode* reverseList(ListNode* head) {
// 递归终止条件
if (!head || !head->next) {
return head;
}
ListNode* reversedHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return reversedHead;
}
快慢指针 删除链表的倒数第N个节点
思想
如果要删除倒数第n个节点,让fast移动n+1步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了
为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作)
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode*dummy=new ListNode(0);
dummy->next=head;
ListNode*fast=dummy;
ListNode*slow=dummy;
for(int i=0;i<n+1;i++){
fast=fast->next;
}
while(fast){
slow=slow->next;
fast=fast->next;
}
ListNode*temp=slow->next;
slow->next=temp->next;
delete temp;
return dummy->next;
}
};
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
链表相交
简单来说,就是求两个链表交点节点的指针
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode*currentA=headA;
ListNode*currentB=headB;
int lenA=0,lenB=0;
while(currentA){
currentA=currentA->next;
lenA++;
}
while(currentB){
currentB=currentB->next;
lenB++;
}
currentA=headA;
currentB=headB;
if(lenA>lenB){
int len=lenA-lenB;
while(len--){
currentA=currentA->next;}
}
if(lenA<lenB){
int len=lenB-lenA;
while(len--){
currentB=currentB->next;}
}
while(currentA!=currentB){
currentB=currentB->next;
currentA=currentA->next;
}
return currentA;
}
};
面试题 02.07. 链表相交 - 力扣(LeetCode)
环形链表II
fast走两步,slow走一步,相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合
在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。
让index1和index2同时移动,每次移动一个节点, 那么他们相遇的地方就是 环形入口的节点
(x + y) * 2 = x + y + n (y + z)
x + y = n (y + z)
x = n (y + z) - y
x = (n - 1) (y + z) + z
当 n为1的时候,公式就化解为 x = z
这就意味着,从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode*show=head;
ListNode*fast=head;
while(fast != NULL && fast->next != NULL)
{
show=show->next;
for(int i=0;i<2;i++)
fast=fast->next;
if(show==fast)
{
ListNode*index1=head;
ListNode*index2=fast;
while(index1!=index2)
{
index1=index1->next;
index2=index2->next;
}
return index1;
}
}
return nullptr;
}
};