题目链接 :移除链表元素
首先有一个疑问,这个链表是默认是单链表吗?是的
已知链表头节点head和一个整数val,删除链表中与val相等的节点,返回新的头节点。
遍历链表中的各个节点的元素,比较每个节点元素与val的大小,如果相等,则将该元素所在节点的前一个节点的指针指向该节点的下一个节点,如此遍历下去,直到所有的节点元素都比较判断完成。
自己思路存在的问题
Q1:首先就是没有考虑头节点的情况与其他节点不同,没有分类讨论
Q2:还有就是自己的思想太简单了,一直想着遍历,对于单链表而言,是无法找寻上一个节点的,因为是单向的。
/**
* 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) {
//分两步考虑,头节点 非头节点
//删除头节点,首先判断头节点是否为空,若为空,相当于对空指针进行操作,编译报错
//注意这是一个循环遍历的过程[1,1,1],val=1,持续移除的过程
while(head!=NULL&&head->val==val)//头节点不能为空,因为要取头节点的值
{
head = head -> next;
}
//删除非头节点
ListNode* cur = head; //这里需要定义头节点的类型,将cur指向头节点,如果指向当前要删除
//的位置的话,前一个节点无法寻找
while(cur!=NULL&&cur->next!=NULL)//因为要对cur->next进行操作,所以事先必须判断cur
不为空,cur->next也不能为空,因为cur->next与val进行
对比,如果为空,则是对空指针进行操作
{
if(cur->next->val==val)//如果出现相等的情况
{
cur->next = cur->next->next;
}
else //如果不等的话,则cur继续指向下一个元素,继续进行while循环
{
cur = cur->next;
}
}
return head; //头节点一直存在,所以返回头节点
}
};
网站上直接使用原链表进行移除操作(思想相同)
/**
* 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) {
//分两步考虑,头节点 非头节点
//删除头节点,首先判断头节点是否为空,若为空,相当于对空指针进行操作,编译报错
//注意这是一个循环遍历的过程[1,1,1],val=1,持续移除的过程
while(head!=NULL&&head->val==val)
{
ListNode* tmp = head;//设定一个中间变量,最后直接删除这个tmp即可
head = head ->next;
delete tmp;
}
//删除非头节点
ListNode* cur = head; //这里需要定义头节点的类型,将cur指向头节点,如果指向当前要删除的位置的话,前一个节点无法寻找
while(cur!=NULL&&cur->next!=NULL)//因为要对cur->next进行操作,所以事先必须判断cur-next不为空
{
if(cur->next->val==val)//如果出现相等的情况
{
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
else //如果不等的话,则cur继续指向下一个元素,继续进行while循环
{
cur = cur->next;
}
}
return head; //头节点一直存在,所以返回头节点
}
};
/**
* 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;//这里不是简单的赋值操作,是dummyhead指向head
//将dummyhead当作头节点,剩下的包括head在内的所有节点一样,这样就不用分类讨论了
ListNode* cur = dummyhead; //因为是单向链表,所以只能向后找,所以进行这样的赋值 注意对cur进行定义
while(cur!=NULL&&cur->next!=NULL) //因为要对cur->next进行操作,所以需保证其不为空
{
if(cur->next->val==val) //如果cur的下一个值与val相等,则进行操作,
{
cur->next = cur->next->next;
}
else
{
cur = cur->next; //如果cur的下一个值与val不相等,则将cur推至下一个节点
}
}
return dummyhead->next;//这个头节点head(整个链表)是一直都没有动的
}
};
网站上给出的对应的代码
/**
* 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;
//将dummyhead当作头节点,剩下的包括head在内的所有节点一样,这样就不用分类讨论了
ListNode* cur = dummyhead; //因为是单向链表,所以只能向后找,所以进行这样的赋值 注意对cur进行定义
while(cur->next!=NULL) //因为要对cur->next进行操作,所以需保证其不为空
{
if(cur->next->val==val) //如果cur的下一个值与val相等,则进行操作,
{
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
else
{
cur = cur->next; //如果cur的下一个值与val不相等,则将cur推至下一个节点
}
}
return dummyhead->next;//这个头节点head(整个链表)是一直都没有动的
"""
head = dummyhead->next;
delete dummyhead;
return head;//这个头节点head其实就是上dummyhead这三行有点多余有一行就够了
"""
}
};
题目链接:设计链表
共有1个类定义和5个函数定义
类:初始化
5个函数:
获取下标对应的节点值
将节点插入到头节点之前,使之成为新的头节点
将节点放到最后一个结点之后
将节点插入到中间某一个节点之前
删除某一个节点
index
的相关操作为 O(index), 其余为 O(1)class MyLinkedList {
public:
//定义链表节点结构体
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val):val(val),next(nullptr){}
};
MyLinkedList() {
dummyhead = new LinkedNode(0); //定义虚拟头节点
_size = 0;
}
int get(int index) {
//LinkedNode* dummyhead = new LinkedNode(0); //定义虚拟头节点 这一行不用,前面已经定义了
if(index>(_size-1)||index<0)
{
return -1;
}//头节点下标是0,尾节点下标是size-1
// LinkedNode* cur = dummyhead;
// while(index)
// {
// cur = cur->next;
// index--;
// }
// return cur->next->val; //这段代码也可以正常运行
LinkedNode* cur = dummyhead->next;//因为题目中获取的是index下标对应的值
while(index)
{
cur = cur->next;
index--;
}
return cur->val;
}
void addAtHead(int val) {
// LinkedNode* dummyhead = new LinkedNode(0); //定义虚拟头节点 前面已经定义了
LinkedNode* newnode = new LinkedNode(val);
// LinkedNode* cur = dummyhead;//像这种,可以直接使用dummyhead做运算
// newnode->next = cur->next;
// cur->next = newnode;
// _size++;//这个函数的类型是void所以不返回任何东西 这段代码也可以正常运行
newnode->next = dummyhead->next;
dummyhead->next = newnode;
_size++;
}
void addAtTail(int val) {
// LinkedNode* dummyhead = new LinkedNode(0); //定义虚拟头节点 前面已经定义了不需要
LinkedNode* newnode = new LinkedNode(val);
LinkedNode *cur = dummyhead;
while(cur->next!=nullptr){
cur = cur->next;
}//如果cur->next==null才指向最后一个节点,那就对其进行操作,
// while(cur->next!=NULL)/
// {
// cur = cur->next;
// }
// //也可以使用while(cur->next->val!=Null)
cur->next = newnode;
_size++;
}
void addAtIndex(int index, int val) {
// LinkedNode* dummyhead = new LinkedNode(0); //定义虚拟头节点不需要,前面已经定义了
if(index>_size) return;
if(index<0) return;
LinkedNode* cur = dummyhead;
LinkedNode* newnode = new LinkedNode(val);
while(index){
cur = cur->next;
index--;
}
newnode->next = cur->next;
cur->next = newnode;
_size++;
}
void deleteAtIndex(int index) {
// LinkedNode* dummyhead = new LinkedNode(0); //定义虚拟头节点 不需要这一行,前面已经定义
if(index>=_size||_size<0)
{
return;
}
LinkedNode* cur = dummyhead;
while(index)
{
cur = cur->next;
index--;
}
//cur->next = cur->next->next;
LinkedNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;//delete命令指示释放了tmp指针原本所指的那部分内存,
//被delete后的指针tmp的值(地址)并非就是NULL,而是随机值。也就是被delete后,
//如果不再加上一句tmp=nullptr,tmp会成为乱指的野指针
//如果之后的程序不小心使用了tmp,会指向难以预想的内存空间
tmp = nullptr;
_size--;
}
void printLinkedList() {
LinkedNode* cur = dummyhead;
while (cur->next != nullptr) {
cout << cur->next->val << " ";
cur = cur->next;
}
cout << endl;
}
private:
int _size;
LinkedNode* dummyhead;
};
/**
* 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);
*/
// 打印链表
①获取下标对应的节点值
将cur=dummyhead->next就可,因为是一个直接取值的操作,不涉及前面的节点。
②将节点插入到头节点之前,使之成为新的头节点
设定一个虚拟节点,令cur=dummyhead,cur->next=head,因为要在头节点前面插入一个节点,所以需要用到头节点前面的虚拟节点,所以这样设置,如果cur=head的话,无法找到前面的虚拟节点。
③将节点放到最后一个结点之后
cur=dummyhead,判断条件是,cur->next!=NULL, 若不满足,即·当cur->next为空时,说明cur到了最后一个节点,再将cur->next=newnode即可
④将节点插入到中间某一个节点之前
首先要执行①F->next=D,然后②C->next=F,这样才会成功,如果两者顺序颠倒,那么就会导致D节点先消失,找不到该节点,最终无法插入。
令cur=C,cur->next=D,因为这个操作,关系到节点的前一个节点,所以要这样设置,如果将D赋值给cur的话,最终找不到C节点,无法完成插入操作。
⑤删除某一个节点
与添加某一个节点相似,同样要知道删除的节点所在的前一个节点,那么删除的这个节点设置为cur->next,其前一个节点是cur,使得cur->next=cur->next->next即可
题目链接:反转链表
将链表“倒置”
定义一个cur指向head,pre位于head的前面,,在反转链表中cur指向pre,即将pre赋值给cur->next,temp临时指针,代表cur之后的那个节点。
首先确定循环的范围,直到cur=NULL,整个链表才遍历完成,
一定要先c后d,如果调换顺序的话,那么cur和pre的内容一样,是无效的
首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。
然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。
为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。
接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。
最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。
/**
* 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* cur = head;
ListNode* pre = NULL;
ListNode* temp ;
while(cur)
{
temp = cur->next;
cur ->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};
/**
* 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* temp = cur->next;
cur->next = pre;
return reverse(cur,temp);
}
ListNode* reverseList(ListNode* head) {
return reverse(NULL,head);
}
};