知识点
链表
- 定义链表结构体:
struct ListNode {
int val;
ListNode *next; // 指向ListNode类型的指针,next中存放指向一块存放ListNode型对象地址
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
指针
- 定义
- Type *instance;
- instance: 存放指向一块Type型对象地址
- 未初始化:拥有不确定值。因此建议都初始化。
- 利用指针访问对象
&
- 引用:
int i = 10; int &a = i;
,紧跟类型名; - 取地址符:
int *p; p = &i;
,取出变量的地址;
- 引用:
*
int *p;
:代表指针;*p = 10
:解引用符,访问p指向对象;
- 空指针
int *p = nullptr;
int *p = 0 / NULL;
题解
203.移出链表元素
解法:用原链表操作 & 加虚拟头结点;
心路历程:已经忘了链表的具体实现,又翻了数据结构书捡起来的。看题知道流程什么样,一上手连指针的概念都忘了。
代码:
结构体声明:
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
- 原链表操作
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
while (head != NULL && head->val == val) {
ListNode* tmp = head; // 操作头元素
head = head->next;
delete tmp;
}
// 至此头元素不再会被摘掉,因此头指针须保留,用于返回
ListNode* item = head; // 两个留一个,另一个用于遍历链表
while (item != NULL && item->next != NULL) {
if (item->next->val == val) {
ListNode* tmp = item->next;
item->next = tmp->next;
delete tmp;
}
else item = item->next;
}
return head;
}
};
- 设虚拟头指针
// 不规范版
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* virt = new ListNode(0, head); // 挂在真正头结点前
ListNode* res = virt; // 一个保存头指针,一个遍历
while (virt->next != NULL) {
if (virt->next->val == val) {
ListNode* tmp = virt->next;
virt->next = tmp->next;
delete tmp;
}
else virt = virt->next;
}
head = res->next; // 返回真正头指针
delete res; // 销毁虚拟头指针
// 不能销毁virt:空指针没问题(最后一个元素不等于val),
// 如果是最后一个有效元素(virt->next->val == val)返回将错误
return head;
}
};
// 规范版
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* virt = new ListNode(0, head); // 挂在真正头结点前
// 上述代码知:while中链表遍历指针不能delete,如果选动态内存分配new出的指针遍历,
// 意味着不能delete;可 new出的空间最好delete释放掉,所以不能选virt.
ListNode* res = virt; // so,res遍历,virt保存(最后销毁)
while (res->next != NULL) {
if (res->next->val == val) {
ListNode* tmp = res->next;
res->next = tmp->next;
delete tmp;
}
else res = res->next;
}
head = virt->next; // 返回真正头指针
delete virt; // 销毁虚拟头指针
return head;
}
};
707.设计链表
- 思路:起初没想到:用location记录位置走的有点麻烦,把自己搞蒙了
- 实现:
class MyLinkedList {
private:
int _size;
LinkedList* _dummyHead;
LinkedList* _p;
public:
struct LinkedList {
int val;
LinkedList *next;
LinkedList(int val) {
this->val = val;
this->next = 0;
}
};
MyLinkedList() {
_dummyHead = new LinkedList(-1);
_size = 0; // 结点个数
_p = _dummyHead; // 虚拟头结点
}
int get(int index) {
_p = _dummyHead;
if (index > _size-1) return -1;
int loc = -1;
while (_p->next != 0) {
_p = _p->next;
loc++;
if (loc == index) break;
}
return _p->val;
}
void addAtHead(int val) {
_p = _dummyHead;
LinkedList *tmp = new LinkedList(val);
tmp->next = _p->next;
_p->next = tmp;
_size++;
tmp = 0;
delete tmp;
return;
}
void addAtTail(int val) {
_p = _dummyHead;
LinkedList *tmp = new LinkedList(val);
while (_p->next != 0) {
_p = _p->next;
}
_p->next = tmp;
_size++;
tmp = 0;
delete tmp;
}
void addAtIndex(int index, int val) {
if (index <= 0) return this->addAtHead(val); // index<=0
if (index == _size) return this->addAtTail(val); // index 在末尾
if (index > _size) return;
_p = _dummyHead;
int loc = -1;
while (index--) {
_p = _p->next;
}
LinkedList *tmp = new LinkedList(val);
tmp->next = _p->next;
_p->next = tmp;
_size++;
tmp = 0;
delete tmp;
return;
}
void deleteAtIndex(int index) {
if (index > _size-1) return;
_p = _dummyHead;
while (index--) {
_p = _p->next;
}
LinkedList *tmp = _p->next;
_p->next = tmp->next;
delete tmp;
_size--;
return;
}
};
206.反转链表
- 思路:快慢指针
- 做法:
- 实现
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* low = nullptr; // 慢指针要比快指针慢一拍(某一时刻二者有一个元素间隔),用于快指针指向慢指针代表的前一个元素
ListNode* fast = head;
ListNode* tmp = nullptr; // 用于保存快指针的下一步
while(fast != nullptr) {
tmp = fast->next;
fast->next = low;
low = fast;
fast = tmp;
}
return low;
}
};