c语言——数据结构【链表:单向链表】

news2024/12/17 7:38:02

 上篇→快速掌握C语言——数据结构【创建顺序表】多文件编译-CSDN博客

一、链表

二、单向链表

2.1 概念

2.2 单向链表的组成

2.3 单向链表节点的结构体原型

//类型重定义,表示存放的数据类型
typedef int DataType;

//定义节点的结构体类型
typedef struct node
{
    union
    {
        int len; //头结点的数据域,表示链表的长度
        DataType data;//普通节点的数据域
    };
    struct node *next; //节点的指针域
}linkList,*linkListPtr;

2.4 单向链表的相关操作 (功能函数的封装)

1>创建

#include "test.h"

//创建链表==创建头结点
linklistPtr create()
{
	//在堆区申请节点大小空间,将地址放回给主程序使用
	linklistPtr H=(linklistPtr)malloc (sizeof(linklist));
	if (NULL==H)
	{
		printf("创建失败\n");
		return NULL;
	}
//申请成功,将头节点的数据域为0,指针域NULL
	H->len=0;
	H->next=NULL;

	printf("创建成功\n");
	return H;

}

2>判空

//判空
int  empty(linklistPtr H)
{
	if (NULL==H)
	{
		printf("判空失败");
		return -1;
	}
  return H->len==0;

}

3>申请节点,封装数据

//申请节点封装数据
linklistPtr create_node(int e)
{
	linklistPtr p=(linklistPtr)malloc (sizeof(linklist));
	if(NULL==p)
	{
		printf("申请失败");
		return NULL;
	}
	p->data=e;
	p->next=NULL;
	return p;
}

4>头插

//头插
int   head_add(linklistPtr H,int e)
{
	if (NULL==H)
	{
		printf("插入失败");
		return 0;

	}

//申请节点封装数据
	linklistPtr p=create_node(e);
//头插
	p->next =H->next;
	H->next =p;
//插入成功长度自增
	H->len++;
	return 1;
}

 5>遍历

void show (linklistPtr H)
{
	
		if (NULL==H ||empty(H))
		{
			printf("遍历失败");
			return ;
		}
//定义一个指针指向头结点
		linklistPtr p =H;
		for (int i=0;i<H->len;i++)
		{
			p=p->next;
			printf("%d ",p->data);
		}
putchar(10);
}

6>尾插

//尾插
int tail_add(linklistPtr H,int e)
{
	if (NULL== H)
	{
		printf("插入失败");
		return 0;
	}
//申请节点封装数据
	linklistPtr p=create_node(e);

	linklistPtr q=H;
	while(q->next !=NULL)
	{
		 q= q->next;
	}
//尾插
 	 q->next =p;

//插入成功长度自增
	 H->len++;
	 return 1;
}

7>任意位置插入

//任意位置插入
int insert(linklistPtr H,int index , int e)
{
	//链表是否合法
	//插入位置是否合理
	if (NULL==H || index <1 ||index>H->len+1)
	{
		printf("插入失败\n");
		return 0;
	}
//申请节点封装数据 
	linklistPtr p=create_node(e);

//定义一个指针指向要插入位置的前一个节点
	linklistPtr q=H;

	for (int i=0;i<index-1;i++)
	{
		q=q->next ;
	}
	
//插入(头插)
	p->next =q->next;
	q->next =p;

//插入成功长度自增 
	H->len++;
	return 1;
}

8>头删

//头删
int head_del(linklistPtr H)
{
	//判空 
	//判断合法性
	if (NULL==H ||empty(H))
	{
		printf(" 删除失败\n");	
		return 0;
	}
	//定义一个指针指向普通节点的第一个节点
	linklistPtr q= H->next;

//删除 (孤立)
	H->next=q->next ;

//释放空间
	free(q);
	q=NULL;

//删除成功 链表长度自减
	H->len--;
	return 1;
}

9>尾删

//尾删
int tail_del(linklistPtr H)
{
	if(NULL==H ||empty(H))
	{
		printf("删除失败 ");
		return 0;
	}
//定义一个指针,指向 最后一个节点的 前一个节点
	linklistPtr q=H;

	for (int i=0;i<H->len-1;i++)
	{
		q=q->next;
	}
//删除
	free(q->next);
	q->next=NULL;
//删除成功 长度自减
	H->len--;
	return 1;
}

10>任意位置删除

//任意位置删除
int index_del(linklistPtr H ,int index)
{
	if (NULL==H ||empty(H)||index<0||index>H->len)
	{
		printf("删除失败");
		return 0;
	}

//定义指针,指向要删除的节点
	linklistPtr p=NULL;

//定义一个指针,指向要删除的前一个节点
	linklistPtr q=H;

	for (int i=0;i<index-1;i++)
	{
		q=q->next;
	}

	if (p=NULL)
	{
		printf("删除失败");
		return  0;
	}

//保存删除节点的位置
	p=q->next;

	q->next=p->next;

//删除节点的内存
	free (p);
//删除成功 长度自减
	H->len--;
	return 1;
}

11>按位置修改

//按位置修改
int index_change(linklistPtr H,int index ,int e)
{
	if (NULL==H||empty(H))
	{
		printf("修改失败");
		return 0;
	}
	
//定义一个指针,指向要修改的前一个节点
	linklistPtr q=H;
//定义指针,指向要修改的节点
	linklistPtr p=NULL;

	for (int i=0;i<index;i++)
	{
		q=q->next;
	}

//保存修改节点的位置
	p=q->next;

	//修改值
	p->data=e;

	return 1;
	
}

12>按值查找返回地址

//按值查找返回
linklistPtr  index_find(linklistPtr H,int e)
{
	if (NULL==H||empty(H))
	{
		printf("查找失败");
		return NULL;
	}
 //定义一个指针指向头结点 
	linklistPtr p=H->next;
	while(p!=NULL)
	{

		if (p->data==e)
		{
			printf("%p\n",p);
			return p;
			
		}
		p=p->next;
	}
	//没找到
	printf("没找到目标值\n");
	return NULL;
	
}

14>销毁

//销毁
void my_free(linklistPtr *H)
{
	if (NULL==*H)
	{
		printf("销毁失败");
		return;
	}
	free (*H);

	H=NULL;
	printf("销毁成功");
}

三、完整代码

1>头文件test.h

#ifndef __TEST_H__
#define __TEST_H__

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

//定义节点的结构体类型
typedef struct node
{
	union
	{
		int len;//头结点的数据域,表示链表的长度
		int data;//普通节点的数据域
	};
    struct node *next;//节点的指针域
}linklist,*linklistPtr;

//创建链表==创建头结点
linklistPtr create();

int  empty(linklistPtr H);

linklistPtr create_node(int e);

int   head_add(linklistPtr How,int e);

void show (linklistPtr H);

int tail_add(linklistPtr H,int e);

int insert(linklistPtr H,int index , int e);

//头删
int head_del(linklistPtr H);


//尾删
int tail_del(linklistPtr H);

int index_del(linklistPtr H ,int index);
//按位置修改
int index_change(linklistPtr H,int index ,int e);
//按值查找返回
linklistPtr  index_find(linklistPtr H,int e);
#endif

2>源文件test.c

#include "test.h"

//创建链表==创建头结点
linklistPtr create()
{
	//在堆区申请节点大小空间,将地址放回给主程序使用
	linklistPtr H=(linklistPtr)malloc (sizeof(linklist));
	if (NULL==H)
	{
		printf("创建失败\n");
		return NULL;
	}
//申请成功,将头节点的数据域为0,指针域NULL
	H->len=0;
	H->next=NULL;

	printf("创建成功\n");
	return H;

}
//判空
int  empty(linklistPtr H)
{
	if (NULL==H)
	{
		printf("判空失败");
		return -1;
	}
  return H->len==0;

}
//申请节点封装数据
linklistPtr create_node(int e)
{
	linklistPtr p=(linklistPtr)malloc (sizeof(linklist));
	if(NULL==p)
	{
		printf("申请失败");
		return NULL;
	}
	p->data=e;
	p->next=NULL;
	return p;
}




//头插
int   head_add(linklistPtr H,int e)
{
	if (NULL==H)
	{
		printf("插入失败");
		return 0;

	}

//申请节点封装数据
	linklistPtr p=create_node(e);
//头插
	p->next =H->next;
	H->next =p;
//插入成功长度自增
	H->len++;
	return 1;
}

void show (linklistPtr H)
{
	
		if (NULL==H ||empty(H))
		{
			printf("遍历失败");
			return ;
		}
//定义一个指针指向头结点
		linklistPtr p =H;
		for (int i=0;i<H->len;i++)
		{
			p=p->next;
			printf("%d ",p->data);
		}
putchar(10);
}
//尾插
int tail_add(linklistPtr H,int e)
{
	if (NULL== H)
	{
		printf("插入失败");
		return 0;
	}
//申请节点封装数据
	linklistPtr p=create_node(e);

	linklistPtr q=H;
	while(q->next !=NULL)
	{
		 q= q->next;

	}
//尾插
 	 q->next =p;

//插入成功长度自增
	 H->len++;

	 return 1;
}
//任意位置插入
int insert(linklistPtr H,int index , int e)
{
	//链表是否合法
	//插入位置是否合理
	if (NULL==H || index <1 ||index>H->len+1)
	{
		printf("插入失败\n");
		return 0;
	}
//申请节点封装数据 
	linklistPtr p=create_node(e);

//定义一个指针指向要插入位置的前一个节点
	linklistPtr q=H;

	for (int i=0;i<index-1;i++)
	{
		q=q->next ;
	}
	
//插入(头插)
	p->next =q->next;
	q->next =p;

//插入成功长度自增 
	H->len++;
	return 1;
}


//头删
int head_del(linklistPtr H)
{
	//判空 
	//判断合法性
	if (NULL==H ||empty(H))
	{
		printf(" 删除失败\n");	
		return 0;
	}
	//定义一个指针指向普通节点的第一个节点
	linklistPtr q= H->next;

//删除 (孤立)
	H->next=q->next ;

//释放空间
	free(q);
	q=NULL;

//删除成功 链表长度自减
	H->len--;
	return 1;
}
//尾删
int tail_del(linklistPtr H)
{
	if(NULL==H ||empty(H))
	{
		printf("删除失败 ");
		return 0;
	}
//定义一个指针,指向 最后一个节点的 前一个节点
	linklistPtr q=H;

	for (int i=0;i<H->len-1;i++)
	{
		q=q->next;
	}
//删除
	free(q->next);
	q->next=NULL;
//删除成功 长度自减
	H->len--;
	return 1;
}

//任意位置删除
int index_del(linklistPtr H ,int index)
{
	if (NULL==H ||empty(H)||index<0||index>H->len)
	{
		printf("删除失败");
		return 0;
	}

//定义指针,指向要删除的节点
	linklistPtr p=NULL;

//定义一个指针,指向要删除的前一个节点
	linklistPtr q=H;

	for (int i=0;i<index-1;i++)
	{
		q=q->next;
	}

	if (p=NULL)
	{
		printf("删除失败");
		return  0;
	}

//保存删除节点的位置
	p=q->next;

	q->next=p->next;

//删除节点的内存
	free (p);
//删除成功 长度自减
	H->len--;
	return 1;
}

//按位置修改
int index_change(linklistPtr H,int index ,int e)
{
	if (NULL==H||empty(H))
	{
		printf("修改失败");
		return 0;
	}
	
//定义一个指针,指向要修改的前一个节点
	linklistPtr q=H;
//定义指针,指向要修改的节点
	linklistPtr p=NULL;

	for (int i=0;i<index;i++)
	{
		q=q->next;
	}

//保存修改节点的位置
	p=q->next;

	//修改值
	p->data=e;

	return 1;
	
}
//按值查找返回
linklistPtr  index_find(linklistPtr H,int e)
{
	if (NULL==H||empty(H))
	{
		printf("查找失败");
		return NULL;
	}
 //定义一个指针指向头结点 
	linklistPtr p=H->next;
	while(p!=NULL)
	{

		if (p->data==e)
		{
			printf("%p\n",p);
			return p;
			
		}
		p=p->next;
	}
	//没找到
	printf("没找到目标值\n");
	return NULL;
	
}

//反转 
 

//销毁
void my_free(linklistPtr *H)
{
	if (NULL==*H)
	{
		printf("销毁失败");
		return;
	}
	free (*H);

	H=NULL;
	printf("销毁成功");
}

3>测试文件main.c

#include "test.h"

int main(int argc, const char *argv[])
{
	//创建
	linklistPtr H=create();

//头插 
	head_add(H,10);
	head_add(H,20);
	head_add(H,30);
	head_add(H,40);
	head_add(H,50);
	
    show(H);
//尾插 
	tail_add(H,11);
	tail_add(H,22);
	tail_add(H,33);
	tail_add(H,44);
	tail_add(H,55);
	show(H);
	
    
//任意位置插入
	insert(H,3,888);

	show (H);	

//头删  	
	head_del(H);
	show(H);

	head_del(H);
	show(H);

	tail_del(H);
	show(H);


	index_del(H,3);
	show(H);


	index_change (H,5,666);
	show(H);

	index_find (H,666);
	
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2260933.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LC】876. 链表的中间结点

题目描述&#xff1a; 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[3,4,5] 解释&#xff1a;链表只有一个中间结点…

Bugku---misc---隐写2

题目出处&#xff1a;首页 - Bugku CTF平台 ✨打开发现是一张图片&#xff0c;于是查看属性&#xff0c;放在010查看&#xff0c;这都是基本步骤了&#xff0c;发现里面有一个flag.rar&#xff01;&#xff01;&#xff01;拿binwalk分析也确实存在 ✨于是按照压缩包的起始位置…

无需公网IP,本地可访问TightVNC 服务端

TightVNC 是一款免费而且开源的远程桌面软件&#xff0c;它允许用户在不同的操作系统之间实现无缝连接&#xff0c;TightVNC支持 Windows、macOS 和 Linux 等多个操作系统&#xff0c;为用户提供高效便捷的远程控制体验。在 Windows 系统电脑端安装使用 TightVNC 服务端和客户端…

【Unity基础】Unity中如何实现图形倒计时

为了在Unity中实现一个图形倒计时&#xff0c;除了代码部分&#xff0c;还需要一些UI元素的创建和设置。本文以环形倒计时为例&#xff0c;以下是完整的步骤&#xff0c;涵盖了如何创建UI元素、设置它们&#xff0c;以及如何编写控制环形倒计时进度的脚本。 1. 创建UI元素 创建…

Excel/VBA 正则表达式归纳汇总

1.with结构。以下语句用来提取A列中的“成品”两个字前面的部分的中文&#xff0c;不含成品两个字&#xff0c;结果存放在第2列。使用了On Error Resume Next&#xff0c;表示错误时继续下一条。 Sub 提取口味() Set regx CreateObject("vbscript.regexp") On Err…

xshell连接虚拟机,更换网络模式:NAT->桥接模式

NAT模式&#xff1a;虚拟机通过宿主机的网络访问外网。优点在于不需要手动配置IP地址和子网掩码&#xff0c;只要宿主机能够访问网络&#xff0c;虚拟机也能够访问。对外部网络而言&#xff0c;它看到的是宿主机的IP地址&#xff0c;而不是虚拟机的IP。但是&#xff0c;宿主机可…

优选算法《双指针》

在学习了C/C的基础知识之后接下来我们就可以来系统的学习相关的算法了&#xff0c;这在之后的笔试、面试或竞赛都是必须要掌握的&#xff1b;在这些算法中我们先来了解的是一些非常经典且较为常用的算法&#xff0c;在此也就是优选出来的算法&#xff0c;接下来在每一篇章中我们…

SQL server学习06-查询数据表中的数据(中)

目录 一&#xff0c;聚合函数 1&#xff0c;常用聚合函数 2&#xff0c;具体使用 二&#xff0c;GROP BY子句分组 1&#xff0c;基础语法 2&#xff0c;具体使用 3&#xff0c;加上HAVING对组进行筛选 4&#xff0c;使WHERE记录查询条件 汇总查询&#xff1a;在对数…

上传文件时获取音视频文件时长和文本文件字数

获取音视频文件时长和文本文件字数 一、获取音视频文件时长二、计算文本文件字数 最近有个需求&#xff0c;要求上传文件时获取音视频文件时长和文本文件字数&#x1f436;。 发现这样的冷门资料不多&#xff0c;特做个记录。本文忽略文件上传功能&#xff0c;只封装核心的工具…

C语言学习day22:进程ID获取工具/GetWindowThreadProcessId函数

简言&#xff1a; 每个人都有身份证号&#xff0c;这个身份证号就是个人的唯一标识符 进程也是如此&#xff0c;每个进程也有唯一的标识符&#xff0c;来标记自身是独一无二的 如下图:其中PID &#xff1a;Process ID&#xff0c;即进程ID 但是我们怎么去在编程中去获取某个…

使用Localstorage(Mapty)

使用Localstorage(Mapty) 首先&#xff0c;我们创建一个函数名&#xff0c;先在app中去调用它 // 为所有的锻炼创建本地存储this._setLocalStorage();之后我们就开始编写这个函数的功能 _setLocalStorage() {localStorage.setItem(workouts, JSON.stringify(this.#workouts));…

如何用细节提升用户体验?

前端给用户反馈是提升用户体验的重要部分&#xff0c;根据场景选择不同的方式可以有效地提升产品的易用性和用户满意度。以下是常见的方法&#xff1a; 1. 视觉反馈 用户执行了某些操作后&#xff0c;需要即时确认操作结果。例如&#xff1a;按钮点击、数据提交、页面加载等。…

OpenHarmony-3.HDF input子系统(5)

HDF input 子系统OpenHarmony-4.0-Release 1.Input 概述 输入设备是用户与计算机系统进行人机交互的主要装置之一&#xff0c;是用户与计算机或者其他设备通信的桥梁。常见的输入设备有键盘、鼠标、游戏杆、触摸屏等。本文档将介绍基于 HDF_Input 模型的触摸屏器件 IC 为 GT91…

旅游资源系统|Java|SSM|VUE| 前后端分离

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库可…

Docker网络与数据管理

Docker网络与数据管理 1. Docker网络基础&#xff1a;桥接网络、主机网络和自定义网络 Docker提供了多种网络模式&#xff0c;以满足不同应用场景的需求。理解Docker的网络模式对于容器间通信、网络安全性及性能优化至关重要。在Docker中&#xff0c;每个容器都可以连接到不同…

X.game解析柚子币提升速效双向利好和年中历史新低原因

柚子币最新消息&#xff0c;币安宣布将于2024年9月25日21:00左右暂停柚子币网络上的代币存取业务&#xff0c;以全力支持即将到来的柚子币网络升级和硬分叉&#xff0c;这一消息为柚子币的未来发展增添了新的期待和变数。 除了速度的提升&#xff0c;Spring1.0还带来了诸多技术…

数据结构之线性表1

2.1 线性表的定义和基本操作 1.线性结构的特点是&#xff1a;在数据元素的非空有限集中&#xff0c; &#xff08;1&#xff09;存在惟一的一个被称做“第一个”的数据元素&#xff1b; &#xff08;2&#xff09; 存在惟一的一个被称做“最后一个”的数据元素&#xff1b; &a…

Tomcat原理(5)——tomcat最终实现

目录 一、什么是Servlet容器 二、ServletConfigMapping构建实现容器 ServletConfigMapping MyTomcat 三、优化server Server MyTomcat 四、匹配 代码如下&#xff1a; 测试如下&#xff1a; 上一篇博客已经为介绍了servelet的实现 &#xff0c;这篇对上一篇博客进行补…

echarts 常见组件合集

仪表盘组件 <template><div class"w100 h100" ref"chart"></div> </template><script> import resize from "./mixins/resize"; export default {mixins: [resize],props: ["list"],watch: {list: {// …

C/C++代码性能优化技巧的书籍及资料

使用C/C开发的场景&#xff0c;大多对代码的执行的速度&#xff0c;实时性有较高的要求&#xff0c;像嵌入式系统的开发&#xff0c;资源还受限。在算力存储空间有限的MCU上写出简洁又高效的代码实际是一种艺术。软件工程师在代码设计上的这种差距&#xff0c;会反映在产品的性…