707. 设计链表

题目

这题卡哥的讲解视频特别好,涵盖了很多细节。

自己跟着卡哥代码敲了一遍。

单链表:

class MyLinkedList {
public:

    struct LinkedNode {
        int val;
        LinkedNode *next;
        LinkedNode(int val):val(val), next(nullptr){}
    };


    MyLinkedList() {
        _dummyHead = new LinkedNode(0);
        _size = 0;
    }
    
    int get(int index) {
        if (index > (_size - 1)|| index < 0)
        {
            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;
    }
    
    void addAtTail(int val) {
        LinkedNode *newNode = new LinkedNode(val);
        LinkedNode *cur = _dummyHead;
        while (cur->next != nullptr)
        {
            cur = cur->next;
        }
        cur->next = newNode;
        ++_size;
    }
    
    void addAtIndex(int index, int val) {
        if (index > _size) return;
        if (index < 0) index = 0;
        LinkedNode *newNode = new LinkedNode(val);
        LinkedNode *cur = _dummyHead;
        while (index--)
        {
            cur = cur->next;
        }
        newNode->next = cur->next;
        cur->next = newNode;
        ++_size;
    }
    
    void deleteAtIndex(int index) {
        if (index < 0 || index >= _size)
        {
            return;
        }
        LinkedNode *cur = _dummyHead;
        while(index--)
        {
            cur = cur->next;
        }
        LinkedNode *tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        tmp=nullptr;
        --_size;
    }

    void printLinkedList()
    {
        LinkedNode *cur = _dummyHead;
        while (cur->next != nullptr)
        {
            cout << cur->next->val << " ";
            cur = cur->next;
        }
        cout << endl;
    }

private:
    int _size;
    LinkedNode *_dummyHead;
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */

附上自己看卡哥视频有所感的点:

img

img

img

img

img

img

卡哥也给出了双向链表的代码

问了下ChatGPT哨兵节点:

在这段代码中,哨兵节点(sentinelNode)的 prev 和 next 指针指向的是它自身,形成一个循环结构。具体来说:

  1. sentinelNode->next:哨兵节点的 next 指针指向链表的第一个有效节点(即头节点)。但是,最开始这个节点是指向哨兵节点本身,意味着链表为空时,哨兵节点的 next 指向它自己。

  2. sentinelNode->prev:哨兵节点的 prev 指针指向链表的最后一个有效节点(即尾节点)。同样,当链表为空时,哨兵节点的 prev 也指向它自己。

这样做的目的是为了简化链表的边界条件,避免在处理链表的头部和尾部时需要额外的判断。

举个例子:

  • 空链表时:

    • sentinelNode->next 指向哨兵节点自身。

    • sentinelNode->prev 指向哨兵节点自身。

    这时,链表没有任何有效节点,头部和尾部都由哨兵节点控制。

  • 向链表头部添加一个新节点:

    假设我们添加一个值为 10 的节点:

    • 创建一个新的节点 newNode,它的 next 指向哨兵节点的原 next,即空链表时指向哨兵节点本身。

    • 新节点的 prev 指向哨兵节点。

    • 然后更新哨兵节点的 next 指向新节点,sentinelNode->next = newNode。

    此时,链表变成:[sentinelNode] <-> [newNode] <-> [sentinelNode]。

  • 向链表尾部添加一个新节点:

    如果我们在尾部插入一个值为 20 的节点:

    • 创建一个新的节点 newNode,它的 prev 指向哨兵节点的原 prev,即空链表时指向哨兵节点本身。

    • 新节点的 next 指向哨兵节点。

    • 然后更新哨兵节点的 prev 指向新节点,sentinelNode->prev = newNode。

    此时,链表变成:[sentinelNode] <-> [newNode] <-> [sentinelNode]。

  • 总结:

    在空链表中,哨兵节点的 prev 和 next 都指向它自己,形成一个闭环。当链表非空时,哨兵节点的 prev 和 next 分别指向链表的尾节点和头节点,但仍然保持循环结构。

附上一张自己画的图:

img

posted @ 2024-11-24 19:55  hisun9  阅读(33)  评论(0)    收藏  举报