通用链表实现(参考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 ...
随机推荐
- webrtc--AudioProcessing的使用
1.AudioProcessing的实例化和配置: AudioProcessing* apm = AudioProcessing::Create(0); apm->level_estimator ...
- oracle 去掉空格
trim(value) 去掉左右空格 ltrim(value) 去掉左空格 rtrim(value) 去掉右空格
- Terrain & Light & Camera
[Terrain Engine] 1.When you press F, wherever your mouse is positioned will be moved to the center o ...
- POJ 2653 Pick-up sticks(判断线段相交)
Pick-up sticks Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 7699 Accepted: 2843 De ...
- Samsung Galaxy S II GT-I9100 指令全集 部分指令请慎用
英文版 谷歌翻译 Obtain/Change Device Information *#06# (Display IMEI number) *#1234# (Display current firmw ...
- UIView UITableView 背景图片添加
这几天,经常用到为某个视图设置背景图片,而API中UIView没有设置背景图片的方法,搜集归纳如下: 第一种方法: 利用的UIView的设置背景颜色方法,用图片做图案颜色,然后传给背景颜色. UICo ...
- HDU 5164Matching on Array(AC自动机)
这是BC上的一道题,当时比赛没有做,回头看看题解,说是AC自动机,想着没有写过AC自动机,于是便试着抄抄白书的模板,硬是搞了我数个小时2000ms时限1800过了= = ! 这里就直接贴上BC的结题报 ...
- Minus-C 一个最小化的C语言规范
资深C++程序员都不会对C++编程规范太陌生,C++实在太复杂,以至于所有项目都需要裁剪一个子集共项目组内使用.经过在家休息这一小段时间,我发现其实C语言更需要一个相同的规范,这就是本文的目标,最大可 ...
- [转]ViewPager onPageChangeListener总结
android ViewPager滑动事件讲解 首先ViewPager在处理滑动事件的时候要用到OnPageChangeListener OnPageChangeListener这个接口需要实现三个方 ...
- ADO与ADO.NET的区别
ADO是使用ole db接口并基于微软的COM技术,ADO.NET使用自己的ADO.NET接口并基于微软的.NET体系架构,所以ADO.NET与ADO是两种数据访问方式. ADO以recordset存 ...