提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
提示:这里可以添加本文要记录的大概内容:
1.移除链表元素的算法
2.设计链表(插入,删除,查询)
3.反转链表
提示:以下是本篇文章正文内容,下面案例可供参考
一、移除链表元素(力扣203)
实现思想:在链表的头节点之前创建一个虚拟头节点(dummy_head),指针从虚拟头节点开始,每次判断指针的下一个值是否是需要删除的元素,如果是就执行p->next = p->next->next;否则就正常执行p = p->next操作
1. 力扣写法
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummy_head = new ListNode(-1);
dummy_head->next = head;
ListNode* cur = dummy_head;
while(cur->next){
if (cur->next->val == val){
cur->next = cur->next->next;
}
else{
cur = cur->next;
}
}
return dummy_head->next;
}
};
2.自行创建链表并实现移除链表中元素的操作
#include <iostream>
using namespace std;
struct ListNode{
int val;
ListNode* next;
ListNode(int val):val(val), next(nullptr){}
};
//创建一个链表
void create(ListNode* head){
ListNode* p = head;
for (int i = 5; i > 0; i--){
ListNode* newNode = new ListNode(i);
newNode->next = p->next;
p->next = newNode;
}
}
//遍历整个链表,并输出每一个节点的值
void printlist(ListNode* head){
ListNode* p = head;
while(p){
cout << p->val << ' ';
p = p->next;
}
cout << endl;
}
void remove_target(ListNode* &head, int target){
//首先给链表添加一个虚拟头节点
//原来的链表:0(head)->1->2->3->4->5->null
//添加虚拟头节点后: 虚拟(dummy_head)->0(head)->1->2->3->4->5->null
ListNode* dummy_head = new ListNode(-1);
dummy_head->next = head;
ListNode* p = dummy_head;
while(p->next){
// 如果当前节点的下一个节点的值是我们要删除的值我们就删除下一个节点
if (p->next->val == target){
p->next = p->next->next;
}else{
//否则就让p正常向后移动
p = p->next;
}
}
//因为原本的头节点可能会被删除,所以在删除操作完成后要再次指定头节点
head = dummy_head->next;
//释放虚拟头节点的空间
delete dummy_head;
}
int main(void){
ListNode *head = new ListNode(0);
//创建链表
create(head);
//打印没有删除之前的链表
printlist(head);
//删除指定值
remove_target(head, 1);
//打印删除之后的链表
printlist(head);
return 0;
}
二、设计链表(力扣707)
1.力扣写法
class MyLinkedList {
public:
struct LinkedNode{
int val;
LinkedNode* next;
LinkedNode(int val):val(val), next(nullptr){}
};
//用来初始化链表
MyLinkedList() {
_dummy_head = new LinkedNode(-1);
_dummy_head->next = nullptr;
_size = 0;
}
int get(int index) {
if (index < 0 || index > _size - 1){
return -1;
}
LinkedNode* p = _dummy_head->next;
while(index--) p = p->next;
return p->val;
}
void addAtHead(int val) {
LinkedNode* Node = new LinkedNode(val);
Node->next = _dummy_head->next;
_dummy_head->next = Node;
_size++;
}
void addAtTail(int val) {
LinkedNode* p = _dummy_head;
while(p->next){
p = p->next;
}
LinkedNode* Node = new LinkedNode(val);
Node->next = p->next;
p->next = Node;
_size++;
}
void addAtIndex(int index, int val) {
if (index < 0 || index > _size) return;
LinkedNode* p = _dummy_head;
while(index--){
p = p->next;
}
LinkedNode* Node = new LinkedNode(val);
Node->next = p->next;
p->next = Node;
_size++;
}
void deleteAtIndex(int index) {
if (index < 0 || index > _size - 1) return;
LinkedNode* p = _dummy_head;
while(index--){
p = p->next;
}
LinkedNode* tmp = p->next;
p->next = tmp->next;
delete tmp;
_size--;
}
private:
int _size;
LinkedNode* _dummy_head;
};
/**
* 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);
*/
三、反转链表(力扣206)
实现思想:用三个指针pre, cur, tmp,pre从空开始,cur从头节点开始,tmp每次用来保存cur->next,因为如果不保存cur->next那么在执行cur->next = pre,操作之后cur指针后面的节点会全部丢失
1. 力扣写法
class Solution {
public:
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;
}
};
2.自行创建链表并实现链表反转的操作
#include <iostream>
using namespace std;
struct ListNode{
int val;
ListNode* next;
ListNode(int val):val(val), next(nullptr){}
};
//创建一个链表
void create(ListNode* head){
ListNode* p = head;
for (int i = 5; i > 0; i--){
ListNode* newNode = new ListNode(i);
newNode->next = p->next;
p->next = newNode;
}
}
//遍历整个链表,并输出每一个节点的值
void printlist(ListNode* head){
ListNode* p = head;
while(p){
cout << p->val << ' ';
p = p->next;
}
cout << endl;
}
//反转链表
void reverse(ListNode* &head){
ListNode* pre = nullptr;
ListNode* cur = head;
//while(cur)这种写法会让cur最后指向一个空指针,这时候pre指向的是整个链表最后一个节点,所以要把pre赋给head
//while(cur->next)这种写法会让指针停留在最后一个节点且不会将最后一个节点指向倒数第二个节点
//因为最后一个节点的next指针指向null,因此不会进入最后一次循环,也就不会将最后一个节点指向
//倒数第二个节点,链表也就丢失了一个节点 ,因此不能使用这种方式
while(cur){
ListNode* tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
head = pre;
}
int main(void){
ListNode *head = new ListNode(0);
//创建链表
create(head);
//打印没有删除之前的链表
printlist(head);
//反转链表
reverse(head);
//打印反转之后的链表
printlist(head);
return 0;
}