概述: 单链表由一个个节点组成,每一个节点包括一个数据和下一个节点的地址。这意味着链表不需要一整块储存空间。但当我们需要对单链表进行操作时,我们的流程是:找到头节点->通过头节点存储的地址找到第一个节点->判断->通过改节点存储的地址找到下一个节点........->达成目的操作结束。所以当我们对单链表进行初始化时只需要创立一个头节点并记录头节点的位置,而增加和删除元素时便只需要找到需要操作的位置并依据需要改变前后节点记录的位置即可。
链表的创建和初始化:
#include<iostream>
#include<cstdlib>
using namespace std;
//规定一个节点类型,节点包含数据和下个节点的地址。
typdefe struct LNode{
int data;//数据
int len;//在头节点中记录链表的长度,主要目的是防止进行错误的访问,可以没有这个变量
struct LNode* next;//下一个数据的地址
}LNode,*PLink;//方便起见给结构体指针起了一个叫PLink的别名
void InitList(PLink &l)
{
l= new LNode;//申请一片空间,并让pl指向这片空间(创立头节点)
l->next=nullptr;//让头节点的下一个地址不存在(防止奇奇怪怪的错误)
l->len=0;
}
插入:我们需要创建一个新的节点,并让插入位置前一个节点记录新节点的位置,新节点记录后一个节点的位置。
void add(LNode* p,int sit,int target)//sit从1开始
{
if(sit<1 || sit>l.len+1)//防止乱七八糟的错误产生
{
cout<<"非法插入";
exit(0);
}
p->len=p->len+1;//头节点记录的长度加一,因为接下来头节点会丢失(没有记录)所以在这里操作
for(int i=0;i+1<sit;i++)//在查找位置为sit的节点
{
//-> 用于结构体指针访问结构体里存在的数据
p=p->next;
//通常的解释是让p指向下一个节点
//但我的理解是将p中存储的地址对应的结构体存储的地址赋予给p
}
//此时我们需要在p指针指向的节点后插入新节点
LNode* s;//初始化一个新的节点用于存储数据
InitList(s);
s->data=target;//将数据存入节点
cout<<"插入的数据:"<<s->data<<endl;
s->next=p->next;//将下一个节点的位置存入s
p->next=s;//将这个节点的位置信息存入p
}
删除: 我们需要将被删除节点(记为D)的前一个节点记录的地址更改为D后面的节点的地址
void DeletElem(LNode &l,int sit)
{
if(sit<1 || sit>l.len)
{
cout<<"非法删除";
exit(0);
}
LNode* p=&l;
for(int i=0;i+1<sit;i++)
{
p=p->next;
}
//此时p指向的节点的下一个节点是需要删除的节点
LNode* p2=p;
l.len--;//表长减一
p2=p2->next;//将下一个节点(需要删除)的地址赋值给p2
p->next=p2->next;//将p这个节点记录的地址更新,此步将需要删除的节点移出链表
delete p2;//将节点删除
}
全部代码:
#include<iostream>
using namespace std;
//一个节点,包含数据和下个节点的地址
typedef struct LNode{
int data;//数据
int len;
struct LNode* next;//下一个数据的地址
}LNode,*PLink;
void InitList(PLink &pl)
{
pl= new LNode;//申请一片空间,并让l指向这片空间(创立头节点)
pl->next=nullptr;//头节点的下一个地址不存在
pl->len=0;
}
void add(LNode* p,int sit,int target)//sit从1开始
{
p->len=p->len+1;
for(int i=0;i+1<sit;i++)
{
p=p->next;
}
PLink s;
InitList(s);
s->data=target;
cout<<"插入的数据:"<<s->data<<endl;
s->next=p->next;
p->next=s;
}
void DeletElem(LNode &l,int sit)
{
if(sit<1 || sit>l.len)
{
cout<<"非法删除";
exit(0);
}
LNode* p=&l;
for(int i=0;i+1<sit;i++)
{
p=p->next;
}
LNode* p2=p;
p2=p2->next;
p->next=p2->next;
l.len--;
delete p2;
}
void print(LNode* pl)
{
while(pl->next!=nullptr)
{
pl=pl->next;
cout<<pl->data<<" ";
}
cout<<endl;
}
int main()
{
LNode* l;
InitList(l);
for(int i=1;i<10;i++)
{
add(l,i,i);
}
cout<<"链表的长度"<<l->len<<endl;
cout<<"打印链表:";
print(l);
return 0;
}
注意:指针本身就是一个存储地址的变量,但是当指针存储的地址是一个结构体时似乎就不那么有趣了,这时指针可以访问结构体里的数据并对其进行修改。