通用链表实现(参考Linux List)
最近参考Linux实现的通用双向链表时,因typeof并不是标准c规定的关键字,除GCC编译器外其他编译器未必支持typeof关键字,所以在使用上并不能想Linux所实现的链表哪样灵活,它要求将连接器即链表结构作为用户自定义结构体的第一个元素使用,话不多说,直接上代码,内嵌详细注释。
IList.h
#ifndef _I_LIST_H_2012_11_23_
#define _I_LIST_H_2012_11_23_ #ifdef __cplusplus
extern "C" {
#endif /** \brief 双向链表连接器
* \details 实现用户自定义结构链表的连接器的结构定义,使用注意事项:
1. 务必将其嵌入到用户自定义结构体元素的顶端;
2. 务必使用结构类型而非其指针类型嵌入到用户自定义结构体
* \typedef typedef struct _IList IList,*pIList
*/
typedef struct _IList
{
struct _IList *_prev;
struct _IList *_next;
}IList, *pIList; /**
\brief 遍历链表所有节点
\details 遍历链表所有节点,在遍历过程中,请勿执行添加、删除操作 \param[in] pList 链表对象
\param[out] pLink 节点
*/
#define IList_Foreach(pList, pos) \
for ( \
pos = pos = (pList)->_next; \
pos != (pList); \
pos = pos->_next \
) /**
\brief 遍历链表所有节点
\details 安全遍历链表所有节点,在遍历过程中,可以删除节点 \param[in] pList 链表对象
\param[out] pLink 节点
*/
#define IList_Foreach_Salf(pList, temp, pos) \
for ( \
pos = (pList)->_next, temp = pos->_next; \
pos != (pList); \
pos = temp, temp = pos->_next\
) /**
\brief 链表初始化 \param[in] pList 链表对象
*/
void IList_Init(pIList pList); /**
\brief 插入新节点
\details 将新节点插入链表指定节点之前 \param[in] pList 链表对象
\param[in] pLink 指定节点
\param[in] pNewLink 带插入节点
*/
void IList_Insert(pIList pLink, pIList pNewLink); /**
\brief 插入新节点至链表尾部 \param[in] pList 链表对象
\param[in] pLink 指定节点
\param[in] pNewLink 带插入节点
*/
void IList_Append(pIList pList, pIList pNewLink); /**
\brief 插入新节点至链表尾头部 \param[in] pList 链表对象
\param[in] pLink 指定节点
\param[in] pNewLink 带插入节点
*/
void IList_Prepend(pIList pList, pIList pNewLink); /**
\brief 删除指定节点 \param[in] pList 链表对象
\param[in] pLink 带删除的节点
*/
void IList_Remove(pIList pLink); /**
\brief 获取表头节点 \param[in] pList 链表对象 \return NULL: 链表为空
其他: 表头节点地址
*/
pIList IList_Head(pIList pList); /**
\brief 获取表尾节点 \param[in] pList 链表对象 \return NULL: 链表为空
其他: 表尾节点地址
*/
pIList IList_Tail(pIList pList); /**
\brief 检测链表是否为空 \param[in] pList 链表对象 \return 0: 链表非空
1: 链表为空
*/
int IList_IsEmpty(pIList pList);
/**
\brief 获取链表节点数 \param[in] pList 链表对象 \return 链表节点数
*/
int IList_Size(pIList pList); /**
\brief 获取指定节点的后一节点 \param[in] pList 链表对象
\param[in] pLink 指定的节点 \return NULL: 指定节点为尾节点
其他: 指定节点后一节点地址
*/
pIList IList_Next(pIList pList, pIList pLink); /**
\brief 获取指定节点的前一节点 \param[in] pList 链表对象
\param[in] pLink 指定的节点 \return NULL: 指定节点为头节点
其他: 指定节点前一节点地址
*/
pIList IList_Prev(pIList pList, pIList pLink); /**
\brief 获取链表中第index个节点 \param[in] pList 链表对象
\param[in] index 节点序号,从1计数 \return NULL: 指定序号无节点
其他: 链表中第index所对应的节点
*/
pIList IList_Nth(pIList pList, int index); /**
\brief 获取链表中指定节点的序号 \param[in] pList 链表对象
\param[in] pLink 指定节点 \return NULL: 指定序号无节点
其他: 链表中第index所对应的节点
*/
int IList_Find(pIList pList, pIList pLink); #ifdef __cplusplus
}
#endif #endif//_I_LIST_H_2012_11_23_
IList.c
#include <stdio.h>
#include "iList.h" void IList_Init(pIList pList)
{
pList->_prev = pList;
pList->_next = pList;
} void IList_Insert(pIList pLink, pIList pNewLink)
{
pNewLink->_prev = pLink->_prev;
pNewLink->_next = pLink;
pNewLink->_prev->_next = pNewLink;
pNewLink->_next->_prev = pNewLink;
} void IList_Append(pIList pList, pIList pNewLink)
{
IList_Insert(pList, pNewLink);
} void IList_Prepend(pIList pList, pIList pNewLink)
{
IList_Insert(pList->_next, pNewLink);
} void IList_Remove(pIList pLink)
{
pLink->_prev->_next = pLink->_next;
pLink->_next->_prev = pLink->_prev;
} pIList IList_Head(pIList pList)
{
return pList->_next != pList ? pList->_next : NULL;
} pIList IList_Tail(pIList pList)
{
return pList->_prev != pList ? pList->_prev : NULL;
} int IList_IsEmpty(pIList pList)
{
return pList->_next == pList;
} int IList_Size(pIList pList)
{
int count = ;
pIList temp = NULL; if (pList->_next == pList)
return ; IList_Foreach(pList, temp)
{
count ++;
} return count;
} pIList IList_Next(pIList pList, pIList pLink)
{
return pLink->_next != pList ? pLink->_next : NULL;
} pIList IList_Prev(pIList pList, pIList pLink)
{
return pLink->_prev != pList ? pLink->_prev : NULL;
} pIList IList_Nth(pIList pList, int index)
{
pIList pLink = NULL;
int count = ; IList_Foreach(pList, pLink)
{
count ++;
if (count == index)
return pLink;
} return NULL;
} int IList_Find(pIList pList, pIList pLink)
{
pIList pTemp = NULL;
int index = ; pTemp = IList_Head(pList); while ((pTemp != NULL) && (pTemp != pLink))
{
index++;
pTemp = IList_Next(pList, pTemp);
} if (pTemp == NULL)
return (-);
else
return (index);
}
IListTest.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "iList.h" typedef struct _Student
{
IList _list; int _id;
char *name;
}Student, *pStudent; int main(int argc, char *argv[])
{
int i = ;
int num = ;
int count = ;
pStudent temp= NULL;
pIList list, link; if (argc > )
num = atoi(argv[]); list = (IList *)malloc(sizeof(IList));
if (!list)
{
printf("Error in malloc.\n");
return -;
}
memset(list, , sizeof(IList)); IList_Init(list);
for (i = ; i < num; i ++)
{
temp = malloc(sizeof(Student));
if (!temp)
return -;
memset(temp, , sizeof(Student));
temp->_id = i + ;
IList_Append(list, &temp->_list);
//IList_Prepend(list, &temp->_list);
} IList_Foreach(list, link)
{
temp = (pStudent)link;
printf("%d\t", temp->_id);
}
printf("\n"); printf("Input the num(1 ~ %d) that you want to:\n", IList_Size(list));
scanf("%d", &count);
link = IList_Nth(list, count);
printf("Num %d id: %d\n", count, ((pStudent)link)->_id);
printf("Id %d num: %d\n", ((pStudent)link)->_id, IList_Find(list, link)); printf("List count: %d\n", IList_Size(list));
/*for (link = IList_Head(list);!IList_IsEmpty(list);)
{
pIList tLink = link;
link = IList_Next(list, link);
IList_Remove(tLink);
free(tLink);
}*/
do
{
pIList n, pos;
IList_Foreach_Salf(list, n, pos)
{
IList_Remove(pos);
free(pos);
}
} while ();
printf("List count: %d\n", IList_Size(list)); free(list); return ;
}
通用链表实现(参考Linux List)的更多相关文章
- 通用双向链表的设计(参考Linux系统中的实现)
通常我们设计设计链表都是将数据域放在里面,这样每次需要使用链表的时候都需要实现一个链表,然后重新实现它的相关操作,这里参考Linux系统中的设计实现了一个通用的双向链表,只需要在你的结构里面有一个这个 ...
- 拒绝造轮子!如何移植并使用Linux内核的通用链表(附完整代码实现)
在实际的工作中,我们可能会经常使用链表结构来存储数据,特别是嵌入式开发,经常会使用linux内核最经典的双向链表 list_head.本篇文章详细介绍了Linux内核的通用链表是如何实现的,对于经常使 ...
- C语言实现通用链表初步(一)
注意:本文讨论的是无头单向非循环链表. 假设不采用Linux内核链表的思路,怎样用C语言实现通用链表呢? 一种常用的做法是: typedef int element_t; struct node_in ...
- C 封装一个通用链表 和 一个简单字符串开发库
引言 这里需要分享的是一个 简单字符串库和 链表的基库,代码也许用到特定技巧.有时候回想一下, 如果我读书的时候有人告诉我这些关于C开发的积淀, 那么会走的多直啊.刚参加工作的时候做桌面开发, 服务是 ...
- Linux内核链表-通用链表的实现
最近编程总想着参考一些有名的开源代码是如何实现的,因为要写链表就看了下linux内核中对链表的实现. 链表是一种非常常见的数据结构,特别是在动态创建相应数据结构的情况下更是如此,然而在操作系统内核中, ...
- C语言实现通用链表初步(四)----双向链表
在前面的文章中,我们讨论了如何实现通用类型的链表,方法是用void *类型的指针,指向数据.那么还有其他的方法吗(不考虑内核链表)? 答案是肯定的.用零长数组也可以实现. struct node_in ...
- 链表的艺术——Linux内核链表分析
引言: 链表是数据结构中的重要成员之中的一个.因为其结构简单且动态插入.删除节点用时少的长处,链表在开发中的应用场景许多.仅次于数组(越简单应用越广). 可是.正如其长处一样,链表的缺点也是显而易见的 ...
- MySql通用二进制版本在Linux(Ubuntu)下安装与开启服务
安装mysql前可能需要其他软件的依赖,请先执行下面命令安装mysql的依赖软件 shell> apt-cache search libaio # search for info shell&g ...
- C语言实现通用链表初步(三)----单元测试
前两节,我们已经完成了链表的一些操作,快来测试一下吧. 这里使用的单元测试工具名字叫"check". START_TEST(my_slist_1) { struct student ...
随机推荐
- oracle 去掉空格
trim(value) 去掉左右空格 ltrim(value) 去掉左空格 rtrim(value) 去掉右空格
- 解决ehcache的UpdateChecker问题
问题描述 项目中用了ssh框架,每次启动tomcat的时候都特别慢,会在这样一句话下面停留很久 [2016-01-08 23:55:51,517 INFO UpdateChecker.java:doC ...
- c语言指针详解(转载)
转自(http://blog.csdn.net/ad_ad_ad/article/details/1522145) 指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最主要的风格之一.利用指 ...
- TcxGrid导出EXCEL
function ExportExcel(grid: TcxGrid; const fileName: string = '1.xls'): Boolean;var sd: TSaveDialog; ...
- 实时监控mysql数据库变化
对于二次开发来说,很大一部分就找找文件和找数据库的变化情况 对于数据库变化.还没有发现比较好用的监控数据库变化监控软件. 今天,我就给大家介绍一个如何使用mysql自带的功能监控数据库变化 1.打开数 ...
- 【Android框架进阶〖0〗】ThinkAndroid注解机制
由于项目需要,开始研究ThinkAndroid. 个人认为该框架的注解机制十分新颖,所以先研究这个,顺便学习下 Java 的annotation. 粗略的看了看,该机制在BaseActivity中初始 ...
- Odoo constraints 使用教程
在日常开发Odoo的过程中,我们不免要用到Constraints,中文就是约束. 首先我们来介绍下Odoo里面的两种Constraints. SQL Constraints:就是添加一个数据库的约束. ...
- uva 558 - Wormholes(Bellman Ford判断负环)
题目链接:558 - Wormholes 题目大意:给出n和m,表示有n个点,然后给出m条边,然后判断给出的有向图中是否存在负环. 解题思路:利用Bellman Ford算法,若进行第n次松弛时,还能 ...
- ASP.NET设置404页面返回302HTTP状态码的解决方法
在配置文件中配置404页面如下: .代码如下: <customErrors mode="On" defaultRedirect="404.aspx"> ...
- [p2p]UDP用打洞技术穿透NAT的原理与实现
首先先介绍一些基本概念: NAT(Network Address Translators),网络地址转换:网络地址转换是在IP地址日益缺乏的情况下产生的, ...