通用链表实现(参考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 ...
随机推荐
- tomcat 粗略笔记
GlobalNamingResources 存在于server.xml中,定义全局公共数据源,如果host中有大量引用相同的数据源,那么可以都配在这里 <GlobalNamingResource ...
- 常见mongo命令
@(编程) 查询 db.getCollection('SalaryEntity').find({"Month" : "201601"}) db.getColle ...
- hdu 5025 Saving Tang Monk(bfs+状态压缩)
Description <Journey to the West>(also <Monkey>) is one of the Four Great Classical Nove ...
- HDU 4493 Tutor (控制精度)
题意:给定12个数,求平均数. 析:这个题就是精度控制问题,如果控制精度,最好的办法就是用整型了. 代码如下: #include <cstdio> #include <string& ...
- 用完成例程(Completion Routine)实现的重叠I/O模型
/// 用完成例程(Completion Routine)实现的重叠I/O模型 /// 异步IO模型 /// 用完成例程来实现重叠I/O比用事件通知简单得多.在这个模型中,主线程只用不停的接受连接 / ...
- button 禁止
1.按钮的id为btnzhuce==> 控制按钮为禁用: $("#btnzhuce").attr({"disabled":"disabled& ...
- A*算法为什么是最优的
图搜索的A*算法有两种情况: hn是可采纳的,但是不是满足一致性 如果满足一致性,A*算法的实现要简单一些:即使不检查closed节点的状态重复,也能得到最优的结果 下面是证明最优性的一些关键点: 1 ...
- 利用HTML5开发Android(1)---Android设备多分辨率的问题
Android浏览器默认预览模式浏览 会缩小页面 WebView中则会以原始大小显示 Android浏览器和WebView默认为mdpi.hdpi相当于mdpi的1.5倍 ldpi相当于0.75倍 三 ...
- .NET开发中的事务处理大比拼
本文转载:http://www.cnblogs.com/jhxk/articles/2696307.html http://liubaolongg.blog.163.com/blog/static/2 ...
- cocos2d-x 2.2 资源更新AssetsManager例子代码
转自:http://www.58player.com/blog-2327-601.html // // UpgradeLayer.h // AmazeDemo // // Created by lsw ...