链表理论基础
单链表
只能向后查询
双链表
可以双向查询
循环链表
首尾链接
链表的存储方式
链表在内存中不需要是连续分布的!和数组不同!
链表通过指针域的指针链接在内存中的各个节点,所以可以散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
链表的定义
C/C++定义链表节点:
struct ListNode {
int val; // value of the node
ListNode* next; // pointer points to the next node
ListNode(int x): val(x), next(NULL) {} // construct function, initialize val and assign next to NULL
};
定义构造函数可以让你初始化节点:
ListNode* head = new ListNode(5);
如果使用C++默认构造函数,在初始化时不可以直接给变量赋值!
ListNode* head = new ListNode();
head->val = 5;
链表的操作
删除节点
把C的next指针指向E,把D的指针断开并手动释放D。
在Java,Python等语言中有自己的内存回收机制,不需要自己手动释放。
添加节点
C的next指针指向F,F的next指针指向D。
添加和删除都是O(1),但是要是删除最后一个节点,查找的复杂度是O(N)。
性能分析
数组的长度是固定的!想改长度只能新建一个新数组!
链表的长度是不固定的,可以动态删减,适用于频繁删减较少查询的场景。
203.移除链表元素 Remove Linked List Elements
需要把删除head和删除其他元素分开讨论,但也可以使用虚拟头节点的方式进行统一删除法
C解法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* temp = head;
while (head && head->val == val){
temp = head;
head = head->next;
temp->next = NULL;
free(temp);
}
struct ListNode* node = head;
while (node && node->next){
while (node->next && node->next->val == val){
temp = node->next;
node->next = node->next->next;
temp->next = NULL;
free(temp);
}
node = node->next;
}
return head;
}
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* temp;
while (head && head->val == val){
temp = head;
head = head->next;
temp->next = NULL;
delete temp;
}
ListNode* node = head;
while (node && node->next){
while (node->next && node->next->val == val){
temp = node->next;
node->next = node->next->next;
temp->next = NULL;
delete temp;
}
node = node->next;
}
return head;
}
};
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
"""
while (head and head.val == val):
head = head.next
node = head
while (node and node.next):
while (node.next and node.next.val == val):
node.next = node.next.next
node = node.next
return head
虚拟头节点
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
"""
dummpyhead = ListNode(next = head)
node = dummpyhead
while (node and node.next):
while (node.next and node.next.val == val):
node.next = node.next.next
node = node.next
return dummpyhead.next
707.设计链表 Design Linked List
单向链表
需要什么?
- 定义节点,每个节点需要:
- val 储存的值
- next 指向下一个节点的指针
- 一个虚拟头,Leetcode官方称之为哨兵(sentinel)
- 一个size参数保存有效节点 (有助于进行与index相关的操作时可以先行判定index的validity
定义节点的方式有很多种:
- 新建一个class
- 或者在现有的MyLinkedList里定义一个struct
虚拟头和size则为MyLinkedList Class的variable
一些需要注意的C++ Convention:
The public, protected, and private sections of a class are to be declared in that order (the public section is declared before the protected section which is declared before the private section).
C++解法
要注意addAtIndex这个function的用法,当index==length,操作如同addAtTail
class MyLinkedList {
public:
MyLinkedList() {
head = new ListNode();
size = 0;
}
int get(int index) {
if (index < 0 || index > size - 1) {
return -1;
} else {
ListNode* current = head->next;
while (index--){
current = current->next;
}
return current->val;
}
}
void addAtHead(int val) {
// our "head" is not the real head!!!
if (val <= 1000){
ListNode* newHead = new ListNode(val);
newHead->next = head->next;
head->next = newHead;
size++;
}
}
void addAtTail(int val) {
if (val <= 1000){
ListNode* newTail = new ListNode(val);
ListNode* current = head;
while (current->next){
current = current->next;
}
current->next = newTail;
size++;
}
}
void addAtIndex(int index, int val) {
/** Add a node of value val before the indexth node in the linked list.
* If index equals the length of the linked list, the node will be appended
* to the end of the linked list. If index is greater than the length,
* the node will not be inserted.
**/
if (index < 0 || index > size) {
return;
} else if (val <= 1000) {
ListNode* current = head;
while (index--){
current = current->next;
}
ListNode* newNode = new ListNode(val);
newNode->next = current->next;
current->next = newNode;
size++;
}
}
void deleteAtIndex(int index) {
if (index < 0 || index > size - 1) {
return;
} else {
ListNode* current = head;
while (index--){
current = current->next;
}
ListNode* deleteNode = current->next;
current->next = deleteNode->next;
delete deleteNode;
size--;
}
}
private:
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) {}
};
ListNode* head;
int size;
};
/**
* 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);
*/
C解法
struct的定义很重要!!!
typedef struct MyLinkedList {
int val;
struct MyLinkedList* next;
} MyLinkedList;
MyLinkedList* myLinkedListCreate() {
MyLinkedList* head = (MyLinkedList*) malloc (sizeof(MyLinkedList));
head->val = 0;
head->next = NULL;
return head;
}
int myLinkedListGet(MyLinkedList* obj, int index) {
int size = obj->val;
if (index < 0 || index > size - 1){
return -1;
} else {
MyLinkedList* current = obj->next;
while (index--) {
current = current->next;
}
return current->val;
}
}
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
if (val <= 1000){
MyLinkedList* newObj = (MyLinkedList*) malloc (sizeof(MyLinkedList));
newObj->val = val;
newObj->next = obj->next;
obj->next = newObj;
obj->val++;
}
}
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
if (val <= 1000){
MyLinkedList* current = obj;
MyLinkedList* newObj = (MyLinkedList*) malloc (sizeof(MyLinkedList));
newObj->val = val;
newObj->next = NULL;
while (current->next){
current = current->next;
}
current->next = newObj;
obj->val++;
}
}
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
int size = obj->val;
if (index < 0 || index > size){
return;
} else if (val <= 1000){
MyLinkedList* current = obj;
MyLinkedList* newObj = (MyLinkedList*) malloc (sizeof(MyLinkedList));
newObj->val = val;
newObj->next = NULL;
while (index--){
current = current->next;
}
newObj->next = current->next;
current->next = newObj;
obj->val++;
}
}
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
int size = obj->val;
if (index < 0 || index > size - 1){
return;
} else {
MyLinkedList* current = obj;
while (index--){
current = current->next;
}
MyLinkedList* deleteNode = current->next;
current->next = current->next->next;
deleteNode->next = NULL;
free(deleteNode);
obj->val--;
}
}
void myLinkedListFree(MyLinkedList* obj) {
while (obj){
MyLinkedList* deleteNode = obj;
obj = obj->next;
deleteNode->next = NULL;
free(deleteNode);
}
}
/**
* Your MyLinkedList struct will be instantiated and called as such:
* MyLinkedList* obj = myLinkedListCreate();
* int param_1 = myLinkedListGet(obj, index);
* myLinkedListAddAtHead(obj, val);
* myLinkedListAddAtTail(obj, val);
* myLinkedListAddAtIndex(obj, index, val);
* myLinkedListDeleteAtIndex(obj, index);
* myLinkedListFree(obj);
*/
Python解法
class ListNode:
def __init__(self, val):
self.val = val
self.next = None
class MyLinkedList(object):
def __init__(self):
self.head = ListNode(0)
self.size = 0
def get(self, index):
"""
:type index: int
:rtype: int
"""
if (index < 0 or index > self.size - 1):
return -1
else:
curr = self.head.next
while index:
curr = curr.next
index -= 1
return curr.val
def addAtHead(self, val):
"""
:type val: int
:rtype: None
"""
if val <= 1000:
new = ListNode(val)
new.next = self.head.next
self.head.next = new
self.size += 1
def addAtTail(self, val):
"""
:type val: int
:rtype: None
"""
if val <= 1000:
curr = self.head
while (curr.next):
curr = curr.next
curr.next = ListNode(val)
self.size += 1
def addAtIndex(self, index, val):
"""
:type index: int
:type val: int
:rtype: None
"""
if (index < 0 or index > self.size):
return
elif val <= 1000:
curr = self.head
while index:
index -= 1
curr = curr.next
new = ListNode(val)
new.next = curr.next
curr.next = new
self.size += 1
def deleteAtIndex(self, index):
"""
:type index: int
:rtype: None
"""
if (index < 0 or index > self.size - 1):
return
else:
curr = self.head
while index:
index -= 1
curr = curr.next
delete = curr.next
curr.next = curr.next.next
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)
双指针写法可参照Leetcode官方解答:官方解答
206.反转链表 Reverse Linked List
代码随想录文章里的动图可以很直观的展现这个题的解法
反转指针:
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* reverseList(ListNode* head) {
ListNode* temp;
ListNode* curr = head;
ListNode* prev = nullptr;
while(curr){
temp = curr->next;
curr->next = prev;
prev = curr;
curr = temp;
}
return prev;
}
};
C解法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* temp;
struct ListNode* curr = head;
struct ListNode* prev = NULL;
while (curr) {
temp = curr->next;
curr->next = prev;
prev = curr;
curr = temp;
}
return prev;
}
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
"""
curr = head
prev = None
while (curr):
temp = curr.next
curr.next = prev
prev = curr
curr = temp
return prev
递归法
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* reverser(ListNode* prev, ListNode* curr){
if (!curr) return prev;
ListNode* temp = curr->next;
curr->next = prev;
return reverser(curr, temp);
}
ListNode* reverseList(ListNode* head) {
return reverser(nullptr, head);
}
};
C解法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverse(struct ListNode* prev, struct ListNode* curr){
if (!curr){
return prev;
}
struct ListNode* temp = curr->next;
curr->next = prev;
return reverse(curr, temp);
}
struct ListNode* reverseList(struct ListNode* head){
return reverse(NULL, head);
}
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, prev, curr):
if not curr:
return prev
temp = curr.next
curr.next = prev
return self.reverse(curr, temp)
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
return self.reverse(None, head)