【C++ 資料結構:連結串列】二刷LeetCode707設計連結串列

2023-01-29 06:01:07

【C++連結串列】

使用c++重新寫一遍LeetCode707設計連結串列

目的是熟悉c++中連結串列的操作

知識點

C++連結串列節點的實現

在c++中,一般通過結構體來定義連結串列的節點,也需要寫建構函式(使用初始化列表)

如:

struct ListNode{
        int val;
        ListNode* next;
        //要寫建構函式
        //結構體中的建構函式要用初始化列表來初始化屬性
        ListNode(int val) :val(val), next(nullptr){}
    };

存取節點中的屬性遵循結構體指標操作

即利用操作符 -> 可以通過結構體指標存取結構體屬性

例如,遍歷連結串列

		while(cur->next != nullptr){
            cur = cur->next;
        }

實現一個連結串列節點

c++中對於連結串列的操作均通過指標完成,例如:

//建立一個待插入的節點
ListNode* node4add = new ListNode(val);

上述程式碼在堆區開闢一塊新記憶體存放一個ListNode物件,將指標node4add指向該區域

記憶體釋放

在c++中操作節點,如果不再需要某個節點,一定要把該節點刪除(釋放記憶體)

例如刪除節點的操作中,我們將待刪除節點的上一個節點指向待刪除節點的後一個節點,繞過了待刪除節點,實現對該節點的刪除

如果是其他語言,就直接操作就行了,在c++中不行

我們還需要將待刪除節點儲存下來,再刪除釋放

void deleteAtIndex(int index) {
        if(index < 0 || index >= m_size){
            return;
        }
        //將當前指標指向dummy
        ListNode* cur = m_dummy;
        while(index){
            cur = cur->next;
            index--;
        }
        //要先把待刪除的節點用臨時節點儲存,以便之後進行delete操作
        //如果不刪除的話會報錯
        ListNode* tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        m_size--;
     
    }

完整程式碼

class MyLinkedList {

public:
    //要先定義一個結構體作為節點
    struct ListNode{
        int val;
        ListNode* next;
        //要寫建構函式
        //結構體中的建構函式要用初始化列表來初始化屬性
        ListNode(int val) :val(val), next(nullptr){}
    };

    MyLinkedList() {
        //初始化(定義/實現)連結串列的頭節點和size
        //實際上這兩個屬於MyLinkedList類的成員屬性,由於我們不想其被修改
        //因此可以把它們寫在private區
        m_size = 0;
        m_dummy = new ListNode(0);//在堆區開闢一塊新記憶體存放一個ListNode物件,將指標m_dummy指向該區域
    }
    
    int get(int index) {
        if (index > (m_size - 1) || index < 0) {
            return -1;
        }
        //將當前指標指向頭節點(即dummy的下一個)
        // ListNode* cur = m_dummy->next;
        ListNode* cur = m_dummy;
        while(index){
            cur = cur->next;
            index--;
        }
        return cur->next->val;//記得返回的是cur的下一個節點,因為最初cur指向的是dummy
        //要麼一開始就讓cur指向dummy->next
    }
    
    void addAtHead(int val) {
        //建立一個待插入的節點
        ListNode* node4add = new ListNode(val);
        node4add->next = m_dummy->next;
        m_dummy->next = node4add; 
        m_size++;
    }
    
    void addAtTail(int val) {
        //建立一個待插入的節點
        ListNode* node4add = new ListNode(val);
        ListNode* cur = m_dummy;
        //遍歷到連結串列末尾處
        while(cur->next != nullptr){
            cur = cur->next;
        }
        //插入新節點
        cur->next = node4add;
        m_size++;


    }

    // 在第index個節點之前插入一個新節點,例如index為0,那麼新插入的節點為連結串列的新頭節點。
    // 如果index 等於連結串列的長度,則說明是新插入的節點為連結串列的尾結點
    // 如果index大於連結串列的長度,則返回空
    // 如果index小於0,則在頭部插入節點
    void addAtIndex(int index, int val) {
        if(index > m_size){
            return;
        }else if(index < 0){
            index = 0;
        }
        //將當前指標指向dummy
        ListNode* cur = m_dummy;
        //遍歷到index位置
        while(index){
            cur = cur->next;
            index--;
        }
        //找到插入位置之後開始插入
        //建立一個待插入的節點
        ListNode* node4add = new ListNode(val);
        node4add->next = cur->next;
        cur->next = node4add;

        //連結串列長度增加
        m_size++;
    }
    
    void deleteAtIndex(int index) {
        if(index < 0 || index >= m_size){
            return;
        }
        //將當前指標指向dummy
        ListNode* cur = m_dummy;
        while(index){
            cur = cur->next;
            index--;
        }
        //要先把待刪除的節點用臨時節點儲存,以便之後進行delete操作
        //如果不刪除的話會報錯
        ListNode* tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        m_size--;
     
    }
private:
    int m_size;//宣告連結串列長度
    ListNode* m_dummy;//宣告dummy頭節點

};

/**
 * 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);
 */

707二刷錯誤點

1、忘記處理連結串列size

記得定義連結串列長度size

2、next的含義

舉個例子

 void addAtIndex(int index, int val) {
        if(index > m_size){
            return;
        }else if(index < 0){
            index = 0;
        }
        //將當前指標指向dummy
        ListNode* cur = m_dummy;
        //遍歷到index位置
        while(index){
            cur = cur->next;
            index--;
        }
        //找到插入位置之後開始插入
        //建立一個待插入的節點
        ListNode* node4add = new ListNode(val);
        node4add->next = cur->next;
        cur->next = node4add;

        //連結串列長度增加
        m_size++;

    }

這裡node4add->next = cur->next;的意思是:
node4add節點的下一個節點指向cur的下一個節點A,此時cur->next代表的是一個節點

cur->next = node4add;的意思是:

cur的下一個節點指向node4add節點,此時cur->next表示存取cur節點的next屬性並對其進行操作

3、get函數,要注意cur的指向

程式碼註釋有說明,在用dummy節點的時候不要搞錯返回物件