今日开始补C++,
在C++中,与Python相比,链表的基本操作有一些区别:
-
节点定义和指针操作:在C++中,需要使用结构体定义链表节点,其中包括数据和指向下一个节点的指针。通过指针操作,可以在链表中进行节点的插入、删除和遍历。
-
内存管理:在C++中,需要手动分配和释放内存。创建新节点时使用
new
关键字分配内存,而释放节点内存时需要使用delete
关键字。这是因为C++不具备自动内存管理的能力,需要程序员手动管理。 -
异常处理:在C++中,需要显式处理一些异常情况,比如节点不存在或链表为空时的操作。在上面的代码示例中,当要删除的节点不存在时,会输出相应的错误信息
LinkedNode* newNode = new LinkedNode(val); |
LinkedNode* newNode
: 这是一个指针声明。newNode
是指向LinkedNode
类型的指针。new LinkedNode(val)
: 使用new
关键字在堆上动态分配一个新的LinkedNode
对象,并调用其构造函数,传入参数val
。=
: 将新创建的LinkedNode
对象的地址赋值给newNode
指针。
203.移除链表元素
题意:删除链表中等于给定值 val 的所有节点。
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;
}
};
707.设计链表
感觉还是开头,结尾,删除和插入的基本操作,但是自己构建链表不太会,还要定义private,自己释放空间。
当设计链表类时,通常将链表节点的定义设为私有(private
),这样外部代码就不能直接访问或修改链表节点,只能通过链表类提供的公共(public
)接口来操作链表。
class MyLinkedList{
public:
struct LinkedNode{
int val; // val:用于存储节点的值。
LinkedNode* next; // next:指向下一个节点的指针。
LinkedNode(int val):val(val),next(nullptr){} //通过参数初始化列表将传入的val赋值给成员变量val,并将next初始化为nullptr
};
MyLinkedList(){
_dummyHead=new LinkedNode(0); //new LinkedNode(0): 使用new关键字在堆上动态分配一个新的LinkedNode对象,并调用其构造函数,传入参数0
_size=0;
}
//获取第index节点数值
//如果index是非法数值,直接返回-1,注意index是从0开始的,第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!=nullptr){
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++;
}
//删除第index个节点,如果index大于等于链条的长度,直接return
void deleteAtIndex(int index){
if (index >= _size || index<0){
return;
}
LinkedNode* cur = _dummyHead;
while(index--){
cur=cur->next;
}
LinkedNode* tmp=cur->next; // tmp指针指向要删除的节点
cur->next=cur->next->next; // 删除操作:跳过tmp指向的节点,直接将cur的next指向tmp的next
delete tmp;// 释放tmp指向的节点的内存
tmp=nullptr;// 将tmp置为空,防止悬挂指针
_size--;
}
//打印链表
void printLinkedList(){
LinkedNode* cur=_dummyHead;
// 当cur指向的节点的下一个节点不为空时,执行循环
// 这里有一个小问题,如果链表为空(即_dummyHead->next为nullptr),则循环体内的代码不会执行
// 这意味着即使链表为空,函数也不会输出任何信息,这可能不是预期的行为
while (cur->next!=nullptr){
cout<<cur->next->val<<" "; //cout << ... << " ";: 使用cout输出流打印cur->next->val的值,并在其后添加一个空格。
cur=cur->next;
}
if (_dummyHead->next == nullptr) {
cout << "链表为空" << endl;
return;
}
cout<<endl;
}
private:
int _size;
LinkedNode* _dummyHead;
};
206.反转链表
只来得及双指针法,给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
我忘了最后返回链表!!! return pre
分析思路:
- 初始化:
temp
用于暂存cur
的下一个节点。cur
是当前节点,开始时指向头节点。pre
是cur
的前一个节点,开始时为NULL
。
- 迭代反转:
- 在每次循环中,首先保存
cur
的下一个节点到temp
。 - 然后将
cur
的next
指针指向pre
,实现反转。 - 接着更新
pre
和cur
的值,以便进入下一次循环。
- 在每次循环中,首先保存
- 断联和重连:
- 断联:当
cur->next
被指向pre
时,cur
原本指向的下一个节点实际上就被“断联”了,因为cur->next
不再指向它。 - 重连:
cur
和pre
的更新确保了链表的连续性。cur
变为temp
(即原本cur
的下一个节点),而pre
变为cur
(即新的反转后的当前节点)。
- 断联:当
- 结束条件:
- 当
cur
为NULL
时,表示已经遍历到链表的末尾,此时pre
就是反转后的新头节点。
- 当
为什么先断联再重连:
- 先断联:是为了改变当前节点
cur
的指向,使其不再指向原来的下一个节点,这是反转操作的关键一步。 - 再重连:是为了保持链表的连续性,确保
cur
的前一个节点pre
能够通过cur
访问到cur
的下一个节点(现在暂存在temp
中)。
例如,对于链表 A -> B -> C
,反转过程如下:
- 初始化:
cur = A
,pre = NULL
,temp
未使用。 - 第一次循环:
temp = B
,A->next = NULL
(断联A和B),pre = A
,cur = B
。此时链表变为B -> C
和孤立的A
。 - 第二次循环:
temp = C
,B->next = A
(断联B和C并重连B和A),pre = B
,cur = C
。此时链表变为C
和反转的部分A -> B
。 - 第三次循环:
temp = NULL
,C->next = B
(断联C的下一个节点并重连C和B),pre = C
,cur = NULL
。此时链表完全反转,为C -> B -> A
。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
//保存cur下一个节点
//当前节点是头节点
ListNode*temp;
ListNode* cur=head;
ListNode* pre=NULL;
while(cur){
temp=cur->next;
cur->next=pre;
pre =cur;
cur=temp;
}
return pre;
}
};