day03 链表part01

移除链表元素:

​    移除链表中某一元素的值,先遍历链表的值,但是存在头节点和后续节点值表示方式不一样的情况,堆区新开一个虚拟头节点,使得遍历后续节点具有一致性;此外,删除一个节点最简单,直接跳过即可,但是循环判断条件需要思考一下;

​    总结:理解错链表节点的意思了,起初不理解为什么在跳过目标节点会定义一个新节点,这个节点用来指向目标节点相同位置,利用其找到其next后释放该节点;不要忘记如果没有找到也要一直指向下一个节点,新定义的节点cur用于遍历,满足的删。

​    关键点:虚拟头节点便于遍历、查到后如何释放、堆空间的释放

```cpp
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
 
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* DummyHead = new ListNode(0);
        DummyHead->next = head;
        ListNode* cur = DummyHead;
        while(cur != nullptr && cur->next != nullptr) {
            if(cur->next->val == val) {
                ListNode* temp = cur->next;
                cur->next = cur->next->next;
                delete temp;
            }
            else cur = cur->next;
        }
        head = DummyHead->next;
        delete DummyHead;
        return head;
    }
};
```

链表设计:

​    链表设计太多细节了,耐心快被磨掉,debug30分钟才改好,有很多细节之处;

​    总结:在写ACM时,先定义节点的结构体;注意区分index值和链表长度值的关系,index指的是链表下标,从0到链表长度减一;指针本质上存储一个地址,所以一个指针只能指向一个地址,虽然代码中没有显式 “删除” 原有连接,但通过指针赋值,原有连接会被自动覆盖,函数如果有要求删除该节点,是需要手动delete释放内存的。

​    关键:虚拟头节点、ACM链表结构体定义、遍历用cur、新加节点用new且记得链表长度加一

```cpp
    class MyLinkedList {
public:

    // 定义链表节点结构体
    struct LinkedNode {
        int val;
        LinkedNode* next;
        LinkedNode(int val): val(val), next(nullptr) {}
    };

    // 初始化链表
    MyLinkedList() {
        _size = 0;
        _dummyHead = new LinkedNode(0);
    }

    // 获取链表下标为index节点的值
    int get(int index) {
        if(index < 0 || index >= _size) return -1;
        LinkedNode* cur = _dummyHead->next;
        while(index--) {
            cur = cur->next;
        }
        return cur->val;
    }
    
    // 在链表第一个节点前加一个节点
    void addAtHead(int val) {
        LinkedNode* newNode = new LinkedNode(val);
        newNode->next = _dummyHead->next;
        _dummyHead->next = newNode;
        _size++;
    }

    // 在链表最后一个元素加一个值为val的节点
    void addAtTail(int val) {
        LinkedNode* newNode = new LinkedNode(val);
        LinkedNode* cur = _dummyHead;
        // 正确遍历到链表末尾
        while(cur->next != nullptr) {
            cur = cur->next;
        }
        cur->next = newNode;
        _size++;
    }

    // 将一个值为val的节点插入到链表中下标为index的节点之前
    void addAtIndex(int index, int val) {
        if(index < 0 || index > _size) return;
        // 直接处理尾部情况,避免递归
        LinkedNode* cur = _dummyHead;
        LinkedNode* newNode = new LinkedNode(val);
        // 找到index的前一个节点
        for(int i = 0; i < index; i++) {
            cur = cur->next;
        }
        newNode->next = cur->next;
        cur->next = newNode;
        _size++;
    }

    // 如果下标有效,删除链表中下标为index的节点
    void deleteAtIndex(int index) {
        if(index < 0 || index >= _size) return;
        LinkedNode* cur = _dummyHead;
        // 找到index的前一个节点
        for(int i = 0; i < index; i++) {
            cur = cur->next;
        }
        LinkedNode* temp = cur->next;
        cur->next = temp->next;  // 避免双重解引用
        delete temp;
        _size--;
    }

private:
    int _size;
    LinkedNode* _dummyHead;
};

```

反转链表:

​    看到这道题我想到了双指针,一快一慢,主要思考一小对中是如何翻转链表的,以及头尾空指针如何翻转;

​    总结:快慢指针的应用,慢指针初始赋值为NULL,快指针定义为头节点,由于快指针后面一个节点会被覆盖,所以需要定义一个temp提前保存,一直这样迭代循环;循环终止条件带入特殊条件,最后返回fast还是slow作为新的头节点也用特殊情况带入。

​    关键点:双指针、容器暂时保存、终止条件

```cpp
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    
    ListNode* reverseList(ListNode* head) {
       ListNode* slow = nullptr;
       ListNode* fast = head;
       while(fast != nullptr) {
            ListNode* temp ;
            temp = fast->next;
            fast->next = slow;
            slow = fast;
            fast = temp;
       }
       return slow;

    }
};
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凡同学。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值