双链表

//////////////////////////////////////////////////////////////////////////////////

//双链表简介

/////////////////////////////////////////////////////////////////////////////////


双链表

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;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值