链表在C语言中的应用,C语言-链表及其相关应用

C语言系列

一.链表定义

1).引

1.什么是链表

2.为什么要引入链表

3.链表有什么用

4.单向表(带头)优点

2).链表涉及的基本概念

1.头指针

2.头节点;

3.链表存在:

4.链表空:

5.链表尾:

6.带头节点链表,无头节点链表

7.单链表, 双链表,循环链表

3).代码书写

一个普通链表代码

头插法

尾插法

二.链表的创建

头插法

尾插法

三.链表操作

1.创建

2.输入

3.输出

4.查找

5.修改

6.插入,删除

插入

删除

一.链表定义

1).引

1.什么是链表

一串 被 连在一起 的内存空间(链式内存)

2.为什么要引入链表

解决内存不够存放一串连续数据问题

Ps:一般来说,数组能解决大多数问题,但是数组要求开辟一块连续完整的内存空间,使其能够连续存放,对内存空间要求苛刻。若内存不够时,链表的作用便体现出来

链表能够充分利用零碎空间

3.链表有什么用

解决空间不足,但要连续储存问题

4.单向表(带头)优点

将表无数据的判断和表处理结束表尾的判断 形式上做了统一。

2).链表涉及的基本概念

1.头指针

指向(记录)链式存储中第1个节点位置(地址)的指针变量。简称为头指针;

2.头节点;

顾名思义,代表链式存储中一个特殊节点;领头的节点,领队节点;可以有,也可以没有。

3.链表存在:

有头节点的链表,链表存在表明至少头节点是存在的;没有头节点的,那p的内容应该存在且有意义;若P为NULL则表明不存在;

4.链表空:

是指链表数据部分不存在。有头节点的,链表为空,表明链表只有头节点;无头节点的,显然P为NULL;

5.链表尾:

指链表中最后一个节点,称为链表的尾节点。

6.带头节点链表,无头节点链表

有头指针和无头指针的区别

7.单链表, 双链表,循环链表

单链表:只有后继关系

双链表:有后继和前驱关系

循环链表:尾节点又指向的第一个节点

3).代码书写

既然要连起来,那必然有一个扣和一个环,且环和扣得在一起,类似于火车车厢

因此,这里的

int data;就是环

struct Link *next;就是扣

struct Link

{

int data;//记录数据

struct Link *next;//记录位置关系,利用递归的方式

};

66003a19f4d6a28f0bca6330b9b20b22.png

Q:怎么连起来?

A:用指针

Q:为什么用结构体?

A:结构体能整合不同的数据类型

Q:为什么要用struct Link定义指针

A:因为每一个节点必须是一样的,用struct Link来递归,指向下一个节点

Ps:个人见解,当程序执行到struct Link *next;这一行时,就已经开辟了一个和自己一样的节点。

这是一个套娃。

C语言支持指针的递归。

一个普通链表代码

头插法

#include

#include

#include

struct Link

{

int data;

struct Link *next;

};

int main()

{

int i,n;

struct Link *p,*q;

scanf("%d",&n);

p=(struct Link *)malloc(sizeof(struct Link));

p->next=NULL;

for(i=0;i

{

q=(struct Link *)malloc(sizeof(struct Link));

scanf("%d",&q->data);

//q->next=NULL;//因为是接到头节点后,所以空不空都行

q->next=p->next;//把环记下来(保留原有关系)

p->next=q;//指向下一个数据

}

q=p->next

while(q!=NULL)

{

printf("%d",q->data);

q=q->next;

}

return 0;

}

当一个数据输入时,指针q[0]的next=头指针的next,然后头指针的next指向了q[0]的数据

下一个数据输入时,指针q[1]的next=头指针的next,然后头指针的next指向了q[1]的数据。

Q:为什么是倒序的

A:因为头指针的next已经指向了q[0]的数据,当指针q[1]的next=头指针的next时,头指针的next已经记录了q[0]的数据,所以指针q[1]的next=头指针的next后,q[0]就接在了q[1]的后面

尾插法

#include

#include

#include

struct Link

{

int data;

struct Link * next;

};

int main()

{

int i,n;

struct Link *p,*q,*r;

scanf("%d",&n);

p=r=(struct Link *)malloc(sizeof(struct Link));

p->next=NULL;

for(i=0;i

{

q=(struct Link *)malloc(sizeof(struct Link));

scanf("%d",&q->data);

q->next=NULL;

r->next=q;//新建一个节点,充当胶水,先给要接入的环抹上。

r=r->next;//然后移动r到下一个节点,黏上

//这里的r,先让其next指向q的数据,然后挪动r,完成对接

}

q=p->next;

while(q!=NULL)

{

printf("%d",q->data);

q=q->next;

}

return 0;

}

Q:怎么理解

A:新建一个临时节点,当数组输入时,让r的next指向q,再让r移动到其next,也就指向了q,所以r的next也就是q的next。当输入下一个时,r->next=q这里的next是上一个q 的next

Q:头指针没用了吗?

A:相当于,另起一个串,这个串串好了,然后才连到头指针上

以下以单向有头链表举例

以动态链表为例

二.链表的创建

头插法

顾名思义,输入的数据是接在头指针的后面,每一个都找头指针对接(扣环)

解释,见上。

输入的数据是倒序的,见上。

尾插法

按节点顺序生成

新节点接在上一个节点的后面,而不是头指针的后面

相关解释,见上。

三.链表操作

1.创建

struct Link

{

int data;

struct Link * next;

};

2.输入

头插和尾插,见上

3.输出

q=p->next;

while(q!=NULL)

{

printf("%d",q->data);

q=q->next;

}

4.查找

目的是找到要求的数据

查找区间在[1,n]之间

找不到返回NULL,找到返回相应指针

struct Link * search(struct Link*p,int n)

{

int i;

struct Link *q;

while(i

{

i++;

q=q->next;

}

if(i!=n)

return NULL;

else

return q;

}

5.修改

给出要修改节点的位置,对应修改即可

这里为了防止手误修改,记录了修改前的内容

struct Link modify(struct Link*p,struct Link y)

{

int i;

struct Link t;

t=*q;

*q=y;

q->next=t->next;

return t;//返回的就是未修改前的内容

}

6.插入,删除

插入和删除,都需要找到要插入或者删除的前一个节点,修改前一个节点的next

插入的节点区间是[0,n+1]

删除的节点区间是[1,n]

插入

必须维护原有的关系,所以要记录原有的关系,再进行插入

因为要找到前一个节点的位置,所以区间是[0,n]

插入点的前驱节点不能为空

采用计数原理,找到要修改的位置

void insert(struct Link *p,struct Link *q,int i)

{

int j=0;

struct Link *r;

r=p;//新建一个链表,用链表找

while(j

{

j++;

r=r->next;

}

if(r!=NULL)//如果找到了

{

//先保留关系

q->next=r->next;//插入节点得和上一个节点的next相等

//在此,新节点的next就把后面的剩余节点保存下来了

//再赋值

r->next=q;//让上一个节点的next指向新节点的值

}

}

删除

同插入

要找到前一个节点的位置,所以区间是[0,n-1]

另外,待删除的节点也不能为空

同样,这里为了防止手误删除,记录了为删除的数据

void delete1(struct Link *p,int i)

{

int j=0;

struct Link *r,*q,t;

r=p;//新建一个链表,用链表找

while(jnext!=NULL)

{

j++;

r=r->next;

}

q=r->next;//找到待删除节点

if(q!=NULL)//如果待删除节点不为空

{

//先保留关系

t=*q;//保留历史记录

//只需将待删除节点的next与上一个节点的next对接上,待删除节点就会被跳过

//也就是完成了删除

r->next=q->next;//完成对接

//这里的q就是待删除节点,让r.next等于待删除节点q.next,就把该节点的数据跳过了

}

free(q);//清除q

return t;

}

写在最后,如果没看懂的,建议动手画一画就明白了~

点赞呀~

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值