目录
一:基础知识(我感觉链表在形式表达上和指针相同,在内容表达上与数组相同)
记于2023-1-16
一:基础知识(我感觉链表在形式表达上和指针相同,在内容表达上与数组相同)
1.数据域 指针域(链接内存中的各个结点)
2.单链表 双链表 循环链表
3.与数组的存储方式不同,数组的内存空间是连续的分布,而链表的空间是由系统随机分布,除起始和终止节点是确定了。
数组的空间确定(数据量确定,若不确定就会重新定义新的数组)所以多查找 少增删 ,而链表的内存空间不是很确定(数据量不是固定的),所以多增删,少查询。
4.链表节点的定义
//单链表的定义
struct ListNode{
int val;//节点上存储的元素
ListNode *next;//指向下一个节点的指针
ListNode(int x):val(x),next(NULL){} //节点的构造函数
};
//通过自己定义构造函数的初始化节点
ListNode* head=new ListNode(5)
//默认构造函数初始化节点
ListNode* head = new ListNode();
head->val = 5;//指针的表示
5.链表节点的删除和增添 删除节点在c/c++中要手动释放删除的内存空间,其他语言不用手动管理内存
1.删除节点:头节点:head=head->nest;
非头节点:cur->next=cur->next->next;
以上两种方式要学会判断并 使用if循环,或者直接使用虚拟节点,统一为有头节点的方式
删除的节点前后都不能为NULL(注意操作的节点不能为空指针)
2.插入节点 找到第n个节点设置为cur->next,注意新节点的设置顺序,先新节点->第n个节点,再使第n个节点的前一个节点为->新节点
代码见下
二:操控节点的几种方式
删除节点的两种方式
(1)直接使用原来的代码进行操作
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
while(head!=NULL && head->val)//删除头节点
ListNode* temp=head; //定义新的链表指针指向头节点
head=head->next;//当满足此条件时,head移动到下一个
delete temp;//删除头节点
}
//删除非头节点
ListNode* cur=head;
while(cur!=NULL&&cur->next!=NULL)
{
if(cur->next->val==val)
{
ListNode* temp=cur->next;
cur->next=cur->next->next;
delete temp;
}
else cur=cur->next;
//为下一次判断cur做准备,因为这里进行while循环,所以会遍历到最后一个节点
}
return head;//这里可以发现返回的是头节点 与数组的地址相似,head的值一直都没有改变
}
};
(2).设置一个虚拟头节点进行操作
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead = new ListNode(0);//设置一个虚拟节点
dummyHead->next = head;//将虚拟头指向head,这样方便删除操作
//注意这个是为什么要这样,若是换成head->next,就会导致最后不能正确的返回头节点
ListNode* cur = dummyHead;
while(cur->next!=NULL){
if(cur->next->val == val){
ListNode* temp=cur->next;
cur->next=cur->next->next;
delete temp;
}else {
cur=cur->next;
//进行这样的操作是为了方便下一次的遍历循环
}
}
head=dummyHead->next;//这里需要注意重新定义head,前面的
delete dummyHead;
return head;
}
};//还是要对虚拟节点进行理解为什么前面设置了dummyHead=head后,后面又要重新将head赋值
获取链表中第 index 个节点的值。如果索引无效,则返回-1。//获取该节点的方式很特殊
cur=dummyHead->next;//参照上面设置新节点的方式
while(n)
{
cur=cur->next;
n--;
//此时节点的值应该是从n=0开始计算,应为此时n>=0&&n<=size-1;
//n最后为0,就是当前节点,停止循环
}
return cur->val;
在头部插入一个节点、
ListNode* newNode = new ListNode(val);
newNode->next = dummyHead->next;
dummyHead->next = newNode;/
/注意这两个式子的顺序,由于是头部插入节点所以
//要先将新链表指向head,再让dummyHead指向newNode
size++;
在尾部插入节点
LinkedNode* newNode = new LinkedNode(val);
//定义一个新节点
cur = dummyHead;
while(cur->next!=NULL)
{
cur=cur->next;//b站的视频上的cur箭头不是表示链表指向
cur->next=newNode;
}
第n个节点之前插入一个节点
cur要指向第n个节点之前的一个节点,在cur和cur->next(第n个节点)之间插入一个节点,所以寻找方法是和获取第n个节点的方式相同。
LinkedNode* newNode = new LinkedNode(val);
cur=dummyHead;
while(n){//保证第n个节点为cur->next
cur=cur->next;//找到两个节点 cur 和cur->next
n--;
newNode->next=cur->next;
cur->next=newNode;
size++;
}
删除第n个节点(找到的第n个节点一定是cur->next)
cur=dummyHead;
//找到前一个节点 cur cur->next(第n个节点)
while(n)
{cur=cur->next;
n--;
}
cur-next=cur->next->next;//与删除节点方式相同
//适当语言delete
size--;