本文提供一种C语言双向链表的通用接口,且均使用宏描述,故仅需包含头文件。该接口在实际应用中使用更方便、灵活。
一、基本结构![在这里插入图片描述](https://img-blog.csdnimg.cn/0f67570e46ad40539ee62f3a0764853e.png)
BASE结点
:即链表的结构体,主要记录链表的 第一个(start) 和 最后一个(end) 结点指针。
结点n
:用户定义的结构体,除了数据外还需要包含 指针域(link),用于双向链表的连接。
二、结点定义方法
1. BASE结点
#define LIST_BASE_NODE_T(TYPE)\
struct\
{\
unsigned int count;\
TYPE* start;\
TYPE* end;\
}
count为该链表的结点总数,实际应用场景经常会用到。
2. 结点指针域
#define LIST_NODE_T(TYPE)\
struct\
{\
TYPE* prev;\
TYPE* next;\
}
示例
此刻有结构体 test_node_t
:
typedef struct test_node_struct test_node_t;
struct test_node_struct
{
int value;
};
仅需要为其添加指针域,以及链表的定义,以便使用后面封装的接口。
typedef struct test_node_struct test_node_t;
struct test_node_struct
{
int value;
LIST_NODE_T(test_node_t) link;
};
typedef LIST_BASE_NODE_T(test_node_t) test_list_t;
注:可以添加多个指针域link1、link2…以便该结点可以同时存在于多个链表中。
三、基本操作接口
1. ADD FIRST
/* 添加结点N到链表的第一个 */
#define LIST_ADD_FIRST(LINK, BASE, N)\
do\
{\
(BASE).count++;\
/* 初始化指针域 */\
(N)->LINK.prev = NULL;\
(N)->LINK.next = (BASE).start;\
/* 如果start存在, 设置N为它的prev */\
if ((BASE).start)\
{\
(BASE).start->LINK.prev = (N);\
}\
/* 如果start不存在, 要设置N为end, 最后设置N为start */\
else\
{\
(BASE).end = (N);\
}\
(BASE).start = (N);\
} while (0)
2. ADD LAST
/* 添加结点N到链表的最后一个 */
#define LIST_ADD_LAST(LINK, BASE, N)\
do\
{\
(BASE).count++;\
/* 初始化指针域 */\
(N)->LINK.prev = (BASE).end;\
(N)->LINK.next = NULL;\
/* 如果end存在, 设置N为它的next */\
if ((BASE).end)\
{\
(BASE).end->LINK.next = (N);\
}\
/* 如果end不存在, 要设置N为start, 最后设置N为end */\
else\
{\
(BASE).start = (N);\
}\
(BASE).end = (N);\
} while (0)
3. INSERT BEFORE
/* 插入结点N到结点NODE的前面 */
#define LIST_INSERT_BEFORE(LINK, BASE, NODE, N)\
do\
{\
(BASE).count++;\
/* 初始化指针域 */\
(N)->LINK.prev = (NODE)->LINK.prev;\
(N)->LINK.next = (NODE);\
/* 如果NODE的prev存在, 设置N为它的next */\
if ((NODE)->LINK.prev)\
{\
(NODE)->LINK.prev->LINK.next = (N);\
}\
/* 如果NODE的prev不存在, 要设置N为start, 最后设置N为NODE的prev */\
else\
{\
(BASE).start = (N);\
}\
(NODE)->LINK.prev = (N);\
} while (0)
4. INSERT AFTER
/* 插入N到结点NODE的后面 */
#define LIST_INSERT_AFTER(LINK, BASE, NODE, N)\
do\
{\
(BASE).count++;\
/* 初始化指针域 */\
(N)->LINK.prev = (NODE);\
(N)->LINK.next = (NODE)->LINK.next;\
/* 如果NODE的next存在, 设置N为它的prev */\
if ((NODE)->LINK.next)\
{\
(NODE)->LINK.next->LINK.prev = (N);\
}\
/* 如果NODE的next不存在, 要设置N为end, 最后设置N为NODE的next */\
else\
{\
(BASE).end = (N);\
}\
(NODE)->LINK.next = (N);\
} while (0)
5. REMOVE
/* 从链表中移除结点 */
#define LIST_REMOVE(LINK, BASE, N)\
do\
{\
(BASE).count--;\
/* 如果N的prev存在, 设置N的next为它的next */\
if ((N)->LINK.prev)\
{\
(N)->LINK.prev->LINK.next = (N)->LINK.next;\
}\
/* 如果N的prev不存在, 设置N的next为start */\
else\
{\
(BASE).start = (N)->LINK.next;\
}\
/* 如果N的next存在, 设置N的prev为它的prev */\
if (((N)->LINK).next)\
{\
(N)->LINK.next->LINK.prev = (N)->LINK.prev;\
}\
/* 如果N的next不存在, 设置N的prev为end */\
else\
{\
(BASE).end = (N)->LINK.prev;\
}\
/* 最后清空指针域 */\
(N)->LINK.prev = NULL;\
(N)->LINK.next = NULL;\
} while (0)
四、其他接口
/* 获取链表长度 */
#define LIST_GET_LEN(BASE) ((BASE).count)
/* 获取链表第一个结点 */
#define LIST_GET_FIRST(BASE) ((BASE).start)
/* 获取链表最后一个结点 */
#define LIST_GET_LAST(BASE) ((BASE).end)
/* 获取N的上一个结点 */
#define LIST_GET_PREV(LINK, N) ((N)->LINK.prev)
/* 获取N的下一个结点 */
#define LIST_GET_NEXT(LINK, N) ((N)->LINK.next)
/* 从头开始向后查找结点 */
#define LIST_SEARCH_FROM_FIRST(LINK, BASE, N, TEST)\
do\
{\
(N) = LIST_GET_FIRST(BASE);\
while (N)\
{\
if (TEST)\
break;\
(N) = LIST_GET_NEXT(LINK, N);\
}\
} while (0)
/* 从末尾开始向前查找结点 */
#define LIST_SEARCH_FROM_LAST(LINK, BASE, N, TEST)\
do\
{\
(N) = LIST_GET_LAST(BASE);\
while (N)\
{\
if (TEST)\
break;\
(N) = LIST_GET_PREV(LINK, N);\
}\
} while (0)
/* 从结点NODE开始向前查找结点 */
#define LIST_SEARCH_BEFORE_NODE(LINK, BASE, NODE, N, TEST)\
do\
{\
(N) = (NODE);\
while (N)\
{\
if (TEST)\
break;\
(N) = LIST_GET_PREV(LINK, N);\
}\
} while (0)
/* 从结点NODE开始向后查找结点 */
#define LIST_SEARCH_AFTER_NODE(LINK, BASE, NODE, N, TEST)\
do\
{\
(N) = (NODE);\
while (N)\
{\
if (TEST)\
break;\
(N) = LIST_GET_NEXT(LINK, N);\
}\
} while (0)
测例
#include "list.h"
#include <assert.h>
typedef struct node_struct node_t;
struct node_struct
{
int value;
LIST_NODE_T(node_t) link1;
LIST_NODE_T(node_t) link2;
};
typedef LIST_BASE_NODE_T(node_t) list_t;
void test_list()
{
const int num = 1000;
int i;
node_t* n;
node_t* n1;
node_t* n2;
node_t* n_prev;
node_t* n_next;
node_t* n249;
node_t* n499;
node_t* n500;
node_t* n750;
list_t L1 = { 0 }, L2 = { 0 };
/* 申请, 按顺序添加到L1 */
for (i = 0; i < num; i++)
{
n = malloc(sizeof(node_t));
assertx(n);
n->value = i;
LIST_ADD_LAST(link1, L1, n);
}
/* 向后遍历L1, 找到结点249 */
LIST_SEARCH_FROM_FIRST(link1, L1, n249, n249->value == 249);
/* 向前遍历L1, 找到结点750 */
LIST_SEARCH_FROM_LAST(link1, L1, n750, n750->value == 750);
/* 从结点249向后遍历L1, 找到结点499 */
LIST_SEARCH_AFTER_NODE(link1, L1, n249, n499, n499->value == 499);
/* 从结点750向前遍历L1, 找到结点500 */
LIST_SEARCH_BEFORE_NODE(link1, L1, n750, n500, n500->value == 500);
assert(n499 && n500 && LIST_GET_NEXT(link1, n499) == n500 && LIST_GET_PREV(link1, n500) == n499);
/* 从结点249往前, 逐个添加到L2开始(0-249) */
n = n249;
while (n)
{
LIST_ADD_FIRST(link2, L2, n);
n = LIST_GET_PREV(link1, n);
}
/* 从结点750往后, 逐个添加到L2最后(750-999) */
n = n750;
while (n)
{
LIST_ADD_LAST(link2, L2, n);
n = LIST_GET_NEXT(link1, n);
}
/* 从结点250开始, 直到结点499, 逐个插入到L2(250-499) */
n = n249;
do
{
n_prev = n;
n = LIST_GET_NEXT(link1, n);
LIST_INSERT_AFTER(link2, L2, n_prev, n);
} while (n != n499);
/* 从结点749开始, 直到结点500, 逐个插入到L2(500-749) */
n = n750;
do
{
n_next = n;
n = LIST_GET_PREV(link1, n);
LIST_INSERT_BEFORE(link2, L2, n_next, n);
} while (n != n500);
assert(LIST_GET_LEN(L1) == num && LIST_GET_LEN(L2) == num);
/* 验证L1和L2中结点顺序是否一致 */
n1 = LIST_GET_FIRST(L1);
n2 = LIST_GET_FIRST(L2);
while (n1 && n2)
{
assertx(n1->value == n2->value);
n1 = LIST_GET_NEXT(link1, n1);
n2 = LIST_GET_NEXT(link2, n2);
}
/* 从L1中移除所有结点 */
n = LIST_GET_FIRST(L1);
while (n)
{
LIST_REMOVE(link1, L1, n);
n = LIST_GET_FIRST(L1);
}
/* 释放 */
n = LIST_GET_LAST(L2);
while (n)
{
LIST_REMOVE(link2, L2, n);
free(n);
n = LIST_GET_LAST(L2);
}
return;
}
源码(list.h)
/**************************************************************
文件:
list.h
目的:
提供双向链表的方法和接口
接口:
LIST_BASE_NODE_T 定义链表类型
LIST_NODE_T 定义链表结点的指针域
LIST_INIT 链表初始化
LIST_NODE_INIT 结点初始化
LIST_ADD_FIRST 添加到链表的第一个
LIST_ADD_LAST 添加到链表的最后一个
LIST_INSERT_BEFORE 插入到结点之前
LIST_INSERT_AFTER 插入到结点之后
LIST_REMOVE 从链表中移除结点
LIST_GET_LEN 获取链表长度
LIST_GET_FIRST 获取链表第一个结点
LIST_GET_LAST 获取链表最后一个结点
LIST_GET_PREV 获取上一个结点
LIST_GET_NEXT 获取下一个结点
LIST_SEARCH_FROM_FIRST 从头开始向后查找结点
LIST_SEARCH_FROM_LAST 从末尾开始向前查找结点
LIST_SEARCH_BEFORE_NODE 从结点NODE开始向前查找结点
LIST_SEARCH_AFTER_NODE 从结点NODE开始向后查找结点
**************************************************************/
#ifndef LIST_H
#define LIST_H
/* 说明: 用于定义链表类型 */
#define LIST_BASE_NODE_T(TYPE)\
struct\
{\
unsigned int count;\
TYPE* start;\
TYPE* end;\
}
/* 说明: 用于定义指针域 */
#define LIST_NODE_T(TYPE)\
struct\
{\
TYPE* prev;\
TYPE* next;\
}
/* 初始化链表 */
#define LIST_INIT(BASE)\
do\
{\
(BASE).count = 0;\
(BASE).start = NULL;\
(BASE).end = NULL;\
} while (0)
/* 初始化结点的指针域 */
#define LIST_NODE_INIT(LINK, N)\
do\
{\
(N)->LINK.prev = NULL;\
(N)->LINK.next = NULL;\
} while (0)
/* 添加结点N到链表的第一个 */
#define LIST_ADD_FIRST(LINK, BASE, N)\
do\
{\
(BASE).count++;\
/* 初始化指针域 */\
(N)->LINK.prev = NULL;\
(N)->LINK.next = (BASE).start;\
/* 如果start存在, 设置N为它的prev */\
if ((BASE).start)\
{\
(BASE).start->LINK.prev = (N);\
}\
/* 如果start不存在, 要设置N为end, 最后设置N为start */\
else\
{\
(BASE).end = (N);\
}\
(BASE).start = (N);\
} while (0)
/* 添加结点N到链表的最后一个 */
#define LIST_ADD_LAST(LINK, BASE, N)\
do\
{\
(BASE).count++;\
/* 初始化指针域 */\
(N)->LINK.prev = (BASE).end;\
(N)->LINK.next = NULL;\
/* 如果end存在, 设置N为它的next */\
if ((BASE).end)\
{\
(BASE).end->LINK.next = (N);\
}\
/* 如果end不存在, 要设置N为start, 最后设置N为end */\
else\
{\
(BASE).start = (N);\
}\
(BASE).end = (N);\
} while (0)
/* 插入结点N到结点NODE的前面 */
#define LIST_INSERT_BEFORE(LINK, BASE, NODE, N)\
do\
{\
(BASE).count++;\
/* 初始化指针域 */\
(N)->LINK.prev = (NODE)->LINK.prev;\
(N)->LINK.next = (NODE);\
/* 如果NODE的prev存在, 设置N为它的next */\
if ((NODE)->LINK.prev)\
{\
(NODE)->LINK.prev->LINK.next = (N);\
}\
/* 如果NODE的prev不存在, 要设置N为start, 最后设置N为NODE的prev */\
else\
{\
(BASE).start = (N);\
}\
(NODE)->LINK.prev = (N);\
} while (0)
/* 插入N到结点NODE的后面 */
#define LIST_INSERT_AFTER(LINK, BASE, NODE, N)\
do\
{\
(BASE).count++;\
/* 初始化指针域 */\
(N)->LINK.prev = (NODE);\
(N)->LINK.next = (NODE)->LINK.next;\
/* 如果NODE的next存在, 设置N为它的prev */\
if ((NODE)->LINK.next)\
{\
(NODE)->LINK.next->LINK.prev = (N);\
}\
/* 如果NODE的next不存在, 要设置N为end, 最后设置N为NODE的next */\
else\
{\
(BASE).end = (N);\
}\
(NODE)->LINK.next = (N);\
} while (0)
/* 从链表中移除结点 */
#define LIST_REMOVE(LINK, BASE, N)\
do\
{\
(BASE).count--;\
/* 如果N的prev存在, 设置N的next为它的next */\
if ((N)->LINK.prev)\
{\
(N)->LINK.prev->LINK.next = (N)->LINK.next;\
}\
/* 如果N的prev不存在, 设置N的next为start */\
else\
{\
(BASE).start = (N)->LINK.next;\
}\
/* 如果N的next存在, 设置N的prev为它的prev */\
if (((N)->LINK).next)\
{\
(N)->LINK.next->LINK.prev = (N)->LINK.prev;\
}\
/* 如果N的next不存在, 设置N的prev为end */\
else\
{\
(BASE).end = (N)->LINK.prev;\
}\
/* 最后清空指针域 */\
(N)->LINK.prev = NULL;\
(N)->LINK.next = NULL;\
} while (0)
/* 获取链表长度 */
#define LIST_GET_LEN(BASE) ((BASE).count)
/* 获取链表第一个结点 */
#define LIST_GET_FIRST(BASE) ((BASE).start)
/* 获取链表最后一个结点 */
#define LIST_GET_LAST(BASE) ((BASE).end)
/* 获取N的上一个结点 */
#define LIST_GET_PREV(LINK, N) ((N)->LINK.prev)
/* 获取N的下一个结点 */
#define LIST_GET_NEXT(LINK, N) ((N)->LINK.next)
/* 从头开始向后查找结点 */
#define LIST_SEARCH_FROM_FIRST(LINK, BASE, N, TEST)\
do\
{\
(N) = LIST_GET_FIRST(BASE);\
while (N)\
{\
if (TEST)\
break;\
(N) = LIST_GET_NEXT(LINK, N);\
}\
} while (0)
/* 从末尾开始向前查找结点 */
#define LIST_SEARCH_FROM_LAST(LINK, BASE, N, TEST)\
do\
{\
(N) = LIST_GET_LAST(BASE);\
while (N)\
{\
if (TEST)\
break;\
(N) = LIST_GET_PREV(LINK, N);\
}\
} while (0)
/* 从结点NODE开始向前查找结点 */
#define LIST_SEARCH_BEFORE_NODE(LINK, BASE, NODE, N, TEST)\
do\
{\
(N) = (NODE);\
while (N)\
{\
if (TEST)\
break;\
(N) = LIST_GET_PREV(LINK, N);\
}\
} while (0)
/* 从结点NODE开始向后查找结点 */
#define LIST_SEARCH_AFTER_NODE(LINK, BASE, NODE, N, TEST)\
do\
{\
(N) = (NODE);\
while (N)\
{\
if (TEST)\
break;\
(N) = LIST_GET_NEXT(LINK, N);\
}\
} while (0)
#endif