C语言单向链表:获取&&删除&&插入#ShadowFox个人作品
2017-12-31 23:41
429 查看
单向链表的获取元素,删除元素,插入元素看似很难,但是当抓住要点后,一切问题都迎刃而解。我来发表一下我学习链表时的一些思路与见解,仅供学习交流之用,因水平问题,如有错误短视之处,恳请谅解。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------拿昨天的代码举例,链表节点定义为
struct note{
char name[20];
int heartlevel;
struct note *next;
};
1.链表的获取
形参为:
@struct note *head 头节点
@int n 需要获取的元素的位置
返回值为:
@无
功能为:
@如果第n个元素存在,则返回第n个元素的内容,否则输出There are no data.
定义函数
void get(struct note *head,int n){
......
}
定义
操作指针struct note *p=head;
是否读取成功的标志flag=0;
计数器step=0;
我们的目的是让p指向第n个节点,这里我们用一个while循环
while(step<n){
step++;
p=p->next;
if(p==NULL){
flag=1;
printf("There are no data.\n");
break;
}
}
当n在链表内时
当step=n-1时,会执行
step++;
p=p->next;
然后step=n,while循环终止,p即指向了节点n.
----------------------------------------->>>示意图<<<-----------------------------------------
如果n超出了链表长度,即n位置处无数据,我们可以这么考虑
首先,p与step是严格一致的,p指向哪个节点的头指针,step就记录这个节点的位置。假如我们要获取最后一个节点的数据,假设 最后一个节点位置是m,当step=m-1时执行
step++;
p=p->next;
p指向了最有一个节点的位置,step等于m,跳出循环。
以此看来,如果n<=m,那么p就不可能是NULL。一旦p=NULL,那么即可判断输入超出,记flag标志位位1。
当flag不为1时,可以进行读取数据的操作。
printf("n=%d,creature=%s,hrearlevel=%d\n",n,p->name,p->heartlevel);
当flag为1时,数据不存在。
附上本函数全部代码
void get(struct note *head,int n){//输入一个n,返回其对应的元素,如果没有,则输出There
are no creatures.
struct note *p=head;
int flag=0;
int step=1;
while(step<n){
step++;
p=p->next;
if(p==NULL){
flag=1;
printf("There are no data.\n");
break;
}
}
if(flag==0){
printf("n=%d,creature=%s,hrearlevel=%d\n",n,p->name,p->heartlevel);
}
}
2.链表的删除
形参为:
@struct note *head 头节点
@int n 需要删除的元素的位置
返回值为:
@修改过后的链表头指针
功能为:
@如果第n个元素存在,则删除第n个节点,否则输出There are no data.
我们需要从何下手?我建议应该把问题分割成如下部分:
首先定义
struct note *p=head;
struct note *q;
int step=1;
int flag=0;
从链表数据方面考虑,如果链表是空表,即head==NULL,则直接输出数据不存在:
if(head==NULL){
printf("There are no data.\n");
}
从删除节点位置方面考虑
@如果要删除表头,即n==1,那么把第一个节点释放,然后接上第二个节点:
if(n==1){
struct note *q=head;
head=head->next;
free(q);
printf("delete OK\n");
}
@如果删除表中或者表尾,最关键的一步是把p移动到n-1节点的位置。
这里有一个思维难点,我们继续把这个难点拆分:
==step1:先不考虑n是否超出链表长度,我们先假设n是符合要求的,那么将p移动到n-1节点的操作是:
while(step<n-1){
p=p->next;
step++;
}
==step2:如果p->next是空,那么下一轮循环中p->next肯定会出错,因为NULL->next是错误的,所以我们要加上“如p->next==NULL,则循环终止”。
while(p->next&&step<n-1){
p=p->next;
step++;
}
==step3:我们假设,输入的n超过了链表最大长度m,那么在step超出n前,会发生什么呢?
假设,n=m+1,这是一种临界情况;
当step==m时,p->next==NULL,上面的循环停止,step永远定格在m上,若n=m+1或者比m+1还大,则以下式子恒成立
p->next&&step<=n-1为真
于是判断n是否在链表内的语句可以写成:
if((p->next==NULL)&&step<=n-1){
flag=1;
printf("There are no data.\n");
}
flag=1标明n超过链表长度;
flag=0标明n没有超过链表长度;
----------------------------->>>下面的操作是删除中间或尾节点的过程<<<------------------------------
q=p->next;
p指向的是节点n-1的位置,q指向节点n的位置。
==若q->next!=NULL(这意味着q不是尾节点)
先把p->next跳过q指向的节点,直接指向下一个节点。然后free(q),即释放q所占的空间。
p->next=NULL;
free(q);
printf("delete OK\n");
==若q==NULL(q是尾节点)
那么q->next就根本不存在,直接将p->next赋予NULL即可。
p->next=NULL;
free(q);
完整函数代码如下:
struct note *delete(struct note *head,int n){
struct note *p=head;
struct note *q;
int step=1;
int flag=0;
if(head==NULL){
printf("There are no data.\n");
}else{
if(n==1){
struct note *q=head;
head=head->next;
free(q);
printf("delete OK\n");
}else{
while(p->next&&step<n-1){
p=p->next;
step++;
}
if((p->next==NULL)&&step<=n-1){
flag=1;
printf("There are no data.\n");
}
if(flag==0){
q=p->next;
if(q->next==NULL){
p->next=NULL;
free(q);
printf("delete OK\n");
}else{
p->next=q->next;
free(q);
printf("delete OK\n");
}
}
}
}
return head;
}
3.链表的添加(这里实现的是向前添加)
形参为:
@struct note *head 头节点
@int n 在n位置前添加一个节点
返回值为:
@修改过的链表头指针
功能为:
@如果第n个元素存在,则添加一个节点,否则输出There are no data.
这里我们核心思想还是先让p指向n-1的位置,但同时也要考虑n超出链表位置,空数据等情况。解决方法与链表节点的删除类似,这里不再累述;
定义:
struct note *inster(struct note *head,int n){
struct note *p,*q,*temp;
处理空数据:
if(head==NULL){
printf("There are no data.\n");
把p指向n-1的位置(先不考虑在头节点前添加的情况):
int step=1;
int flag=0;
p=head;
while(p->next&&step<n-1){
p=p->next;
step++;
}
if(p->next==NULL&&step<=n-1){
flag=1;
printf("There are no data.\n");
}
我们可以注意到这些代码与删除链表节点的操作极其类似;
----------------------------------->>>然后我们就可以开始处理了<<<--------------------------------
我们先用malloc函数申请一个节点,并把这个节点的头指针赋值给temp:
temp=(struct note*)malloc(sizeof(struct note));
==如果n==1(即我们要在头节点前再添加一个节点)
我们应该把temp设置为新的头节点,temp->next指向原来的头节点,然后将数据输入到这个新的节点内即可:
temp=(struct note*)malloc(sizeof(struct note));
head=temp;
temp->next=p;
setbuf(stdin, NULL);
scanf("%s %d",temp->name,&temp->heartlevel);
如果n!=1
我们定义q=p->next。p指向的是n-1的位置,q指向的即为n的位置。我们现申请一个新的节点,并把这个节点的头指针赋值给temp。然后p->next=temp,temp->next=q。
代码如下:
temp=(struct note*)malloc(sizeof(struct note));
head=temp;
temp->next=p;
setbuf(stdin, NULL);
scanf("%s %d",temp->name,&temp->heartlevel);
附上整个函数的代码:
struct note *inster(struct note *head,int n){
struct note *p,*q,*temp;
if(head==NULL){
printf("There are no data.\n");
}else{
int step=1;
int flag=0;
p=head;
while(p->next&&step<n-1){
p=p->next;
step++;
}
if(p->next==NULL&&step<=n-1){
flag=1;
printf("There are no data.\n");
}
if(flag==0){
if(n!=1){
temp=(struct note*)malloc(sizeof(struct note));
q=p->next;
p->next=temp;
temp->next=q;
setbuf(stdin, NULL);
scanf("%s %d",temp->name,&temp->heartlevel);
}else{
temp=(struct note*)malloc(sizeof(struct note));
head=temp;
temp->next=p;
setbuf(stdin, NULL);
scanf("%s %d",temp->name,&temp->heartlevel);
}
}
}
return head;
}
ps:我开始学链表的时候发现在插入元素时scanf一直会被跳过执行,我猜是键盘缓存区的问题,于是加了个linux下的清楚键盘缓冲区代码「setbuf(stdio,NULL);」,问题果然解决。windows系统下可以使用
fflush(stdin); 或rewind(stdin);
清空输入缓存区。
-----------------------------------------------------------------------------------------------
我的见解很浅显,以上教程仅供参考。如果您发现任何错误或者有什么更好想法,欢迎与我联系。
GJK
相关文章推荐
- C语言单向链表:创建&&打印#ShadowFox个人作品
- (C语言版)链表(一)——实现单向链表创建、插入、删除等简单操作(包含个人理解说明及注释,新手跟着写代码)
- [转]C语言之单向链表的创建插入删除等功能
- C语言单向动态链表程序,实现链表的建立,合并,重新排序,链表元素的插入与删除,以及根据元素成员的值进行元素删除。
- (C语言版)链表(一)——实现单向链表创建、插入、删除等简单操作(包含个人理解说明及注释,新手跟着写代码)
- C语言单向链表的创建、释放、插入、删除、翻转操作练习
- (C语言版)链表(一)——实现单向链表创建、插入、删除等简单操作(包含个人理解说明及注释,新手跟着写代码)
- C语言实现链表之单向链表(十一)设置结点数据与获取结点数据
- C语言中单向非循环链表的生成,遍历,排序,插入和删除
- 单向链表之有序插入节点(C语言实现)
- 链表(三)——链表删除冗余结点&插入结点到有序链表
- 数据结构作业代码保存-2.1 单向循环链表的建立,插入和删除,和指针移动
- C语言实现链表插入,删除相关操作
- 数据结构----单向链表之 新建-插入-删除-排序(选择法)-合并-删除-销毁
- 单向链表的删除及插入操作(以头插入法建立单向链表)
- 链表操作 对链表进行输入,插入,删除结点,按关键字进行查找操作 C语言
- 单向链表的相关操作(创建,遍历,插入,删除,逆置)
- c语言链表的创建、插入、删除、排序
- 单向链表操作:新建,输出,删除,插入
- 数据结构Java实现03----单向链表的插入和删除