通用链表实现(参考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 ...
随机推荐
- CXF整合Spring发布WebService实例
一.说明: 上一篇简单介绍了CXF以及如何使用CXF来发布一个简单的WebService服务,并且介绍了客户端的调用. 这一篇介绍如何使用CXF与spring在Web项目中来发布WebService服 ...
- Determining Equality of Objects
[Determining Equality of Objects] If you need to determine whether one object is the same as another ...
- NSLog中的%@
[NSLog中的%@] There is one additional substitution token available in Objective-C, %@, used to denote ...
- django 命名空间详解
include(module[, namespace=None, app_name=None ]) include(pattern_list) include((pattern_list, app_n ...
- sql中获得时间的参数
(----我错了,以下非php.php用例:FORM_UNIXTIME($time, '%H')取小时数.---) 返回表示指定日期的指定日期部分的整数. 语法 DATEPART ( datepart ...
- enumerate
enumerate 函数用于遍历序列中的元素并分配一个序号(序号默认从零开始 可以制定任意值): >>> for i,j in enumerate(('a','b','c')): p ...
- Android - 应用名称设置的问题
今天我想修改我的android应用名称,就是手机桌面上图标下面的名称,根据我的理解我修改AndroidManifest.xml文件中application标签中的android:label=" ...
- redis 重用命令
一. set 1.smembers key 查看所有元素
- iisapp 命令 弹出 iisschlp.wsc [88,25] 属性值无效 progid
iisapp 命令 弹出 iisschlp.wsc [88,25] 属性值无效 progid 在执行iisapp.vbs时,可能会提示如下错误:Windows Script Component - f ...
- 免费的天气Web Service接口
免费的天气Web Service接口 在android应用当中很多时候需要获取天气的信息,这里提供怎么获取天气信息: 1. http://www.ayandy.com/Service.asmx?wsd ...