【链表的定义和初始化】
首先定义节点
struct ListNode
{
double value;//每个节点的第一部分用来存储数据,节点为double类型的数据
ListNode *next;//每个节点的第二部分,指向下一个节点的指针
}
节点的构造函数可以不写,C++会默认生成一个构造函数
ListNode* head = new ListNode(5);//自己定义构造函数初始化节点,初始化的同时给变量节点赋值为5
//使用默认的构造函数初始化节点,就是得再加一个给节点赋值的语句
ListNode* head = new ListNode();
head->val = 5;
【收获1】null是整数类型,用nullptr可以不考虑类型转换问题,它的类型是std::nullptr_t,现在最好用后者。
【收获2】链表适合数据量不固定,频繁增删的数据集合。数组适合数据量较固定,较少增删的数据集合。
【删除链表中的节点】
这道题的求解不涉及复杂的算法,一种是直接从链表中移除元素,将待移除元素的前一个节点的指针,改为指向待移除元素的下一个节点,就实现了把这个节点从链表中移除,但是在C++中不能忘记手动把这个节点delete。
除此之外,头结点的移除和其他节点存在不同,因为移除头节点就要让与头节点相连接的节点变成头节点,代码实现如下:
//删除头节点
while(head != NULL&&head->val==val){ //要确保这个链表不是空的,头节点是有实际值的
ListNode* tmp = head; //将头节点的指针下的地址赋值给tmp
head = head -> next; //现在头节点移动到链表的下一个节点
delete tmp; //删除这个tmp,就让这个节点完全消失了。
}
删除非头节点的代码实现如下:
ListNode* cur = head;
while(cur !=NULL &&cur->next!=NULL){
if(cur->next->val==val){ //不难看出这里cur是val的前一个节点
ListNode* tmp = cur->next; //要被移除的是val所在处的节点,把存储这个节点位置的指针内的地址给tmp
cur->next = cur->next->next; //把这个val往后一个节点的地址放进cur->next,这样就实现了val地址被
//覆盖掉,也就实现了移除
delete tmp; //删除tmp,完全将其地址从内存中删除
}else{
cur = cur->next;//如果这个指针不是指向val节点的,就继续往后移动,直到找到这个位置,不进入else中
}
}
【使用虚拟头节点移除节点】
先定义一个虚拟头节点
ListNode* dummyHead = new ListNode(0);//设置一个虚拟节点
dummyHead->next = head;//将虚拟头节点指向head,这样方便后面做删除操作
确保不是空指针的情况下,再判断指针指向的值是不是val,如果是,那就进行删除节点操作,先把指向val的指针里存储的把val前一个节点的指针改为指向val的下一个节点,就是cur->next->next
这里注意一点,就是每个节点的第二部分(指针)存储的是下一个节点的地址。
ListNode* cur = dummyHead;//将虚拟头的值给cur
while(cur->next !=NULL){ //虚拟头指向当前实际头节点,只要这个节点不为空,就进入判断
if(cur->next->val == val){ //判断cur指向的节点的值是不是
ListNode* tmp = cur->next; //将val的地址存进tmp
cur->next = cur->next->next; //让val的前一个节点的第二部分指向val的后一个节点
delete tmp; //删除tmp,这时就完全删除了val这个节点
}else{
cur = cur->next; //如果不是指向val的指针,就向前走,让cur的指针向前移,进入下一次判断
}
}
完整求解过程代码:
/**
* 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;
}
};
【链表的设计】
求解源代码:
class MyLinkedList {
public:
MyLinkedList() {
this->head=new ListNode(0);
this->size = 0;
}
int get(int index) {
if(index<0||index >= size){
return -1;
}
ListNode *cur = head;
for(int i=0;i<=index;i++){
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
addAtIndex(0,val);
}
void addAtTail(int val) {
addAtIndex(size,val);
}
void addAtIndex(int index, int val) {
if(index >size){
return;
}
index = max(0,index);
size++;
ListNode *pred = head;
for(int i=0;i<index;i++){
pred = pred->next;
}
ListNode *toAdd = new ListNode(val);
toAdd->next = pred->next;
pred->next = toAdd;
}
void deleteAtIndex(int index) {
if(index<0||index >= size){
return;
}
size--;
ListNode *pred = head;
for(int i=0;i<index;i++)
{
pred = pred->next;
}
ListNode *p = pred->next;
pred->next=pred->next->next;
delete p;
}
private:
int size;
ListNode *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);
*/
【双指针法求解】
定义两个指针;pre和cur;pre再前cur在后。
每次让pre的next指向cur,实现一次的局部反转
局部反转完成后,pre和cur同时往前移动一个位置
循环上述过程,直至pre到达链表的尾部
class Solution{
public:
ListNode* reverseList(ListNode* head){
while (pre != NULL){
ListNode* t = pre->next;//定义指针pre,cur;pre在前cur在后
pre->next = cur; //让pre指向cur,实现第一次局部反转
cur = pre;//局部反转完成后,pre和cur同时往前移动一个位置
pre = t;
} //循环到pre到达链表尾部
return cur;
}
};
【递归法求解】
使用递归函数,一直低轨道链表的最后一个节点,该节点就是反转后的头节点,记作ret.
此后,每次函数在返回的过程中,让当前节点的下一个节点的next指针指向当前节点。
同时让当前节点的next指针指向NULL,从而实现从链表尾部开始的局部反转
当递归函数全部出栈后,链表反转完成。
/**
* 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||head -> next == NULL){
return head;
}
ListNode* ret = reverseList(head->next);
head->next->next = head;
head->next =NULL;
return ret;
}
};