//////////////////////////////////////////////////////////////////////////////////
//双链表简介
/////////////////////////////////////////////////////////////////////////////////
双链表
1、双向链表(Double Linked List)
双(向)链表中有两条方向不同的链,即每个结点中除next域存放后继结点地址外,还增加一个指向其直接前趋的指针域prior。
注意:
①双链表由头指针head惟一确定的。
②带头结点的双链表的某些运算变得方便。
③将头结点和尾结点链接起来,为双(向)循环链表。
2、双向链表的结点结构和形式描述
①结点结构(见上图a)
②形式描述
typedef struct dlistnode{
DataType data;
struct dlistnode *prior,*next;
}DListNode;
typedef DListNode *DLinkList;
DLinkList head;
3、双向链表的前插和删除本结点操作
由于双链表的对称性,在双链表能能方便地完成各种插入、删除操作。
①双链表的前插操作
void DInsertBefore(DListNode *p,DataType x)
{//在带头结点的双链表中,将值为x的新结点插入*p之前,设p≠NULL
DListNode *s=malloc(sizeof(DListNode));//①
s->data=x;//②
s->prior=p->prior;//③
s->next=p;//④
p->prior->next=s;//⑤
p->prior=s;//⑥
}
②双链表上删除结点*p自身的操作
void DDeleteNode(DListNode *p)
{//在带头结点的双链表中,删除结点*p,设*p为非终端结点
p->prior->next=p->next;//①
p->next->prior=p->prior;//②
free(p);//③
}
注意:
与单链表上的插入和删除操作不同的是,在双链表中插入和删除必须同时修改两个方向上的指针。
上述两个算法的时间复杂度均为O(1)。
上文转自:
http://student.zjzk.cn/course_ware/data_structure/web/xianxingbiao/xianxingbiao2.3.3.htm
//////////////////////////////////////////////////////////////////////////////////
//封装my_ddlist.h
/////////////////////////////////////////////////////////////////////////////////
#ifndef __DLL_H__
#define __DLL_H__#ifdef __cplusplus
extern "C"{
#endif
//双链表的节点
typedef struct tagDLL_NODE_S
{
struct tagDLL_NODE_S *pPrev;
struct tagDLL_NODE_S*pNext;
//test:
int a;
}DLL_NODE_S;//初始化双链表
#define Dll_Init(pHead) (pHead)->pPrev = (pHead)->pNext = (pHead)
//为双链表增加一个节点(内部使用)
void __Dll_Add(DLL_NODE_S *pNew, DLL_NODE_S *pPrev, DLL_NODE_S *pNext)
{
(pNext)->pPrev = (pNew);
(pNew)->pNext = (pNext);
(pNew)->pPrev = (pPrev);
(pPrev)->pNext = (pNew);
}
//为双链表增加节点外部接口,将pNew加到pHead后面
void Dll_Add(DLL_NODE_S *pNew, DLL_NODE_S *pHead)
{
__Dll_Add(pNew, pHead, (pHead)->pNext);
}
//为双链表增加节点外部接口,将pNew加到pHead前面
void Dll_AddTail(DLL_NODE_S *pNew, DLL_NODE_S *pHead)
{
__Dll_Add(pNew, pHead->pPrev, pHead);
}
//供删除节点时应用(内部接口)
void __Dll_Del(DLL_NODE_S *pPrev, DLL_NODE_S *pNext)
{
(pNext)->pPrev = (pPrev);
(pPrev)->pNext = (pNext);
}
//删除节点pNode,只是将pNode前后结点连起来,并没有删除pNode
void Dll_Del(DLL_NODE_S *pNode)
{
__Dll_Del(pNode->pPrev, pNode->pNext);
}
//移动节点,将pNode移动到pNewHead后面
void Dll_Move(DLL_NODE_S *pNode, DLL_NODE_S *pNewHead)
{
Dll_Del(pNode);
Dll_Add(pNode, pNewHead);
}
//移动节点,将pNode移动到pNewHead节点前面
void Dll_MoveTail(DLL_NODE_S *pNode, DLL_NODE_S *pNewHead)
{
Dll_Del(pNode);
Dll_AddTail(pNode, pNewHead);
}
//是否是最后一个节点,pNode->pNext=pHead?
#define Dll_IsLast(pNode, pHead) \
(pNode)->pNext == (pHead)
//双链表是否是空,pHead->pNext=pHead?
#define Dll_IsEmpty(pHead) \
((pHead)->pNext == (pHead))
//地址偏移量计算当前位置
#define DLL_ENTRY(pNode, structType, nodeMember) \
(void *)((char *)(pNode) - ((char *)(&(((structType *)0)->nodeMember))))
//遍历双链表
#define DLL_FOR_EACH(pPos, pHead) \
for ((pPos) = (pHead)->pNext; \
(pPos) != (pHead); \
(pPos) = (pPos)->pNext)
#define DLL_FOR_EACH_SAFE(pPos, pTmp, pHead) \
for ((pPos) = (pHead)->pNext, (pTmp) = (pPos)->pNext; \
(pPos) != (pHead); \
(pPos) = (pTmp), (pTmp) = (pPos)->pNext)
#ifdef __cplusplus
}
#endif
#endif /*__DLL_H__*/
//////////////////////////////////////////////////////////////////////////////////
//实际应用
/////////////////////////////////////////////////////////////////////////////////
//测试用例:
#include <iostream>
#include "my_dll.h"
using namespace std;
int main()
{
DLL_NODE_S *phead;
phead = (DLL_NODE_S*)malloc(sizeof(DLL_NODE_S));
phead->a = 6;
Dll_Init(phead);
//phead->p1
DLL_NODE_S *p1;
p1 = (DLL_NODE_S*)malloc(sizeof(DLL_NODE_S));
p1->a = 7;
Dll_Add(p1,phead);
//p2->phead->p1
DLL_NODE_S* p2 = (DLL_NODE_S*)malloc(sizeof(DLL_NODE_S));
p2->a = 8;
Dll_AddTail(p2,phead);
//p2->phead->p1->p3
DLL_NODE_S* p3 = (DLL_NODE_S*)malloc(sizeof(DLL_NODE_S));
p3->a = 9;
Dll_Add(p3,p1);
//p2->phead->p1->p3:8,6,7,9
//output :7,9,8
DLL_NODE_S *ptmp = NULL;
cout << "queue1:" << endl;
DLL_FOR_EACH(ptmp,phead)
{
cout << ptmp->a << endl;
}
//phead->p2->p1->p3:6,8,7,9
//output :8,7,9
ptmp = NULL;
Dll_Move(p2,phead);
cout << "queue2:" << endl;
DLL_FOR_EACH(ptmp,phead)
{
cout << ptmp->a << endl;
}
//phead->p1->p2->p3:6,7,8,9
//output :7,8,9
ptmp = NULL;
Dll_Move(p2,p1);
cout << "queue3:" << endl;
DLL_FOR_EACH(ptmp,phead)
{
cout << ptmp->a << endl;
}
cout << "queue4:" << endl;
ptmp = NULL;//结果节点
DLL_NODE_S *ptmp1 = NULL;//工作节点
int i = 0;//循环次数
DLL_FOR_EACH(ptmp1,phead)
{
ptmp = (DLL_NODE_S*)((char *)(ptmp1) - ( (char *) ( (void *)0 )));
if(ptmp->a == 8)
{
cout << "i = " << i << endl;
cout << ptmp->a << endl;
break;
}
else
i++;
}
//注:此处感觉应用不大,其实有时此处有很大用途
#if 0
//eg:我们引擎当中的一个应用:
typedef unsigned long WINKS_CHN_ID; /*消息通道句柄*/
typedef unsigned long WINKS_ENAPP_HND; /*引擎应用句柄*/
typedef struct tag_Winks_HttpReqCtxtListNode_s
{
int Magic;
WINKS_ENAPP_HND hAppHd;
Winks_HttpReqCtxt_s HttpReqCtxt;
DLL_NODE_S Node;
}Winks_HttpReqCtxtListNode_s;
typedef struct tag_Winks_HttpMgr_s
{
WINKS_CHN_ID httpChn;/* http消息通道*/
int ifHttpReady;
int curPri;/* 当前联网的app优先级 */
int ActiveHttpLimit; /* 最大活动http句柄数 */
int TotalHttpNum; /* 总的http句柄数(等于下面链表节点数) */
DLL_NODE_S ReqList;/*用一个双链表管理所有http请求*/
}Winks_HttpMgr_s;
/* 删除指定应用句柄对应的http请求:
输入:
hAppHd : 应用句柄
输出:
返回:
成功返回0,失败返回-1。
*/
int Winks_HttpMgrDelete(WINKS_ENAPP_HND hAppHd)
{
Winks_HttpReqCtxtListNode_s *pReq = NULL;
Winks_HttpMgr_s *pHttpMgr = NULL;
DLL_NODE_S *pPos = NULL;
DLL_NODE_S *pTmp = NULL;
int iCnt = 0;
pHttpMgr = winks_GetHttpMgr();/*获取http管理器句柄*/
if(NULL == pHttpMgr)
return -1;
DLL_FOR_EACH_SAFE(pPos,pTmp,&pHttpMgr->ReqList)
{
//此处用地址偏移量快速查找所需的http句柄
pReq = DLL_ENTRY(pPos,Winks_HttpReqCtxtListNode_s,Node);
if(pReq->hAppHd == hAppHd)
{
Winks_HttpMgrDelReq(pReq);/*删除找到的http请求*/
iCnt++;
}
}
return 0;
}
#endif
system("pause");
return 0;
}



1771

被折叠的 条评论
为什么被折叠?



