C语言Link_List简单实现

2023-10-29

C语言Link_List简单实现,不做线程控制

Link_List.h

/****************************************************************************
作者:代浩然
时间:2017-8-2
该文件定义为非线性链表相关的实现
线性链表的特性:
	1、在内存中的存放地址是非连续的,随机分配
优点:
	1、由于地址的非连续性,所以我们在随机插入的时候只需要找到插入的位置,然后将该位置的前后指针的位置只想该元素的地址就行,不需要重新分配内存
	   ,一瞬间就能完成,速度非常快
缺点:
	2、由于地址的非连续性,所以元素在内存中的存放位置是非固定的,所以就造成了第一个元素和第二个元素的内存位置跨度非常大,最大为4GB,所以CPU的PC
	   指针寻址非常慢。造成随机访问慢、遍历效率低下,释放空间效率低下
****************************************************************************/
#pragma once
#ifndef _Link_LIST_H
#define _Link_LIST_H
#ifdef __cplusplus
extern "C" {
#endif

//定义节点,双向链表
typedef struct _Link_Node{
	void* data;//数据域
	struct _Link_Node* priorNode;//指向上一个节点的指针
	struct _Link_Node* nextNode;//指向下一个节点的指针
}Link_Node;

//定义链表结构
typedef struct _Link_List{
	Link_Node *head;//链表的头指针
	Link_Node *trail;//链表的尾部指针
	unsigned long length;//链表的当前长度
}Link_List;

/**
 * 功能:初始化链表
 * 返回值:如果成功,则返回链表的地址,如果失败返回NULL
 */
Link_List* Link_List_Init();

/**
 * 功能:随机插入链表
 * 参数:
 *		pList:链表地址
 *		pData:插入的数据节点
 *		index:要插入的位置,如果为0,则默认从链表的开始处插入,如果为-1,则默认从链表的最后插入
 * 返回值:成功返回0,失败返回-1
 */
int Link_List_Insert(Link_List* pList,void* pData,long index);

/**
 * 功能:从某个位置取出元素
 * 参数:
 *		pList:链表地址
 *		index:位置
 * 返回值:返回数据体指针
 */
void* Link_List_GetAt(Link_List* pList,unsigned long index);

/**
 * 功能:通过索引删除元素,删除元素只是将data域置为NULL,并不会释放data指针,由调用者释放
 * 参数:
 *		pList:链表地址
 *		index:位置
 */
void Link_List_RemoveAt(Link_List* pList,unsigned long index);


/**
 * 功能:清空链表
 * 参数:
 *	pList:链表地址
 */
void Link_List_Clear(Link_List* pList);

/**
 * 功能:释放链表空间
 * 参数:
 *	pList:链表地址
 */
void Link_List_Free(Link_List* pList);

/**
 * 功能:Link_List测试
 */
void Link_List_Test();

#ifdef __cplusplus
}  /* end of the 'extern "C"' block */
#endif
#endif


Link_List.c

#include "Link_List.h"
#include <stdlib.h>
#include <malloc.h>

/**
 * 功能:初始化链表
 * 返回值:如果成功,则返回链表的地址,如果失败返回NULL
 */
Link_List* Link_List_Init()
{
	Link_List* pList = NULL;
	pList = (Link_List*)malloc(sizeof(Link_List));
	if(pList == NULL)
	{
		return NULL;
	}
	pList->length = 0;
	pList->head = NULL;
	pList->trail = NULL;
	return pList;
}

/**
 * 功能:随机插入链表
 * 参数:
 *		pList:链表地址
 *		pData:插入的数据节点
 *		index:要插入的位置,如果为0,则默认从链表的开始处插入,如果为-1,则默认从链表的最后插入
 * 返回值:成功返回0,失败返回-1
 */
int Link_List_Insert(Link_List* pList,void* pData,long index)
{
	long i = 0;
	if(pList == NULL)
		return -1;
	if(index < -1 || (index > pList->length && index != -1))
	{
		return -1;
	}
	//判断是否是首次插入
	if(pList->length == 0)
	{
		Link_Node* pNode = (Link_Node*)malloc(sizeof(Link_Node));
		if(pNode == NULL)
			return -1;
		pNode->data = pData;
		pNode->priorNode = NULL;
		pNode->nextNode = NULL;
		pList->head = pNode;
		pList->trail = pNode;
		pList->length++;
		return 0;
	}
	else
	{
		if(-1 == index)//从末尾处插入
		{
			//创建节点
			Link_Node* pNode = (Link_Node*)malloc(sizeof(Link_Node));
			if(pNode == NULL)
				return -1;
			pNode->data = pData;
			pNode->nextNode = NULL;
			pNode->priorNode = pList->trail;
			//将节点加到末尾处
			pList->trail->nextNode = pNode;
			pList->trail = pNode;
			pList->length++;
		}
		else if(0 == index) //从开始处插入
		{
			//创建节点
			Link_Node* pNode = (Link_Node*)malloc(sizeof(Link_Node));
			if(pNode == NULL)
				return -1;
			pNode->data = pData;
			pNode->nextNode = pList->head;
			pNode->priorNode = NULL;
			//将节点加载到头部
			pList->head->priorNode = pNode;
			pList->head = pNode;
			pList->length++;
			return 0;
		}
		else//指定位置插入
		{
			//后期可以使用快速查找算法优化
			Link_Node* pNode = pList->head;
			i=0;
			while(pNode != NULL)
			{
				if(index == i)//查找到要插入的位置节点
				{
					//创建节点
					Link_Node* pCurrentNode = (Link_Node*)malloc(sizeof(Link_Node));
					if(pCurrentNode == NULL)
						return -1;
					pCurrentNode->nextNode = pNode;
					pCurrentNode->priorNode = pNode->priorNode;
					pNode->priorNode->nextNode = pCurrentNode;
					pNode->priorNode = pCurrentNode;
					pList->length++;
					return 0;
				}
				pNode = pNode->nextNode;
				i++;
			}
		}
	}
	return 0;
}

/**
 * 功能:从某个位置取出元素
 * 参数:
 *		pList:链表地址
 *		index:位置
 * 返回值:返回数据体指针
 */
void* Link_List_GetAt(Link_List* pList,unsigned long index)
{
	int i = 0;
	Link_Node* pNode = NULL;
	if(pList == NULL)
	{
		return NULL;
	}
	i = 0;
	pNode = pList->head;
	while(pNode != NULL)
	{
		if(i == index)
		{
			return pNode->data;
		}
		pNode = pNode->nextNode;
		i++;
	}
	return NULL;
}

/**
 * 功能:通过索引删除元素,删除元素只是将data域置为NULL,并不会释放data指针,由调用者释放
 * 参数:
 *		pList:链表地址
 *		index:位置
 */
void Link_List_RemoveAt(Link_List* pList,unsigned long index)
{
	int i = 0;
	Link_Node* pNode = NULL;
	if(pList == NULL)
	{
		return;
	}
	i = 0;
	pNode = pList->head;
	while(pNode != NULL)
	{
		if(i == index)
		{
			//找到节点,开始删除
			if(pNode->priorNode == NULL) //表示链表头部节点
			{
				Link_Node* head = pList->head;
				pList->head = head->nextNode;
				pList->head->priorNode = NULL;
				free(head);//释放节点
				pList->length--;
			}
			else if(pNode->nextNode == NULL)//表示链表尾部节点
			{
				Link_Node* trial = pList->trail;
				pList->trail = trial->priorNode;
				pList->trail->nextNode = NULL;
				free(trial);//释放节点
				pList->length--;
			}
			else
			{
				//当前节点的上一个节点的下一个节点指向当前节点的下一个节点
				pNode->priorNode->nextNode = pNode->nextNode;
				//当前节点的下一个节点的上一个节点指向当前节点的上一个节点
				pNode->nextNode->priorNode = pNode->priorNode;
				free(pNode);
				pList->length--;
			}
			return;
		}
		pNode = pNode->nextNode;
		i++;
	}
}

/**
 * 功能:清空链表
 * 参数:
 *	pList:链表地址
 */
void Link_List_Clear(Link_List* pList)
{
	//将数据域置为空
	Link_Node* pNode = NULL;
	if(pList == NULL)
	{
		return;
	}
	//从尾部开始释放
	pNode = pList->trail;
	while(pNode != NULL)
	{
		pList->trail = pNode->priorNode;
		free(pNode);
		pNode = pList->trail;
	}
	pList->length = 0;
	pList->head = NULL;
	pList->trail = NULL;
}

/**
 * 功能:释放链表空间
 * 参数:
 *	pList:链表地址
 */
void Link_List_Free(Link_List* pList)
{
	Link_Node* pNode = NULL;
	if(pList == NULL)
	{
		return;
	}
	//从尾部开始释放
	pNode = pList->trail;
	while(pNode != NULL)
	{
		pList->trail = pNode->priorNode;
		free(pNode);
		pNode = pList->trail;
	}
	pList->length = 0;
	pList->head = NULL;
	pList->trail = NULL;
	free(pList);
	pList = NULL;
}


/**
 * 功能:Link_List测试
 */
void Link_List_Test()
{
	int i = 0;
	int *p = NULL;
	Link_List* list = Link_List_Init();
	//动态添加1000个值
	for(i = 0;i < 1000;i++)
	{
		p = (int*) malloc(sizeof(int));
		*p = i;
		Link_List_Insert(list,p,-1);
	}
	//取出第500个元素
	p = (int*)Link_List_GetAt(list,499);
	//删除第500个元素,删除之后记得释放
	Link_List_RemoveAt(list,499);
	free(p);
	//重新获取第500个元素
	p = (int*)Link_List_GetAt(list,499);
	//开始释放空间
	for(i = 0;i<list->length;i++)
	{
		p = (int*)Link_List_GetAt(list,i);
		free(p);
	}
	Link_List_Clear(list);
	Link_List_Free(list);
}



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言Link_List简单实现 的相关文章

  • Android颜色透明度十六进制表示法

    Android开发中经常会用到色值的透明度 比如要70 透明或者30 透明 这时候就有点犯难了 要么Google 要么借助PS等工具 其实都比较麻烦 下面将把0到100的透明度按照5 的梯度列出 方便收藏使用 其实在开发的过程中我们会经常遇
  • php字段验证规则,ThinkPHP 自动验证及验证规则详解

    ThinkPHP 自动验证及验证规则详解 ThinkPHP 自动验证 ThinkPHP 内置了数据对象的自动验证功能来完成模型的业务规则验证 自动验证是基于数据对象的 而大多情况下数据对象是基于 POST表单 不是绝对的 创建的 基本的自动
  • scrapy POST方式抓取走过的坑

    背景 今天老板让核查新上线的app中的中标数据展示情况 一条一条数据点开看实在是太慢了 于是想抓包获取app请求的api接口以及传入的参数 获取返回的数据内容 将数据存储到sqlite3中直接通过执行sql来统计数据质量 先打开fiddle

随机推荐

  • XSS quiz 1~5解题方案

    第1题 第一题很简单 没做过滤 直接可A过 第二题 查询框中写123查看源码 需要先闭合左边的input 所以 gt 即可 第三题 本题有过滤当输入 gt 时发现引号 尖括号都被过滤 lt gt 分别变成了转义符 尝试Unicode编码也未
  • antd Table中显示图片

  • qt 里面使用webengine

    qt使用webengine 条件 qt在windows上使用webengine必须用visual studio 使用mingw无效 webengine可以集成我们得html5页面 这样可以让界面开发人员更加省心 code 1 包含qwebe
  • YouTube上的版权保护

    早在2007年的时候 我曾写过一篇名为 YouTube The Big Copyright Lie YouTube 关于版权的弥天大谎 的文章 表达了我对YouTube又爱又恨的情感纠结 现在回想一下你在YouTube上看过的所有视频 它们
  • TabLayout+ViewPager+Fragment自定义tab添加小红点(kotlin事例)

    首先看哈效果 下面是两个布局 一个主布局 一个tab的布局 主布局很简单tablayout viewpager
  • Java制作JDK8文档搜索引擎项目并部署到阿里云服务器

    背景介绍 对于一个网站来说 搜索引擎需要提前预备好很多很多的静态资源 当用户输入查询的关键词的时候根据这些关键词来模糊查询匹配对应的资源 然后将这些资源展示给用户即可 搜索核心思路 互联网上主要是依赖于爬虫程序 它们可以极大效率的利用互联网
  • 视觉SLAM前端——直接法

    目录 直接法介绍 单层直接法 多层直接法 直接法介绍 这里所说的直接法不同于上一篇所说的LK光流法 LK光流是首先要选取特征点 如何利用特征点附近的光流进行路标的追踪与位姿的求解的 其本质还是先得到匹配好的点对 然后利用点对进行位姿估计 而
  • Matlab处理心电信号遇到的问题

    1 如何保存 Mat文件 运行上面的代码 在工作区会生成M mat文件 右键可以选择另存为 存到你想存的地址下面 2 得到了波形图和mat文件 然后对这个心电图进行滤波 该怎么处理 最笨的方法就是把 mat文件保存 另外再读取滤波 或者可以
  • Elasticsearch顶尖高手系列:核心知识篇(一)

    目录 1 第1 4节 第01节 课程介绍 第02节 什么是Elasticsearch 第03节 Elasticsearch的功能 适用场景以及特点介绍 第04节 Elasticsearch核心概念 NRT 索引 分片 副本等 2 第5 23
  • 极品开源工具,高糊照片有救了~

    今天给大家安利一款非常好用的AI图片修复工具 甭管你是模糊不清的老照片 还是高糊的表头包 头像 它统统都能帮你变成高清 效果那是嘎嘎攒劲 用过都说好 Upscayl 电脑 软件已在Github开源 版本齐全 Windows MacOS Li
  • 图的深度优先遍历

    深度优先搜素 Depth First Search DFS 是最常见的图的搜索之一 深度优先搜索沿着一条路径一直搜索下去 在无法搜索时 返回到刚刚访问的节点 深度优先的特征是 后被访问的节点 其领接点先被访问 根据深度优先遍历的特征 后来者
  • OSPF 详细总结。陆续更新

    OSPF 1 什么是OSPF OSPF 开放式最短路径优先 是一个基于链路状态进行路由计算的动态路由协议 主要用于大中型网络 2 OSPF的特点 不仅可以在一台路由器上运行多种OSPF路由进程 还可以把一个AS 自治系统 划分成多个不通的A
  • Java设计一个学生类Student,包含的属性有name和年龄age

    由学生类派生出本科生类Undergraduate和研究生类Postgraduate 本科生类包含的属性由专业specialty 研究生包含的属性有研究方向studydirection 重写Student类中的displayInformati
  • 安装Google Blockly Developer Tools离线版

    1 Blockly Developer Tools Demo在线版 https blockly demo appspot com static demos toolbox index html 注意 国内可能被墙导致该网址访问不了 可按如下
  • 物联网LoRa系列-18:LoRa终端Sx1262芯片内部高频电信号到中频电信号的变换(混频和变频)

    我们已经拆解了天线是如何发送和接收空中的高频无线电磁波信号 拆解了无线终端如何对射频前端的高频电信号进行进一步处理的 还拆解了无线终端的发送和接收如何分时复用天线的半双工模式 我们还拆解无线终端是如何对高频射频电信号进行进一步的处理 包括发
  • linux kvm 的虚拟机处于暂停状态怎么开机 和 KVM-Virsh指令

    root ok home virsh list Id Name State 1 13svn running 2 14git running 3 12c running 4 15samba running 5 win7
  • 地信

    准备 用的是qgis desktop 3 12 0 官网上下载即可 打开后页面 语言要修改成中文 setting option第一栏 算土地利用类型 双击新建项目 在浏览界面寻找双击打开自己要处理的数据 显示在图层中 图层可以上下拖动调整显
  • IT校招指南——超实用

    http blog csdn net liuqiyao 01 article details 26567237
  • JAVA方法(函数)的概念

    JAVA中函数的概念 什么是函数 答 函数英文称function 单一或相关联功能用来实现指定 要求功能的代码块 就是函数 函数在项目组可以直接进行调用且实现独立的功能 应对不同的实现需求的各种实现方法 就被称为函数 但主函数只有一个 主函
  • C语言Link_List简单实现

    C语言Link List简单实现 不做线程控制 Link List h 作者 代浩然 时间 2017 8 2 该文件定义为非线性链表相关的实现 线性链表的特性 1 在内存中的存放地址是非连续的 随机分配 优点 1 由于地址的非连续性 所以我