文章链接:代码随想录
链表的类型:单链表 、双链表、循环链表。链表时通过指针域的指针链接再内存中的各个节点。
链表的定义:其实相当于一个数据结构(打包两个值),分别是当前节点的值,和下一个元素的地址。
C++:
// 单链表
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) {}
};
Python:
class ListNode:
def __init__(self, val, next = None):
self.val = val
self.next = next
链表的操作:删除节点、添加节点
203. 移除链表元素
题目要求:删除链表中等于给定值val的所有节点。注意C++需要进行手动内存管理。
移除头节点,需要单独写一段逻辑来处理,只需要将头节点向后移动一位。同时要将原头节点从内存中删除。
如何用统一的逻辑删除链表的节点?给链表添加一个虚拟头节点来作为新的头节点,原来的旧的头节点就变成了节点元素1。
C++(直接使用原来的链表来删除,需要手动处理头节点):
/**
* Definition for singly-linked list.
* 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) {
// Delete header node
while (head != NULL && head -> val == val) {
ListNode* tmp = head;
head = head -> next; // address
delete tmp;
}
// Delete Nonheader node
ListNode* cur = head;
while (cur != NULL && cur -> next != NULL){
if (cur -> next -> val == val){
ListNode* tmp = cur -> next;
cur -> next = cur -> next -> next;
delete tmp; // 手动内存处理
} else{
cur = cur -> next; // 更新cur
}
}
return head;
}
};
在删除非头节点时,实际上是考察,头节点的下一个节点是否需要删除,如果需要删除只需要把头节点的next指向next->next即可。然后再把旧的头节点的next删除掉。后续一直在更新的是cur,而我们的头节点没有改变。
C++(设置一个虚拟头节点,再进行移除节点):
/**
* Definition for singly-linked list.
* 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) {
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;
}
};
在头节点前面新建一个node,指向头节点。
Python:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
dummyhead = ListNode(next = head)
cur = dummyhead
while cur.next:
if cur.next.val == val:
cur.next = cur.next.next
else:
cur = cur.next
return dummyhead.next
707. 设计链表
题目要求:实现链表的一些功能
如果比较熟悉C++中类与对象的关系,我觉得这道题还是比较好实现的。在初始情况下我并没有一个链表,我只有一个_dummyhead初始值为0,指向nullptr。
C++:
class MyLinkedList {
public:
// 定义链表节点结构体
struct LinkedNode{
int val;
LinkedNode *next;
LinkedNode(int val) : val(val), next(nullptr){}
};
private:
int _size;
LinkedNode* _dummyhead;
public:
// 初始化链表
MyLinkedList() {
_dummyhead = new LinkedNode(0);
_size = 0;
}
// 返回index节点值,如果非法则返回-1
int get(int index) {
if (index > (_size - 1) || index < 0){
return -1;
}
LinkedNode* cur = _dummyhead->next;
while(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++;
}
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++;
}
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并非NULL而是随即量,会成为野指针指向不知名内存空间。
tmp = nullptr;
_size--;
}
void printLinkedList(){
LinkedNode* cur = _dummyhead;
while(cur->next!=nullptr) {
cout << cur->next->val << " ";
cur = cur->next;
}
cout << endl;
}
};
/**
* 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);
*/
Python(双向链表法):
class ListNode:
def __init__(self, val=0, prev=None, next=None):
self.val = val
self.prev = prev
self.next = next
class MyLinkedList(object):
def __init__(self):
self.head = None
self.tail = None
self.size = 0
def get(self, index):
"""
:type index: int
:rtype: int
"""
if index < 0 or index >= self.size:
return -1
if index < self.size//2:
cur = self.head
for i in range(index):
cur = cur.next
else:
cur = self.tail
for i in range(self.size - index - 1):
cur = cur.prev
return cur.val
def addAtHead(self, val):
"""
:type val: int
:rtype: None
"""
newNode = ListNode(val, None, self.head)
if self.head:
self.head.prev = newNode
else:
self.tail = newNode
self.head = newNode
self.size += 1
def addAtTail(self, val):
"""
:type val: int
:rtype: None
"""
newNode = ListNode(val, self.tail, None)
if self.tail:
self.tail.next = newNode
else:
self.head = newNode
self.tail = newNode
self.size += 1
def addAtIndex(self, index, val):
"""
:type index: int
:type val: int
:rtype: None
"""
if index < 0 or index > self.size:
return
if index == 0:
self.addAtHead(val)
else:
if index < self.size // 2:
cur = self.head
for i in range(index - 1):
cur = cur.next
else:
cur = self.tail
for i in range(self.size - index):
cur = cur.prev
newNode = ListNode(val, cur, cur.next)
if cur.next:
cur.next.prev = newNode
else:
self.tail = newNode
cur.next = newNode
self.size += 1
def deleteAtIndex(self, index):
"""
:type index: int
:rtype: None
"""
if index < 0 or index >= self.size:
return
if index == 0:
self.head = self.head.next
if self.head:
self.head.prev = None
else:
self.tail = None
elif index == self.size - 1:
self.tail = self.tail.prev
if self.tail:
self.tail.next = None
else:
self.head = None
else:
if index < self.size // 2:
cur = self.head
for i in range(index):
cur = cur.next
else:
cur = self.tail
for i in range(self.size - index - 1):
cur = cur.prev
cur.prev.next = cur.next
cur.next.prev = cur.prev
self.size -= 1
# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
这里涉及很多head、tail是否存在的边界问题,需要注意并处理。
206. 反转链表
题目要求:反转一个单链表。
改变链表next的方向,直接将单链表反转。
C++(双指针法,定义一个cur指针存储当前状态,把cur的next指向pre,需要一个tmp暂存cur->next做状态转移):
/**
* Definition for singly-linked list.
* 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* reverseList(ListNode* head) {
ListNode* tmp;
ListNode* cur = head;
ListNode* pre = NULL;
while(cur){
tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
};
C++(递归法):
/**
* Definition for singly-linked list.
* 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* reverse(ListNode* pre, ListNode* cur){
if(cur == NULL) return pre;
ListNode* tmp = cur->next;
cur->next = pre;
return reverse(cur, tmp);
}
ListNode* reverseList(ListNode* head) {
return reverse(NULL, head);
}
};
C++(递归法2):
/**
* Definition for singly-linked list.
* 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* reverseList(ListNode* head) {
if(head == NULL) return NULL;
if(head->next == NULL) return head;
ListNode* last = reverseList(head->next);//把head->next作为新的头节点
head->next->next = head;
head->next = NULL;
return last;
}
};
Python(双指针法):
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
cur = head
pre = None
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre
Python(递归法):
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def reverse(self, cur, pre):
if cur == None:
return pre
tmp = cur.next
cur.next = pre
return self.reverse(tmp, cur)
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
return self.reverse(head, None)
要注意分清哪个是cur状态,哪个是pre状态,什么应该被存储在tmp状态中。