初学C语言之如何建立一个链表?

链表是除数组外的另一种保存数据的方式,用到了结构、函数、指针等知识,叫链表纯粹是因为结构体变量通过指针连接起来形象的叫做链表。
在建立一个链表前,我们首先要建立一个结构体,包括数据域和指针域两个部分的结构体变量就是结点。如

typedef struct student {
int num;
char name[20];
struct student *next; //指针
};student

通过以上结构体我们建立一个结点:

student node1;

可以看到,所谓结点,其实就是结构体变量,以此类推我们可以建立n个节点并初始化:

student node1={1,NULL};
student node2={2,NULL};
student node3={3,NULL};

建立好了结点,接下来需要把结点连起来形成一个链表,使用指针指向地址的原理,第一个结点的next指针指向第二个结点的地址,以此类推。其中定义首地址head,尾地址指向空。如下

student *head;  //定义一个结构指针head
head=&node1;   //head指针指向node1的地址,表示链表头
node1.next->&node2; //node1的next指向node2地址
node2.next->&node3;//node2的next指向node3地址
node3.next->NULL;//node3指向空,表示链表结束

这样一个链表就定义完毕,接下来可以对链表的数据域进行操作。
上面定义的是静态链表,如果要定义动态链表就需要用到malloc来分配空间:

student * node1;//d定义一个结构指针作为结点
node1=(student *)malloc(sizeof(student));  //分配地址
/*也可以直接写成:
student * node1=(student *)malloc(sizeof(student)); 

动态链表各结点的链接与静态链表相同。
在建立一个链表时,需要定义多个结构指针,包括头指针head,不变,永远指向第一个结点,分配空间指针,用于创立新结点;以及辅助指针,用于链表信息的临时保存等,辅助链表延伸。
链表最后一个结点的next指针必须为空。
新建及添加链表步骤为:
1.定义三个结构指针,head,p,st
2.给st分配一个空间,建立第一个结点,并令head指向st
3.给第一个结点赋值,其中st->next=NULL
4.令p指向st,给st分配一个空间,p->next=st,
st->next=NULL
5.给新结点赋值
6.重复4,5直到循环结束

	printf("输入要添加几个人:");
	scanf("%d",&a);
	scanf("%d%s",&num,name);
	student *head,*st,*p;//工具人st、p指针,拓展结点用:p先指向st,st分配新结点,
	//然后p后移一位指向新st,主要是因为st->next需要为空,因此p指针过度
	st=(student *)malloc(sizeof(student)); //插入第一个结点
	p=head=st;
	st->num =num;
	strcpy(st->name,name);
	st->next =NULL;
	b=a-1;
	while(b--)  //添加新结点
	{
		scanf("%d%s",&num,name);
		st=	add(head,st);
		st->num =num;
		strcpy(st->name,name);
	}
	st->next =NULL;
	for(st=head;st!=NULL;st=st->next )  //遍历
	{
		printf("%d %s\n",st->num ,st->name );
	}



删除链表结点
基本思路,先输入一个数,然后遍历链表,寻找与输入的数相等的结点,然后先将此节点的前后结点连接,再释放该节点空间。
可以知道,删除一个结点最多需要用到三个结点,因此需要引入两个结构指针赋值,起名为p_front,和p_behand。
其中我们要删除的结点是p_behand,该节点的前一个结点是p_front,该节点后一个结点的地址是p_behand->next。p_front用来保存删除结点前一个结点信息,因此若满足,p_front不动,不满足条件p_front后移;p_behand始终要保证p_behand是p_front的下一个结点
而前、后两个辅助指针通过head头结点来完成初定义:
p_front=head;
p_behand=head->next;
这样就定义好了辅助指针。
**还需要注意一个点,**如果我们要删除的恰好是头结点,那么我们需要这样操作:
p_behand=head; //把头结点的地址赋给辅助结点
head=head->next; //原头结点的下一个结点地址作为新头结点地址
free(p_behand); //删除原头结点
下面是代码:

scanf("%d",&c);
/*删除结点为头结点*/
while(head!=NULL&&head->num ==c)
{
	p_behand=head;
	head=head->next ;
	free(p_behand);
}
/* 删除结点不为头结点*/
p_front=head;             
p_behand=head->next ;
while(p_behand!=NULL)    
{	
	if(c==p_behand->num )  //满足条件
	{
		p_front->next =p_behand->next;//连接结点
		free(p_behand);  //释放空间
	}
	else   //不满足条件	
		p_front=p_behand;  //辅助结点front后移
	p_behand=p_front->next ;
	
}

链表信息的修改
修改就很简单了,只需要先从头遍历链表,然后用条件语句找到要修改的值,直接修改即可:

printf("输入要修改的人的学号");
scanf("%d",&d);
for(st=head;st!=NULL;st=st->next )
{
  if(st->num ==d)
  {
   printf("输入要修改姓名:");
   scanf("%s",s);
   strcpy(st->name ,s);  //修改姓名
  
  }
}

查看链表
若要显示所有信息,只需从头遍历。若要设置条件显示,如显示学号1的人信息,同样先遍历,再用条件语句控制输出即可:

printf("输入要显示的学号");
scanf("%d",&a);
for(st=head;st!=NULL;st=st->next )
{
	if(st->num ==a)
printf("%d %s\n\n",st->num ,st->name );
}

现在链表的建立、遍历以及用链表实现增删查改的功能就介绍完毕,其中修改和查看较为简单,不需引入辅助指针;添加需引入两个辅助指针,删除需引入两个辅助指针。需要多思考,理解链表的原理就是用指针和malloc、free函数对数据的存储空间进行操作。除了head头结点特殊不可随意改动外,其他的指针都可以叫做辅助指针。辅助指针可以形象比喻成织布的“针”,织布的时候需要针,布织好了,针也就可以拿走了。也可以叫工具人。
其实计算机内部处理数据,并没有结构、数组等概念,这些概念是我们人为规定的。而计算机中只有地址和地址中的数据的概念。很多初学c语言的人觉得链表难,其实很大原因就是不理解计算机中的数据是如何存储的。因此想学好链表,学好c语言,最好了解计算机的工作原理也就是微机原理,80X86型号就足矣。
最后再附上一段最基本的链表代码,其实大部分上面已经写了,这里给出一个能完成运行的代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct student{
	int num;
	char name[20];
	struct student *next;
}student;
void main()
{
	int a,b,c,d,i;
	int num;
	char name[20];
	char s[20];
	printf("输入要加入的人数:");
	scanf("%d",&a);
	scanf("%d%s",&num,name);
	student *head;
	student *st,*p;//工具人st、p指针,拓展结点用:p先指向st,st分配新结点,
              	//然后p后移一位指向新st,主要是因为st->next需要为空,因此p指针过度
	
	/*建立链表*/
	st=(student *)malloc(sizeof(student));
	p=head=st;
	st->num =num;
	strcpy(st->name,name);
	st->next =NULL;
	
	
	/*增加*/
	b=a-1;
	while(b--)
	{
		scanf("%d%s",&num,name);
		st=(student *)malloc(sizeof(student));//新建结点
		st->num =num;
		strcpy(st->name,name);
		p->next =st;
		st->next=NULL ;
		p=st;
		
	}
	
	/*删除*/
	printf("输入要删除的学号:");
	scanf("%d",&c);
	while(head!=NULL&&head->num ==c)//删除结点为头结点
	{
		p=head;
		head=head->next ;
		free(p);
	}
    p=head;              //删除结点不为头结点
	st=head->next ;
	while(st!=NULL)    
	{	
		if(c==st->num )
		{
			p->next =st->next;
			free(st);		
		}
		else
			p=st;
		st=p->next ;	
		
	}
	
	/*修改*/
	printf("输入要修改的人的学号");
	scanf("%d",&d);
	for(st=head;st!=NULL;st=st->next )
	{
		if(st->num ==d)
		{
			printf("输入要修改姓名:");
			scanf("%s",s);
			strcpy(st->name ,s);
			
		}
	}
	/*显示*/
	printf("输入要显示的学号");
	scanf("%d",&a);
	for(st=head;st!=NULL;st=st->next )
	{
		if(st->num ==a)
			printf("%d %s\n\n",st->num ,st->name );
	}
	
	/*遍历*/
	for(st=head;st!=NULL;st=st->next )
	{
		printf("%d %s\n",st->num ,st->name );
	}
}

这里代码并没有写成函数形式,如果写成函数,要返回head指针。

  • 11
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值