今天是8月2日,學習了連結串列的基礎知識。題目主要是連結串列的基礎操作和反轉連結串列,注意虛擬頭節點的使用、next的順序和tmp的靈活使用。
1. 移除元素
題目:給一個連結串列的頭節點 head
和整數 val
,請刪除連結串列中所有滿足 Node.val == val
的節點,並返回 新的頭節點 。
- 刪除的方法,
cur
指標挨個遍歷,若是cur->next
和val同,則刪除cur->next
。(所以,while中的判斷條件是cur->next
不為null,因為比較和刪除的都是cur->next
)。 - 若是刪除第一個不方便,所以加一個虛擬頭節點。
- 注意C++中開闢空間的方法。
- 注意設定指標的方法,二者有何區別。
ListNode* removeElements(ListNode* head, int val) {
// 設定一個虛擬頭結點 ListNode(int x) : val(x), next(nullptr) {}
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
// 設定一個指標
ListNode* cur = dummyHead;
while (cur->next != NULL) {
if(cur->next->val == val) {
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
} else {
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;
return head;
}
2. 707 設計連結串列
題目:實現 MyLinkedList
類:
MyLinkedList()
初始化MyLinkedList
物件。int get(int index)
獲取連結串列中下標為index
的節點的值。如果下標無效,則返回-1
。void addAtHead(int val)
將一個值為val
的節點插入到連結串列中第一個元素之前。在插入完成後,新節點會成為連結串列的第一個節點。void addAtTail(int val)
將一個值為val
的節點追加到連結串列中作為連結串列的最後一個元素。void addAtIndex(int index, int val)
將一個值為val
的節點插入到連結串列中下標為index
的節點之前。如果index
等於連結串列的長度,那麼該節點會被追加到連結串列的末尾。如果index
比長度更大,該節點將 不會插入 到連結串列中。void deleteAtIndex(int index)
如果下標有效,則刪除連結串列中下標為index
的節點。
思路:
- 注意頭節點的運用。
- 注意C++中建構函式的寫法。(先在外頭寫一個
struct
)- 注意每個函式進去先判斷特殊情況,例如
index<0||index>=size
- 注意再往後順連結串列時的截至條件。
- 足以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>0){ // 如果--index 就會陷入死迴圈
cur = cur->next;
index--;
}
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++;
}
// 刪除第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;
};
3. 反轉連結串列(雙指標+臨時變數)
題目:給單連結串列的頭節點 head
,返回反轉後的連結串列。
最直接的想法就是把next
的指標調轉方向,但是一個指標一定做不到,所以需要雙指標pre
和cur
。想一想即可知,cur的next指向pre
之後,到不了cur
的下一個了,所以解決辦法:提前存下cur的下一個的位置,即設定一個tmp
指標指向cur->next
。
ListNode* reverseList(ListNode* head) {
ListNode* cur = head;
ListNode* pre = nullptr;
while(cur!=nullptr){
ListNode* tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
今日古詩
烏夜啼·紈扇嬋娟素月
陸游〔宋代〕
紈扇嬋娟素月,紗巾縹緲輕煙。高槐葉長陰初合,清潤雨餘天。
弄筆斜行小草,鉤簾淺醉閒眠。更無一點塵埃到,枕上聽新蟬。