链表的基本操作

单链表的创建

结点创建:我们假设要创建的链表的数据域用来存储学生信息,即姓名,学号和成绩:

typedef struct student
{
	char name[20];
	int num,score;
	struct student *next;    //指向下一个结点的指针
}stu;
接下来先用尾插法(即新增结点在尾部插入)创建链表:
#include <stdio.h> #include <stdlib.h> typedef struct student { char name[20]; int num,score; struct student *next; }stu; stu *creat(int n)    //n作为被传递的参数代表要创建的链表的结点个数,函数返回值类型是结点指针类型 { stu *head,*p,*q;    //p,q为两个临时指针 int i; if(n>0) { head=(stu *)malloc(sizeof(stu));    //为head分配动态内存空间 printf("请输入姓名,学号,分数:"); scanf("%s %d %d",head->name,&head->num,&head->score); p=head;    //让p和head指向相同 for(i=1;i<n;i++) { q=(stu *)malloc(sizeof(stu));    //再建一个结点,用q指向它 printf("请输入姓名,学号,分数:"); scanf("%s %d %d",q->name,&q->num,&q->score); p->next=q;    //p的指针域存q p=q; } p->next=NULL;    //循环外让p的指针域为空,因为这是最后一个结点
} else head=NULL; return head;    //返回头指针 } int main() { int n; printf("输入链表结点的个数:"); scanf("%d",&n); stu *head; head=creat(n);    //head接受函数返回值,保存链表起始的地址 if(n) { printf("姓名\t学号\t分数\n"); printf("-------------------\n"); for(int i=0;i<n;i++) { printf("%s\t%d\t%d\n",head->name,head->num,head->score); head=head->next; } } else printf("这是一个空链表!");    //n为0时链表没有结点 }

自己写的代码可能有许多不足之处,不过意思应该差不多了

下面看一下头插法(即新增结点总是插入头部):
#include <stdio.h>
#include <stdlib.h>
typedef struct student
{
	char name[20];
	int num,score;
	struct student *next;
}stu;
stu *creat(int n)
{
	stu *head,*p;    //p为临时指针
	int i;
	if(n>0)
	{
		head=(stu *)malloc(sizeof(stu));    //为head分配动态内存空间
		printf("请输入姓名,学号,分数:");
		scanf("%s %d %d",head->name,&head->num,&head->score);
		head->next=NULL;    //让head的指针域为空
		for(i=1;i<n;i++)
		{
			p=(stu *)malloc(sizeof(stu));    //为p分配动态内存空间
			printf("请输入姓名,学号,分数:");
			scanf("%s %d %d",p->name,&p->num,&p->score);
			p->next=head;    //让p指向head
			head=p;    //将head移动到p的指向上
		}
	}
	else
		head=NULL;
	return head;
}
int main()
{
	int n;
	printf("输入链表结点的个数:");
	scanf("%d",&n);
	stu *head;
	head=creat(n);
	if(n)
	{
		printf("姓名\t学号\t分数\n");
		printf("-------------------\n");
		for(int i=0;i<n;i++)
		{
			printf("%s\t%d\t%d\n",head->name,head->num,head->score);
			head=head->next;
		}
	}
	else
		printf("这是一个空链表!");
}
这两种方式创建的链表结点会刚好是反向的:
例如,如果运行上面两段程序,结果如下:

输入链表节点的个数:3
请输入姓名,学号,分数:张三 11 78
请输入姓名,学号,分数:李四 12 85
请输入姓名,学号,分数:王五 13 92
第一段:
姓名    学号    分数
-------------------
张三    11      78
李四    12      85
王五    13      92
第二段:
姓名    学号    分数
-------------------
王五    13      92
李四    12      85
张三    11      78

单链表的遍历

其实在上面两段代码的主函数中已经有这种思想了,只是并没有作介绍,我们把这种思想提出来单独看一下,以和上面结构一样的链表为例,写一个遍历数据并输出的子函数:

void Print(stu *h)	//h做函数参数,这里将要接收的是指向链表首结点的指针 
{
	stu *t=h;	//让临时指针得到首结点地址
	int i=1;
	while(t!=NULL)
	{
		printf("第%d个学生信息:\n",i);
		printf("姓名\t学号\t分数\n");
		printf("-------------------\n");
		printf("%s\t%d\t%d\n\n",t->name,t->num,t->score); 
		t=t->next;	//让临时指针移动到下一个结点
		i++;
	}
}
单链表的插入

链表插入的主要思想就是先找到插入位置,然后让新增结点的指针域指向插入位置的下一个结点(暂时叫a),然后让原来a前面的结点的指针域指向待插入结点就完成了,看代码,依旧用上面创建的链表:
第一种情况,在链表首部插入新结点:
stu *Insert1(stu *h,int *pn)
/*h做函数参数,这里将要接收的是指向链表首结点的指针,pn是指向n的指针,下面要用到它改变n的值以统计新链表结点个数*/
{
	stu *pnew;	//要插入的新结点
	pnew=(stu *)malloc(sizeof(stu));
	printf("请输入姓名,学号,分数:");
	scanf("%s %d %d",pnew->name,&pnew->num,&pnew->score);
	pnew->next=h;	//新结点指向原链表的首结点 
	h=pnew;	//头指针指向新结点 
	*pn++;	//新链表结点个数增加 
	return h;	//返回新的头指针 
}
第二种,在尾部插入:
stu *Insert2(stu *h,int *pn)
/*h做函数参数,这里将要接收的是指向链表首结点的指针
pn是指向n的指针,下面要用到它改变n的值以统计新链表结点个数*/
{
	stu *pnew;	//要插入的新结点
	stu *p=h;	//临时指针
	while(p && p->next!=NULL)
		p=p->next;	//让p指在原链表的尾结点上 
	pnew=(stu *)malloc(sizeof(stu));
	printf("请输入姓名,学号,分数:");
	scanf("%s %d %d",pnew->name,&pnew->num,&pnew->score);
	p->next=pnew;	//原链表的尾结点的指针指向新结点 
	pnew->next=NULL;	//新结点指针域为空,成为新链表的尾结点 
	*pn++;	//新链表结点个数增加 
	return h;	//返回头指针 
}
第三种,在首尾之间插入,假设要在学号为number的学生的位置后插入:
stu *Insert3(stu *h,int *pn,int number)
/*h做函数参数,这里将要接收的是指向链表首结点的指针
pn是指向n的指针,下面要用到它改变n的值以统计新链表结点个数*/
{
	stu *pnew;	//要插入的新结点
	stu *p=h;	//临时指针
	while(p && p->num!=number)
		p=p->next;	//让p指在原链表中的存储指定学号学生信息的节点的前一个结点上 
	pnew=(stu *)malloc(sizeof(stu));
	printf("请输入姓名,学号,分数:");
	scanf("%s %d %d",pnew->name,&pnew->num,&pnew->score);
	pnew->next=p->next;	//新结点的指针指向原链表的插入结点的下一个结点 
	p->next=pnew;	//插入结点的指针指向新结点 
	*pn++;	//新链表结点个数增加 
	return h;	//返回头指针 
}
单链表的删除

删除也是在遍历的基础上进行操作的,思想就是先找到要删除的结点,再让它前面一个结点的指针域指向它的后面一个结点,还是用同一个链表,假设要删除存储学号为number的学生信息的结点:

stu *Delete(stu *h,int *pn,int number)
/*h做函数参数,这里将要接收的是指向链表首结点的指针
pn是指向n的指针,下面要用到它改变n的值以统计新链表结点个数*/
{
	stu *t=h;	//临时指针
	stu *pPre=t;	//要删除结点的前一个结点 
	while(p && p->num!=number)
		p=p->next;	//让p指在原链表中的存储指定学号学生信息的节点的前一个结点上 
	pPre=p;	//指向待删除结点的前一个结点
	p=p->next;	//现在p指向待删除结点 
	pPre->next=t->next;	//连接待删除结点两边结点 
	free(t)	//释放待删除结点的内存空间 
	*pn--;	//新链表结点个数减少 
	return h;	//返回头指针 
}
单链表的基本操作就这些啦,分享到此结束。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值