第二章 链表part01
- 链表理论基础
- 203.移除链表元素
- 707.设计链表
- 206.反转链表
链表理论基础
建议:了解一下链接基础,以及链表和数组的区别
文章链接:代码随想录
203.移除链表元素
建议: 本题最关键是要理解 虚拟头结点的使用技巧,这个对链表题目很重要。
题目链接:203. 移除链表元素 - 力扣(LeetCode)
文章讲解/视频讲解::代码随想录
707.设计链表
建议: 这是一道考察 链表综合操作的题目,不算容易,可以练一练 使用虚拟头结点
题目链接:707. 设计链表 - 力扣(LeetCode)
文章讲解/视频讲解:代码随想录
206.反转链表
题目链接:206. 反转链表 - 力扣(LeetCode)
文章讲解/视频讲解:代码随想录
c++代码示例如下O(n)
ListNode* removeElements(ListNode* head, int val) {while (head != NULL && head->val == val) {ListNode* tmp = head;head = head->next;delete tmp;}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;}}return head;
}
设置一个虚拟头结点再进行移除节点操作
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;
}
这个例子中ListNode(0)源于链表结构体定义中的构造函数。
ListNode(int x) : val(x),next(NULL) {}
让我们逐一解析这段代码:
ListNode (int x)
: 这是ListNode
类的构造函数的声明。它接受一个整数参数x
。:val(x), next(NULL)
: 这是初始化列表。它用于初始化类的成员变量。在这里,val
成员变量被初始化为x
,而next
成员变量被初始化为NULL
。{ }
: 这是构造函数的主体。在这里它是空的,因为所有的初始化都在初始化列表中完成了。
总的来说,当你创建一个新的ListNode
对象并传递一个整数给它时,这个构造函数将确保该节点的值被设置为该整数,并且该节点没有指向任何下一个节点(因为next
被初始化为NULL
)。
注意:如果不定义构造函数使用默认构造函数的话,在初始化的时候不能直接给变量赋值!
c++代码示例如下
class MyLinkedList {
public:struct LinkedNode {int val;LinkedNode* next;LinkedNode(int val) :val(val), next(NULL) {}};MyLinkedList() {dummyHead = new LinkedNode(0);size = 0;}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 != NULL) {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;tmp = NULL;size--;}
private:int size;LinkedNode* dummyHead;
};
c语言代码示例如下
typedef struct MyLinkedList {int val;struct MyLinkedList* next;
}MyLinkedList;
MyLinkedList* myLinkedListCreate() {MyLinkedList* head = (MyLinkedList*)malloc(sizeof(MyLinkedList));head->next = NULL;return head;
}
int myLinkedListGet(MyLinkedList* obj, int index) {MyLinkedList* cur = obj->next;for (int i = 0; cur != NULL; i++) {if (i == index) {return cur->val;}else {cur = cur->next;}}return -1;
}
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {MyLinkedList* nhead = (MyLinkedList*)malloc(sizeof(MyLinkedList));nhead->val = val;nhead->next = obj->next;obj->next = nhead;
}
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {MyLinkedList* cur = obj;while (cur->next != NULL) {cur = cur->next;}MyLinkedList* ntail = (MyLinkedList*)malloc(sizeof(MyLinkedList));ntail->val = val;ntail->next = NULL;cur->next = ntail;
}
void myLinkedListAddAtIndex(MyLinkedList* obj,int index,int val) {if (index == 0) {myLinkedListAddAtHead(obj, val);return;}MyLinkedList* cur = obj->next;for (int i = 1; cur != NULL; i++){if (i == index) {MyLinkedList* newNode = (MyLinkedList*)malloc(sizeof(MyLinkedList));newNode->val = val;newNode->next = cur->next;cur->next = newNode;return;}else {cur = cur->next;}}
}
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {if (index == 0) {MyLinkedList* tmp = obj->next;if (tmp != NULL) {obj->next = tmp->next;free(tmp);}return;}MyLinkedList* cur = obj->next;for (int i = 1; cur != NULL && cur->next != NULL; i++) {if (i == index) {MyLinkedList* tmp = cur->next;if (tmp != NULL) {cur->next = tmp->next;free(tmp);}return;}else {cur = cur->next;}}
}
void myLinkedListFree(MyLinkedList* obj) {while (obj != NULL) {MyLinkedList* tmp = obj;obj = obj->next;free(tmp);}
}
已知头结点,使用双指针法一个节点一个节点的处理:
定义一个cur指针(head),pre指针(NULL),定义一个临时变量tmp把cur->next的内容拿出来,然后把pre指针放进去,就完成了节点的反转。更新pre指针(cur),cur指针(tmp)。循环遍历完链表就完成整体的反转。循环结束时,cur一定指向最后一个节点的->next==NULL,pre一定指向最后一个节点。返回pre
c++代码示例如下O(n)
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;
}
还可以用递归实现,能够迭代就一定可以递归!
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) {if (head == NULL) return NULL;if (head->next == NULL) return head;ListNode* last = reverseList(head->next);head->next->next = head;head->next = NULL;return last;
}