【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節點的時候不要搞錯返回物件