链表是用一个申请一个 不用了就销毁 而数组是把可能用到的都一次性申请来 而且链表不像数组那样占用的是相连的内存 链表内存可以不相连 链表为了方便操作有很多种形式 可以和很多种结构结合使用
结点的构造如上:
可以理解为一串链子链子之间通过指针链接 单链表可以通过前一个结点内的指针找到下一个结点 也就是说单链表如果某一个结点的指针改变 那他后面的链表也将丢失找不到;
单链表:
单链表就是每一个结点有两大部分组成 一个存数据 一个用来存指针 存的是指向它下一个结点的指针;
struct node
{
int a;
struct node *next;
} ;
这是结点的结构体组成 int a;可以替换成其他东西或多个变量
链表要有一个头指针指向的是第一个结点或者是一个空结点 方便对链表进行操作;
在单链表的结尾结点的指针 应指向空NILL;
单链表的创建 删除与插入
单链表的创建有两种方式 一个是将新建的结点放在链表末尾
Head指向头结点 定义一个指针p让它一直指向链表最后一个结点 这时创建一个新结点q
让q接在p后面
代码如下:
int main()
{
int n,i;
struct node *head=(struct node*)malloc(sizeof(struct node)); //为头结点申请内存空间
struct node *p=head; //头结点给地址p
p->next=NULL;
scanf("%d",&n); //输入链表长度
scanf("%d",&p->a); //输入第一个元素
for(i=1;i<n;i++)
{
struct node *q=(struct node*)malloc(sizeof(struct node)); //创建新的结点
scanf("%d",&q->a);
p->next=q; //接在链表后面
p=q; //把p往后挪一位
}p->next=NULL; //最后面那个指针指向NULL
}
还有一种创建方法是将新来的结点都放在头指针的后面 p不断移到第二个结点上让q的指针指向p head指向一个空结点
如下图
代码如下
int main()
{
int n,i;
struct node *p=(struct node*)malloc(sizeof(struct node)); //为p申请内存空间
struct node *head=(struct node*)malloc(sizeof(struct node)); //为头结点申请内存空间
head->next=p; //头结点的指针指向新来的结点
p->next=NULL;//最后一个结点指针为空
scanf("%d",&n);
scanf("%d",&p->a);
for(i=1;i<n;i++)
{
struct node *q=(struct node*)malloc(sizeof(struct node)); //为新来的申请内存空间
scanf("%d",&q->a);
q->next=p; // 新来的结点指向p
head->next=q; //头结点的指针指向新来的结点
p=q; // p的地址变成q的地址
}
}
这两种创建方式一个是正序的一个是倒序的
单链表的删除:
先用p->next 遍历找到 要删除的结点的 前一个结点 q 定义成要删除的结点 链表在删除时不能直接 free(q); 因为如果这样便将p1弄丢(指向p1的指针也会一起销毁) 则删除q之前要将p->next指向p1 然后再free(q)
删除结点时结点可能是头结点 尾结点 中间结点 但只要定义一个指向头结点的指针就可以不用考虑这个结点是什么结点 。
代码如下:
int main()
{
int n,i,m;
struct node *head=(struct node*)malloc(sizeof(struct node)); //为头结点申请内存空间
struct node *head1=(struct node*)malloc(sizeof(struct node)); //这样方便删除首元素 这是一个指向首节点的结点
struct node *p=head; //头结点给地址p
struct node *q=head;
///////////输入创建链表 略。。。。。。。
head1->next=head; //指向首结点
p=head1; //让p的*next指向首结点
scanf("%d",&m); //输入要删除的结点的值
for(;p->next!=NULL;) //当p的下一个结点为空时结束
{
q=p->next; //让q作为那个可能被删除的结点
if(q->a==m) //当q的值与要求被删除结点值相等时
{
p->next=q->next; //将p的指针指向q的下一个结点 这样防止链表断开
free(q); //销毁
}
else
{
p=p->next; //如果链表删除了一个结点时指针p是不能向后移动的 那样子会出现跳跃结点的现象
}
}
head=head1->next; //找到头结点
p=head; //方便用指针p遍历链表
}
链表的插入:
如上图链表在插入时先将要插入的结点指针指向p结点的下一个结点 将p结点指针指向q
插入时分为 插入头结点尾结点和中间结点 但代码实现基本相同 具体代码操作如下:
int main()
{
int n,i,m;
struct node *head=(struct node*)malloc(sizeof(struct node)); //为头结点申请内存空间
struct node *head1=(struct node*)malloc(sizeof(struct node));
struct node *p=head; //头结点给地址p
struct node *q1=(struct node*)malloc(sizeof(struct node));
scanf("%d",&n); //输入链表长度
//此处 创建链表略.................
head1->next=head;
p=head1; //让p的*next指向首结点
scanf("%d",&m); //输入要在第几个结点后插入元素
for(i=0;i<m;i++)
{
p=p->next; // 找到那个结点
}
scanf("%d",&q1->a);
q1->next=p->next; //将要插入的结点的next存 p后面那个结点的地址
p->next=q1; p的next存q1的地址 这样就实现了插入
p=head;
}