链表及其操作

本文介绍了在单链表中删除具有特定值的节点的不同方法,包括双指针遍历、迭代和使用虚拟头节点,以及如何插入元素和利用快慢指针检测链表环路。
摘要由CSDN通过智能技术生成

常见操作

1.删除链表元素

如果我们想从单链表中删除现有结点 cur,可以分两步完成:

1.找到 cur 的上一个结点 prev 及其下一个结点 next ;

2.接下来链接 prev 到 cur 的下一个节点 next 。

1.双指针

1. 设置两个均指向头节点的指针,pre(记录待删除节点的前一节点)和 cur (记录当前节点);

 遍历整个链表,查找节点值为 val 的节点,找到即删除该节点,否则继续查找。

2.找到,将当前节点的前一节点(之前最近一个值不等于 val 的节点(pre))连接到当前节点(cur)的下一个节点(即将 pre 的下一节点指向 cur 的下一节点:pre->next = cur->next)。

没找到,更新最近一个值不等于 val 的节点(即 pre = cur),并继续遍历(cur = cur->next)

struct ListNode* removeElements(struct ListNode* head, int val){
    while (NULL != head && head->val == val) {
        head = head->next;
    }
    
    struct ListNode* cur = head;
    struct ListNode* pre = head;
    while (cur != NULL) {
        if (cur->val == val) {
            pre->next = cur->next;
        } else {
            pre = cur;
        }
        cur = cur->next;
    }
    return head;
}

2.迭代 


删除链表中给定值的节点,一般的步骤是:

遍历链表,找到所有值为 val 的节点;

将值为 val 的节点的上一个节点直接指向该节点的下一个节点(pre->next = pre->next->next)。

struct ListNode* removeElements(struct ListNode* head, int val){
    while (NULL != head && head->val == val) {
        head = head->next;
    }

    if (NULL == head) {
        return head;
    }

    struct ListNode* pre = head;
    while (pre->next != NULL) {
        /* 找到值为 val 的节点,并将其删除 */
        if (pre->next->val == val) {
            pre->next = pre->next->next;   
        } else {
            /* 没找到,则继续遍历查找 */
            pre = pre->next;
        }
    }
    return head;
}

 3.虚拟头节点(哨兵)

可以通过在头节点前增加虚拟头节点,这样头节点就成了普通节点,不需要单独拎出来考虑,但是在返回的时候,返回的是虚拟头节点的下一节点而不是虚拟头节点

struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode* dummyHead = malloc(sizeof(struct ListNode));
    if (NULL == dummyHead) {
        return NULL;
    }

    dummyHead->next = head;
    struct ListNode* cur = dummyHead;
    while (cur->next != NULL) {
        if (cur->next->val == val) {
            cur->next = cur->next->next;
        } else {
            cur = cur->next;
        }
    }

    struct ListNode* retNode = dummyHead->next;
    free(dummyHead);
    return retNode;
}

 2.插入元素(一定要malloc申请)

//插入index等于len,插入尾部,index从0开始
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) 
{
    if(index<0)return;
    MyLinkedList* node = obj;

    for(int i=0;i<index;i++)
{
      if(node->next==NULL)
    return;
      else 
    node = node->next;
    }
    MyLinkedList* add = (MyLinkedList*)malloc(sizeof(MyLinkedList));
    add->val = val;
    if(node->next!=NULL)
    add->next = node->next;

    else //尾部插入
    add->next = NULL;

    node->next = add;
}

 技巧

1.快慢指针

每次移动慢指针一步,而移动快指针两步

经典问题:环形链表

第一次相遇检查成环(快指针比慢指针每次快一步),第二次相遇检查环节点(快慢指针步长相同,相遇时一定在环节点)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    if(!head||!head->next)return NULL;
    struct ListNode *fast=head;
    struct ListNode *cur=head;
    while(fast!=NULL&&fast->next!=NULL)
    {
       
        
        fast=fast->next->next;
        cur=cur->next;
        if(fast==cur)//相遇后,快指针从头开始
            {
            struct ListNode*cur=head;
            while(cur!=fast){
                cur=cur->next;
                fast=fast->next;
            }
            return cur;//第二次相遇节点
        }
     }
     
     return NULL;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值