双向链表是一种基本的数据结构,在许多场合都会使用到。最近正在编写一个基于Linux的GUI系统,里边许多地方都要使用到双向链表,于是写了一个通用的双向链表。代码如下:
- #ifndef __STDLIST_H__
- #define __STDLIST_H__
- typedef struct tagSTDNODE STDNODE, *LPSTDNODE;
- typedef struct tagSTDLIST STDLIST, *LPSTDLIST;
- // 链表数据结构
- struct tagSTDNODE {
- LPSTDNODE lpPrev;
- LPSTDNODE lpNext;
- };
- // 链表节点结构
- struct tagSTDLIST {
- LPSTDNODE lpHead;
- LPSTDNODE lpTail;
- };
- // 用于链表扩展的宏
- #define NODE_INITIALIZER ((STDNODE){ .lpPrev = NULL, .lpNext = NULL, })
- #define LIST_INITIALIZER ((STDLIST){ .lpHead = NULL, .lpTail = NULL, })
- #define DECLARELISTNODE() STDNODE __snStdNode
- #define INIT_LISTNODE() __snStdNode = NODE_INITIALIZER
- // 初始化链表
- STATIC INLINE
- LPSTDLIST TWINAPI StdListInit(
- LPSTDLIST lpList
- ) {
- lpList->lpHead = NULL;
- lpList->lpTail = NULL;
- return lpList;
- }
- // 获取链表头部节点
- STATIC INLINE
- LPSTDNODE TWINAPI StdListGetHeadNode(
- LPSTDLIST lpList
- ) {
- return lpList->lpHead;
- }
- // 获取链表尾部节点
- STATIC INLINE
- LPSTDNODE TWINAPI StdListGetTailNode(
- LPSTDLIST lpList
- ) {
- return lpList->lpTail;
- }
- // 获取给定节点的下一个节点
- STATIC INLINE
- LPSTDNODE TWINAPI StdListGetNextNode(
- LPSTDNODE lpNode
- ) {
- return lpNode->lpNext;
- }
- // 获取给定节点的上一个节点
- STATIC INLINE
- LPSTDNODE TWINAPI StdListGetPrevNode(
- LPSTDNODE lpNode
- ) {
- return lpNode->lpPrev;
- }
- // 在链表头部插入一个节点
- STATIC INLINE
- VOID TWINAPI StdListPushFront(
- LPSTDLIST lpList,
- LPSTDNODE lpNode
- ) {
- lpNode->lpPrev = NULL;
- lpNode->lpNext = lpList->lpHead;
- if(lpList->lpHead)
- lpList->lpHead->lpPrev = lpNode;
- else
- lpList->lpTail = lpNode;
- lpList->lpHead = lpNode;
- }
- // 在链表尾部插入一个节点
- STATIC INLINE
- VOID TWINAPI StdListPushBack(
- LPSTDLIST lpList,
- LPSTDNODE lpNode
- ) {
- lpNode->lpNext = NULL;
- lpNode->lpPrev = lpList->lpTail;
- if(lpList->lpTail)
- lpList->lpTail->lpNext = lpNode;
- else
- lpList->lpHead = lpNode;
- lpList->lpTail = lpNode;
- }
- // 在指定节点后插入一个节点
- STATIC INLINE
- VOID TWINAPI StdListInsert(
- LPSTDLIST lpList,
- LPSTDNODE lpAfter,
- LPSTDNODE lpNode
- ) {
- if(lpAfter) {
- if(lpAfter->lpNext)
- lpAfter->lpNext->lpPrev = lpNode;
- else
- lpList->lpTail = lpNode;
- lpNode->lpPrev = lpAfter;
- lpNode->lpNext = lpAfter->lpNext;
- lpAfter->lpNext = lpNode;
- } else {
- StdListPushFront(lpList, lpNode);
- }
- }
- // 从链表头部弹出一个节点
- STATIC INLINE
- LPSTDNODE TWINAPI StdListPopFront(
- LPSTDLIST lpList
- ) {
- if(lpList->lpHead) {
- LPSTDNODE lpNode = lpList->lpHead;
- if(lpList->lpHead->lpNext)
- lpList->lpHead->lpNext->lpPrev = NULL;
- else
- lpList->lpTail = NULL;
- lpList->lpHead = lpList->lpHead->lpNext;
- lpNode->lpPrev = lpNode->lpNext = NULL;
- return lpNode;
- } else {
- return NULL;
- }
- }
- // 从链表尾部弹出一个节点
- STATIC INLINE
- LPSTDNODE TWINAPI StdListPopBack(
- LPSTDLIST lpList
- ) {
- if(lpList->lpTail) {
- LPSTDNODE lpNode = lpList->lpTail;
- if(lpList->lpTail->lpPrev)
- lpList->lpTail->lpPrev->lpNext = NULL;
- else
- lpList->lpHead = NULL;
- lpList->lpTail = lpList->lpTail->lpPrev;
- lpNode->lpPrev = lpNode->lpNext = NULL;
- return lpNode;
- } else {
- return NULL;
- }
- }
- // 从链表中删除给定节点
- STATIC INLINE
- LPSTDNODE TWINAPI StdListRemove(
- LPSTDLIST lpList,
- LPSTDNODE lpNode
- ) {
- if(lpNode->lpPrev)
- lpNode->lpPrev->lpNext = lpNode->lpNext;
- else
- lpList->lpHead = lpNode->lpNext;
- if(lpNode->lpNext)
- lpNode->lpNext->lpPrev = lpNode->lpPrev;
- else
- lpList->lpTail = lpNode->lpPrev;
- return lpNode;
- }
- // 检查链表是否为空
- STATIC INLINE
- BOOL TWINAPI StdListIsEmpty(
- LPSTDLIST lpList
- ) {
- if(lpList->lpHead || lpList->lpTail)
- return FALSE;
- else
- return TRUE;
- }
- // 获取链表中的节点数
- STATIC INLINE
- LONG TWINAPI StdListGetSize(
- LPSTDLIST lpList
- ) {
- LONG lnSize = 0;
- LPSTDNODE lpNode = StdListGetHeadNode(lpList);
- while(lpNode) {
- ++ lnSize;
- lpNode = StdListGetNextNode(lpNode);
- }
- return lnSize;
- }
- // 合并两个链表
- STATIC INLINE
- LPSTDLIST TWINAPI StdListCombine(
- LPSTDLIST lpList1,
- LPSTDLIST lpList2
- ) {
- if(!StdListIsEmpty(lpList2)) {
- if(!StdListIsEmpty(lpList1)) {
- lpList1->lpTail->lpNext = lpList2->lpHead;
- lpList2->lpHead->lpPrev = lpList1->lpTail;
- lpList1->lpTail = lpList2->lpTail;
- } else {
- lpList1->lpHead = lpList2->lpHead;
- lpList1->lpTail = lpList2->lpTail;
- }
- lpList2->lpHead = lpList2->lpTail = NULL;
- }
- return lpList1;
- }
- #endif//__STDLIST_H__
算法本身没有什么特别的地方,为什么说这是一个通用双向链表呢?奥妙就在那四个用于扩展的宏。利用这几个宏你可以将这个双向链表扩展到任意结构。
例如,我们要实现一个消息队列,那么我们可以这样定义消息节点:
- typedef struct tagMSGNODE {
- DECLARELISTNODE();
- HWND hWnd;
- UINT uMsg;
- WPARAM wParam;
- LPARAM lParam;
- } MSGNODE, *LPMSGNODE;
而消息队列则可以直接用LISTNODE结构来表示:
- STDLIST lstMsgQueue;
这样我们就可以用刚刚定义的函数来对这个消息队列进行操作了:
- // 向消息队列插入一个消息
- LPMSGNODE lpMsgNode = MemAlloc(SIZEOF(MSGNODE));
- lpMsgNode->INIT_LISTNODE();
- lpMsgNode->hWnd = hWnd;
- lpMsgNode->uMsg = WM_PAINT;
- lpMsgNode->wParam = NULL;
- lpMsgNode->lParam = NULL;
- StdListPushBack(&lstMsgQueue, (LPSTDNODE)lpMsgNode);
- // 从消息队列取出一个消息
- LPMSGNODE lpMsgNode = (LPMSGNODE)StdListPopFront(&lstMsgQueue);
- // 删除所有属于hWnd的消息
- LPMSGNODE lpTemp = (LPMSGNODE)StdListGetHeadNode(&lstMsgQueue);
- while(lpTemp) {
- LPMSGNODE lpNext = (LPMSGNODE)StdListGetNextNode(&lstMsgQueue, (LPSTDNODE)lpTemp);
- if(lpTemp->hWnd == hWnd) {
- StdListRemove(&lstMsgQueue, (LPSTDNODE)lpTemp);
- MemFree(lpTemp);
- }
- lpTemp = lpNext;
- }
是不是很方便呢^_^。
备注:
由于正在编写的GUI是参考Windows的体系结构,所以代码风格采用了微软的风格。
代码中的MemAlloc,MemFree函数以及各种数据结构均在其他地方定义。