单链表的基本操作代码实现(C语言版)

这篇具有很好参考价值的文章主要介绍了单链表的基本操作代码实现(C语言版)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言:

单链表的基本操作

准备工作(头文件、各种宏定义以及结构体定义)

一.较简单操作

1.单链表的初始化

2.判断单链表是否为空表

3.单链表的销毁

4.单链表的清空

5.求单链表的表长

二.较重要操作

1.单链表的取值

2.单链表元素的查找

3.单链表的结点插入

4.单链表的结点删除

5.单链表的创建

以下是主函数以及函数声明

补充


前言:

        在实现顺序表的基本操作后,觉得自己对单链表基本操作的思路无大问题,因此当时没有对链表基本操作进行实现,在后来的稀疏多项式的运算中需要运用到单链表(顺序表实现会造成大量空间的浪费),而自己并没有实现过这些基本操作,为防止在做稀疏多项式的运算时出现难以解决的问题,打算再把单链表的基本操作实现一遍。并写一篇博客,耗时:70分钟。

        希望能够对您有一定帮助和参考价值。新csdner,有所不足尽管提出。

单链表的基本操作

        单链表的基本操作包括单链表的初始化判断空链表销毁清空以及求表长这些较为简单的操作,还有更为重要的单链表的取值、按值查找返回元素所在地址、按值查找返回元素所对应序号、结点插入和删除以及头插法和尾插法建立单链表。目前只实现了这些操作,并进行的测试。

准备工作(头文件、各种宏定义以及结构体定义)

#include <stdio.h>
#include <stdlib.h>
#include<stdbool.h>

#define OK 1
#define ERROR 0        /*用于返回函数执行的状态值*/

typedef int Status;
typedef int ElemType;

typedef struct Node {

	ElemType data;			 //存储数据
	struct Node *next;//存储下一个元素的地址

} Node;

typedef struct Node *LinkList; /* 定义LinkList */

一.较简单操作

1.单链表的初始化

        单链表的初始化指生成一个只有头指针的单链表,并将其指向的头结点的指针域置空。需要注意的是,传入的参数为LinkList *L;为什么L本来就是指针类型了还要加   " * "呢,因为你要知道你是要对链表的本质(内存,指针指向等)进行更改而不是使用链表进行元素的查找取值等,如果只是这些操作,只要告诉计算机你要查找的对象是哪个表,即把链表的头指针传过去就行(这样就不需要添加 " * " )。以下是代码实现:

/* 初始化链式线性表 */
Status IniList(LinkList *L) {
	
	*L=(LinkList)malloc(sizeof(Node)); /* 产生头结点,并使L指向此头结点 */
		
	(*L)->next=NULL; /* 指针域为空 */
	
	return OK;
}

2.判断单链表是否为空表

        只需要判断对应单链表头结点的指针域是否为空即可。该实现我使用的是bool类型返回值,实际上c语言中逻辑值就是0,1,因此多此一举了属于是;如果要用bool类型需要添加头文件#include<stdbool.h>。以下是代码实现:

bool Empty(LinkList L) {

	if(L->next==NULL)
		return true;    

	return false;
//main函数中测试bool c=Empty(L); printf("%d",c);  返回 1
}

3.单链表的销毁

        单链表的销毁指将链表中的所有结点包括头结点都释放掉(c语言中使用free(),c++中使用delete())。由于仍然是对单链表的“本质”进行修改,所以参数需加  " * " ,思路是利用头指针以及新指针p(用于释放其指向的结点),在释放之前,先将头指针后移,否则找不到下一结点。以下是代码实现:

/* 单链表的销毁*/         

Status DestoryList(LinkList *L) {
	LinkList p=*L;              //p此时指向头结点

	//注意此时不能直接释放p,因为头结点中还存放着下一结点的地址,释放就找不到下一个结点了
	while(*L) {
		*L=(*L)->next;
		free(p);            
		p=*L;	
	}

	return OK;

	//测试int b=DestoryList(&L);  printf("%d",b);ListTraverse(L); 输出1,且并不打印其他的
}

4.单链表的清空

        将除头结点以外的结点释放,并将头结点的指针域置空。与销毁不同,该操作的头指针不能动,所以还需要新定义一个指针对下一结点进行定位。以下是代码实现:

/*清空链表*/
Status ClearList(LinkList L) {

	LinkList p,q;    //p用于指向需要释放的结点,q用于在p释放之前指向下一结点,以使p移动
	p=L->next;       //p指向首元结点

	while(p) {
		q=p->next;   //q指向下一结点
		free(p);
		p=q;
	}

	//最后不要忘了,结点释放后还需要将头结点的指针域更改为NULL,形成空表
	L->next=NULL;

	return OK;

	/*测试CreateList(&L,n); ClearList(L);ListTraverse(L);//不输出创建时输入的元素*/

}

5.求单链表的表长

        以下是代码实现:

/*求链表的表长*/
int ListLength(LinkList L) {

	LinkList p;   //用于指向除头结点以外的结点
	int count=0;
	p=L->next;

	while(p) {
		count++;
		p=p->next;
	}

	return count;	

 //测试  printf("%d",ListLength(L)); 输出正确
}

二.较重要操作

1.单链表的取值

        取出链表中位置 i 对应的元素,i表示的是序号,不按逻辑层面确定。思路:将指针p移动到对应序号逻辑层面存储位置,随后将其指向的元素返回即可。注意循环终止条件,以下是代码实现:

/*获得某一元素*/  //返回链表中第i位置的元素
Status GetElem(LinkList L,int i,ElemType *e) {

	Node *p;
	p=L->next;
	int j = 1;

	for(; p&&j<i ;) {
		p = p->next; /*p所指元素存在且j<1时循环执行*/
		++j;
	}

	if(!p||j>i) //j大于i的情况:如i传入的为0或负数
		return ERROR;

	*e=p->data;

	return OK;
 //测试:元素返回正确
}

2.单链表元素的查找

        查找分为按值查找返回元素所在地址和返回所在序号,思路:定义一个指针p指向头结点,随后利用循环将指针p进行移动即对链表进行遍历,将每次循环时结点的数据与待查找数据比较,如果找到则返回对应地址(反映为当前指针的指向),以及对应的序号。以下是代码实现:

//查找
/*按值查找数据所在地址并返回*/  //参数为所需查询链表,需要查询的数据,返回p的地址
LinkList searchAD(LinkList L,ElemType e) {

	LinkList p;
	p=L->next;

	for(int i=0; p&&i<ListLength(L); i++) {
		if(p->data==e)
			break;
		p=p->next;
	}

	return p; 

//测试;printf("%p",searchAD(L,5));  5所在元素次序不同,打印的地址不同

}

/*按值查找数据所在链表的序号(第几个元素)*/  //参数:所需查询链表,所需查询数据,返回数据所在序号
int searchNum(LinkList L,ElemType e) {

	LinkList p;
	p=L->next;

	for(int i=0; p&&i<ListLength(L) ; i++) {
		if(p->data==e) {    //遍历链表中p所指项结点的数据,与e比较,找到后返回对应序号即可
			return i+1;
		}

		p=p->next; //当前结点的数据不等于e则p指针后移
	}

	return 0; 

 //测试:printf("%d",searchNum(L,5));  返回5所在位置正确,如果不存在所查询数据,返回0
}

3.单链表的结点插入

        思路:先将待插入位置找到,利用其前一个位置的指针p对其后继进行保留,随后定义一个新结点并用指向它的指针q,进行前驱后继的链接。以下是代码实现:

//链表元素的插入    //参数:需要插入数据的链表,需要插入元素的位置,需要插入的数据,返回插入结束状态
Status ListInsert(LinkList L,int i,ElemType e) {

	LinkList p,q;
	p=L;        //指向头结点

	//先新建并初始化好需要插入的结点,用指针q指向它
	q=(Node *)malloc(sizeof(Node));
	q->data=e;
	q->next=NULL;


	for(int j=0; p&&j<i-1 ; j++) { 

		if(i>ListLength(L)+1)
			return ERROR;   //如果插入的位置大于链表的尾结点后面的一个位置,则返回错误
		p=p->next; 
	}

	//将待插入结点的前后结点与之形成链式关系

	q->next=p->next;    //接后继结点
	p->next=q;	        //接前驱结点

	return OK;

	/*		测试:ListInsert(L,4,99);	ListTraverse(L); 在表中元素为5个的情况下
		插入位置为1--6均可正确插入,如果插入位置大于等于7,则不插入元素	              */
}

4.单链表的结点删除

        思路:同样是先找到待删除结点,将q指针指向它,并新定义一个指针p对其前驱进行指向,以便后续链接,接好待删除结点的前驱后继后即可释放该结点。以下是实现代码:

//链表元素的删除  //参数需要删除元素的链表,需要删除的结点
Status deleElem(LinkList L,int i) {

	LinkList p,q;   //p指向删除位置的前一结点,q指向需要删除的结点
	p=L;  //p指向头结点


	//首先需要将p移动到删除结点的前一结点
	for(int j=0; p&&j<i-1; j++) {
		p=p->next;
	}

	q=p->next;  //如果所需删除结点存在,则将q指向它,如果不存在返回错误,不执行删除

	if(!q)
		return ERROR;  //判断删除的结点是否存在


	p->next=p->next->next;  //也可以p->next=q->next;但一定要在释放之前将p指向下一结点,否则找不到
	free(q);


	return OK;
	/*
	测试:
	deleElem(L,1);
	ListTraverse(L);假设表中有5个元素,则第1--5个位置的元素正常删除,如果为大于等于6的位置,不删除
	*/
}

5.单链表的创建

        包括尾插法和头插法,进行单链表的内存分配和结点的添加与赋值。以下是代码实现:

/*头插法创建链表*/ //输入n个元素 ,元素从头开始依次插入

Status CreateList_H(LinkList *L,int n) {
	LinkList p,r;  //p用于指向新结点,r指向头结点

	//建立一个带有头结点的单链表并将指针域置为空
	*L=(LinkList)malloc(sizeof(Node));
	r=*L;
	r->next=NULL;
//结点添加与赋值
	for(int i=n; i>0; i--) {
		p=(Node *)malloc(sizeof(Node));
		printf("请输入该链表的第%d个元素:",i);
		scanf("%d",&p->data);
		p->next=NULL;
		p->next=r->next;
		r->next=p;
	}

	return OK;

	/*测试:printf("请输入头插法创建链表的元素个数:");
	scanf("%d",&n);
	CreateList_H(&L_H,n);
	ListTraverse(L_H);  新建正常
	*/
}
/*尾插法创建链表*/ //输入n个元素, 元素从尾部依次接入
Status CreateList(LinkList *L,int n) {

	LinkList p,r;//p用于指向新结点(待插入结点),r指向尾部结点

	*L = (LinkList)malloc(sizeof(Node));
	r=*L;  //刚开始时r指向头结点
	r->next=NULL;

	for(int i=0; i<n; i++) {
		p=(Node *)malloc(sizeof(Node));   //注意这里不要忘记将这块内存定义为Node的指针类型
		printf("请输入该链表的第%d个元素:",i+1);
		scanf("%d",&p->data);
		p->next=NULL;
		r->next=p;
		r=r->next;
	}
	r->next=NULL;
	return OK;
}

以下是主函数以及函数声明

对应操作的运行截图就不搞了,主函数也没有对所有函数进行调用,但是各个操作都已进行测试,程序的健壮性还是有的。

Status IniList(LinkList *L);
Status GetElem(LinkList L,int i,ElemType *e);
Status CreateList(LinkList *L,int n);  //尾插法
Status CreateList_H(LinkList *L,int n);//头插法
Status visit(ElemType c);
Status ListTraverse(LinkList L);
bool Empty(LinkList L);
Status DestoryList(LinkList *L);
Status ClearList(LinkList L);
int ListLength(LinkList L);
LinkList searchAD(LinkList L,ElemType e);
int searchNum(LinkList L,ElemType e);
Status ListInsert(LinkList L,int i,ElemType e);
Status deleElem(LinkList L,int i);

int main() {
	LinkList L,L_H;
	int n;
	int a=IniList(&L);     //a用于判断是否成功初始化

	printf("请输入尾插法创建链表的元素个数:");
	scanf("%d",&n);
	CreateList(&L,n);
	ListTraverse(L);
	printf("请输入头插法创建链表的元素个数:");
	scanf("%d",&n);
	CreateList_H(&L_H,n);
	ListTraverse(L_H);
	return 0;
}

补充

        为了更方便的对链表进行输出,新定义了两个子函数实现,代码如下:

//打印元素
Status visit(ElemType c) {
	printf("%d ",c);
	return OK;
}
//遍历链表
Status ListTraverse(LinkList L) {
	LinkList p=L->next;
	printf("链表中所有元素为: ");
	if(!p)
		return ERROR;//如果首元结点不存在返回0

	while(p) {
		visit(p->data);
		p=p->next;
	}
	printf("\n");
	return OK;
}

我的小站:Kris20030907.gitee.io,有需要的话可以交换友链哦,评论区留言文章来源地址https://www.toymoban.com/news/detail-847439.html

到了这里,关于单链表的基本操作代码实现(C语言版)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】单链表——单链表的定义及基本操作的实现(头插、尾插、头删、尾删、任意位置的插入与删除)

    🧑‍💻作者: @情话0.0 📝专栏:《数据结构》 👦个人简介:一名双非编程菜鸟,在这里分享自己的编程学习笔记,欢迎大家的指正与点赞,谢谢!   顺序表可以随时存取表中的任意一个元素,它的存储位置可以用一个简单直观的公式表示,但是插入和删除操作需要移动

    2024年02月19日
    浏览(205)
  • 单链表的基本操作

    目录 一.链表的基本概念和结构 二.链表的分类 三.单链表的基本操作  1.创建一个节点 2.打印 3.尾插 4.头插 5.尾删 6.头删 7.查找 8.指定位置插入 9.指定位置删除 10.销毁         概念:链表是一种 物理存储结构上非连续 、非顺序的存储结构,数据元素的 逻辑顺序 是通过链表

    2024年01月22日
    浏览(47)
  • 【C++】单链表——单链表的基本操作

     由于顺序表的插入删除操作需要移动大量的元素,影响了运行效率,因此引入了线性表的链式存储—— 单链表 。单链表通过一组任意的存储单元来存储线性表中的数据元素,不需要使用地址连续的存储单元,因此它不要求在逻辑上相邻的两个元素在物理位置上也相邻。 单

    2024年02月03日
    浏览(46)
  • 【头歌】单链表的基本操作

    任务描述 本关任务:编写单链表的初始化、插入、遍历三个操作函数。 相关知识 链表 是线性表的链式存储结构的别称,特点是以“指针”指示后继元素,因此线性表的元素可以存储在存储器中任意一组存储单元中。 每个结点只有一个指针域的链表称为 单链表 。 因此单链

    2024年03月26日
    浏览(45)
  • 数据结构上机练习——单链表的基本操作、头文件、类定义、main函数、多种链表算法的实现,含注释

      头文件和源文件分开有很多好处:可以提高编译速度、提高代码的可维护性、提高代码的可重用性和可扩展性,同时也可以使代码结构更清晰,方便代码的管理和维护。 LinkList.h test.cpp                  (下面所有函数都默认在类中实现)   我们以

    2024年02月07日
    浏览(58)
  • 【数据结构】——单链表的基本操作(带头结点)

            单链表解决了顺序表需要大量连续存储单元的缺点,但单链表附加指针域, 存储密度较顺序表低(考点!!) 。由于单链表的元素离散地分布在存储空间中,所以单链表是 非随机存取 的存储结构,即不能直接找到表中某个特定的结点。当查找某个特定结点时,需要

    2024年02月05日
    浏览(52)
  • 单链表——单链表的定义及基本操作(头插法尾插法建表、查找、插入、删除等)

    上一篇我们已经完成了顺序表的实现和基本操作元素的增加、删除和查找 (链接直达:线性表元素的基本操作(C语言)【数据结构】-CSDN博客) 我们知道顺序表支持随机访问,可以通过下标来直接访问,同时也可以进行排序等优点;但是仍存在局限性,对顺序表的中部进行增加

    2024年04月10日
    浏览(48)
  • C语言单链表实现初始化、创建、增、删、查等基本操作(详细)

    提示:文章参考王道的课程,相当于课程笔记 目录 一、单链表的定义及初始化 1、定义   2、初始化  1)不带头结点的单链表  2)带头节的单链表  二、单链表插入和删除 1)插入 1、按位序插入(带头结点) 2、按位插入(不带头结点)  3、指定结点的后插操作  4、指定结点

    2023年04月08日
    浏览(65)
  • 【数据结构】C语言实现双链表的基本操作

    大家好,很高兴又和大家见面啦!!! 经过前面几个篇章的内容分享,相信大家对顺序表和单链表的基本操作都已经熟练掌握了。今天咱们将继续分享线性表的链式存储的第二种形式——双链表。在今天的内容中,咱们将介绍双链表的创建以及一些基本操作,接下来跟我一起

    2024年02月04日
    浏览(63)
  • c语言数据结构——链表的实现及其基本操作

    顺序表的问题及思考 问题: 中间/头部的插入删除,时间复杂度为O(N) 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插

    2023年04月09日
    浏览(85)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包