【程式碼隨想錄】二、連結串列:2、設計連結串列

henFiu發表於2024-08-16

部分圖文參考於:程式碼隨想錄 - 707. 設計連結串列

這道題目設計連結串列的五個介面:
● 獲取連結串列第index個節點的數值
● 在連結串列的最前面插入一個節點
● 在連結串列的最後面插入一個節點
● 在連結串列第index個節點前面插入一個節點
● 刪除連結串列的第index個節點
可以說這五個介面,已經覆蓋了連結串列的常見操作,是練習連結串列操作非常好的一道題目。

1.題目連結

707.設計連結串列

2.思路

我們引入一個虛擬頭結點來進行操作(dummyHead)。
1.get(index) 獲取第index個結點的值。如果索引無效,返回-1。
(1)索引越界:當index<0或是index>size-1,索引無效。
(2)獲取第index個結點的值:當前結點cur指向dummyHead的next,在index=0時,即獲取頭結點的值(cur->val)。在index為其他值時,透過while(index--){cur = cur -> next;}將當前結點cur向後移,直到移到index處,結束while迴圈。

2.addAtHead(val) 頭部插入結點
注意插入時的順序:
①newNode->next = dummyHead->next;
②dummyHead->next = newNode;
image

3.addAtTail(val) 尾部插入結點
當前結點的next結點不為空時,持續向後找最後一個結點。找到後,在當前結點後插入新結點:cur -> next = newNode;

4.addAtIndex(index,val) 第index個結點前插入結點
(1)index如果大於連結串列長度,不會插入結點。index小於0,在頭部插入結點。index等於連結串列長度,則該結點將附加到連結串列末尾。
(2)當前結點cur指向dummyHead,使用while(index--){cur = cur->next}找到index所在位置。
(3)插入結點。newNode->next = cur->next; cur->next = newNode;

2-4需要size++。

5.deleteAtIndex(index) 刪除第index個結點
(1)需要判斷index是否有效,index<0或index≥size無效。
(2)透過while(index--){cur=cur->next;}找到要刪除的結點。
(3)刪除操作:cur->next = cur->next->next;
(4)C++需要delete釋放無效結點記憶體。

class MyLinkedList {
public:
    // 定義連結串列節點結構體
    struct LinkedNode {
        int val;
        LinkedNode* next;
        LinkedNode(int val):val(val), next(nullptr){}
    };

    // 初始化連結串列
    MyLinkedList() {
        _dummyHead = new LinkedNode(0); // 這裡定義的頭結點 是一個虛擬頭結點,而不是真正的連結串列頭結點
        _size = 0;
    }

    // 獲取到第index個節點數值,如果index是非法數值直接返回-1, 注意index是從0開始的,第0個節點就是頭結點
    int get(int index) {
        if (index > (_size - 1) || index < 0) {
            return -1;
        }
        LinkedNode* cur = _dummyHead->next;
        while(index--){ // 如果--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++;
    }

    // 在第index個節點之前插入一個新節點,例如index為0,那麼新插入的節點為連結串列的新頭節點。
    // 如果index 等於連結串列的長度,則說明是新插入的節點為連結串列的尾結點
    // 如果index大於連結串列的長度,則返回空
    // 如果index小於0,則在頭部插入節點
    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++;
    }

    // 刪除第index個節點,如果index 大於等於連結串列的長度,直接return,注意index是從0開始的
    void deleteAtIndex(int index) {
        if (index >= _size || index < 0) {
            return;
        }
        LinkedNode* cur = _dummyHead;
        while(index--) {
            cur = cur ->next;
        }
        LinkedNode* tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        //delete命令指示釋放了tmp指標原本所指的那部分記憶體,
        //被delete後的指標tmp的值(地址)並非就是NULL,而是隨機值。也就是被delete後,
        //如果不再加上一句tmp=nullptr,tmp會成為亂指的野指標
        //如果之後的程式不小心使用了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;

};

● 時間複雜度: 涉及 index 的相關操作為 O(index), 其餘為 O(1)。
● 空間複雜度: O(n)。

相關文章