双向链表 001

来源:互联网 发布:天津泰达网络 编辑:程序博客网 时间:2024/05/01 22:22

好久没有写东西了,最近准备整理整理思绪,写点东西。

这次说说双向链表吧。我这里会有一系列的双向链表问题,一步步完善现在开始001

双向链表分为两类 1.私有双向链表。(私有是指链表结点保存的数据结构是定好了的,如果需要修改,会稍微麻烦一点)

                          2.通用双向链表。(只管理结点节点的创建,对比,删除以及打印功能由调用者提供)

 

#ifndef __DLIST_H__
#define __DLIST_H__

typedef void * Data;     //用来保存节电数据的指针
/*
 Node struct
*/
typedef struct _Node
{
 struct _Node * pre;
 struct _Node * next;
 Data   data;
}Node;                           //结点,连接上下,保存数据指针

 

// Create node data
typedef Data (*CreateNode)(void * Nodedata);

//compare node -1 less 0 equal 1 large
typedef int (*CompareNode)(void * node1data, void * node2data);

//Delete node
typedef int (*DeleteNode)(void * node);

//print node
typedef void (*PrintNode)(void * node);

 

//上边几个函数需要调用方实现,创建,比较,删除以及打印节点信息。就是几个回调函数


typedef struct _DList
{
 Node  * head;
 Node  * tail;
 unsigned int count;

 CreateNode pCreate;
 CompareNode pCompare;
 DeleteNode  pDelete;
 PrintNode pPrint;
}DList;

// dlist interface

//上边是双向链表的句柄。保存了头尾指针,结点数目以及操作节点的几个函数指针。

//create
DList * DListCreate(CreateNode createnode,CompareNode comparenode, DeleteNode deletenode,PrintNode printnode );

//add tail
int DListAddTail(DList * pDList, void *data);

//add head
int DListAddHead(DList * pDList, void * data);

//delete node
int DListDeleteNode(DList * pDList, void * data);

//delete all nodes
int DListEmpty(DList * pDList);

//destory DList
int DListDestory(DList ** pDList);

//print
void DListPrint(DList *pDlist);

#endif

 

说的多不如看看例子。

//实现部分

#include <stdlib.h>
#include <stdio.h>
#include "dlist.h"

/*
 create dlist
*/
DList * DListCreate(CreateNode createnode,CompareNode comparenode, DeleteNode deletenode,PrintNode printnode )
{
 DList *pDList = malloc(sizeof(DList));

 if (pDList)
 {
  pDList->head = NULL;
  pDList->tail = NULL;
  pDList->count = 0;
  pDList->pCompare = comparenode;
  pDList->pCreate = createnode;
  pDList->pDelete = deletenode;
  pDList->pPrint = printnode;
 }

 return pDList;

}

/*
 add node at tail
*/
int DListAddTail(DList * pDList, void *data)
{
 int res = 0;
 if ((0 == pDList) || (0 == data))
 {
  res = -1;
 }
 else
 {
  Node * pn = malloc(sizeof(Node));
  pn->data = pDList->pCreate(data);
  pn->pre = NULL;
  pn->next = NULL;
  if (pn)
  {
   //check
   if (0 == pDList->count)
   {
    pDList->head = pn;
    pDList->tail = pn;
   }
   else
   {
    pDList->tail->next = pn;
    pn->pre = pDList->tail;
    pDList->tail = pn;
   }

   pDList->count++;
  }
  else
  {
   res = -1;
  }

 }

 return res;
}

/*
 Add Node at head
*/
int DListAddHead(DList * pDList, void * data)
{
 int res = 0;
 if ((0 == pDList) || (0 == data))
 {
  res = -1;
 }
 else
 {
  Node * pn = malloc(sizeof(Node));
  pn->data = pDList->pCreate(data);
  pn->pre = NULL;
  pn->next = NULL;
  if (pn)
  {
   //check
   if (0 == pDList->count)
   {
    pDList->head = pn;
    pDList->tail = pn;
   }
   else
   {
    pDList->head->pre = pn;
    pn->next = pDList->head;
    pDList->head = pn;
   }

   pDList->count++;
  }
  else
  {
   res = -1;
  }

 }

 return res;
}

int DListDeleteNode(DList * pDList, void * data)
{
 int res = 0;
 if ((0 == pDList) || (0 == data))
 {
  res = -1;
 }
 else
 {
  Node dumynode;
  Node * pPreNode;
  Node * pCurNode;

  dumynode.next = pDList->head;

  pPreNode = &dumynode;
  pCurNode = pDList->head;

  for (; pCurNode != NULL; pPreNode = pCurNode, pCurNode= pCurNode->next)
  {
   if ( 0 == pDList->pCompare(pCurNode->data, data))
   {
    //find the delete node
    if (pCurNode == pDList->head) //delete head
    {
     pDList->head = pCurNode->next;
     pDList->pDelete(pDList->head);
     free(pCurNode);
    }
    else if (pCurNode == pDList->tail) // delete tail
    {
     pDList->tail = pCurNode->pre;
     pDList->pDelete(pDList->tail); 
     free(pCurNode);
    }
    else  // normal node
    {
     pPreNode->next = pCurNode->next;
     pCurNode->next->pre = pPreNode;
     pDList->pDelete(pCurNode);
     free(pCurNode);
    }

    pDList->count--;
   }
  }
 }
 return res;
}

void DListPrint(DList *pDlist)
{
 if (NULL == pDlist)
 {
  return;
 }
 else
 {
  Node * ptmp = pDlist->head;

  while (ptmp)
  {
   pDlist->pPrint(ptmp->data);
   ptmp = ptmp->next;
  }
 }
}

int DListEmpty(DList * pDList)
{
 if (NULL == pDList)
 {
  return 0;
 }
 else
 {
  Node * ptmp = pDList->head;
  Node * pDel = ptmp;

  while (ptmp)
  {
   pDList->pDelete(ptmp->data);
   ptmp = ptmp->next;
   free(pDel);
   pDel = ptmp;
   pDList->count--;
  }
 }

 return 0;
}

int DListDestory(DList ** pDList)
{
 DListEmpty(*pDList);

 free(*pDList);
 *pDList = NULL;
 return 0;
}

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

测试部分


#include "dlist.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

/*
 测试部分
*/
typedef struct __MyNode
{
 int  nNum;
 char szInfo[128];
}MyNode;    //自己需要的节点数据结构

static Data  CreateMyNode(void * NodeData)
{
 MyNode * pNode = malloc(sizeof(MyNode));

 if (pNode)
 {
  memcpy(pNode, NodeData,sizeof(MyNode));
 }
 
 return (Data)pNode;
}

static int CompareMyNode(void * node1data, void * node2data)
{
 MyNode *pNodefirst = (MyNode*)node1data;
 MyNode * pNodeSecond = (MyNode*)node2data;
 int  res = 0;

 if ( (0 == node1data) || (0 == node2data))
 {
  res= -2;
 }
 else
 {
  if (pNodefirst->nNum < pNodeSecond->nNum)
  {
   res = -1;
  }
  else if (pNodefirst->nNum == pNodeSecond->nNum)
  {
   res = 0;
  }
  else
  {
   res = 1;
  }
 }
 
 return res;
}

static int DeleteMyNodeData(void * pData)
{
 if (pData)
 {
  free(pData);
  pData = NULL;
 }

 return 0;
}

static void PrintMyNodeData(void *pData)
{
 MyNode * pNode = (MyNode*)pData;
 if (pNode)
 {
  printf("[No.] : %d  [Info]: %s /n",pNode->nNum, pNode->szInfo);
 }
}

int main(int argc, char * argv[])
{
 DList * dlist = DListCreate(CreateMyNode, CompareMyNode, DeleteMyNodeData,PrintMyNodeData);

 MyNode node;
 int i  = 0;

 for ( i = 0; i < 20; i++)
 {
  node.nNum = i;
  sprintf_s(node.szInfo,128, "Node %d", i);
  DListAddTail(dlist, (void*)&node);
 }

 printf_s("===================== /n");

 DListPrint(dlist);

 printf("===================== /n");

 for (i = 0; i < 10; i++)
 {
  node.nNum = rand()%100;
  sprintf_s(node.szInfo,128, "Node %d", i);
  DListAddHead(dlist, (void*)&node);
 }

 DListPrint(dlist);

 DListDestory(&dlist);

 return 0;
}

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

总结:

1.调用方知道结点的具体数据,所以需要调用方提供创建,比较,删除以及打印的具体功能函数。(以回调函数的形式传给双向链表管理)

2.双向链表只专注与结点的关系的管理,就是维护结点间的顺序管理,例如新加结点该挂在哪里,前面是谁,后边是谁。

3.记录头尾节点,主要是方便使用。

4.关于句柄的概念。主要是为了能够多次实例化,所以有了这个概念,因为双向链表的具体信息以及操作函数都保存在了句柄中,所以可以同时实例化多个双向链表,彼此之间没有任何耦合关系。

疑惑:

刚开始会对这种通用双向链表搞不清楚,主要是没有掌握好任务的拆分。写结点管理的时候又在考虑结点的具体数据管理。很容易就写糊涂了,要学会拆分,只专注自己需要管理的部分,其它的不要瞎考虑,那样只会......。

"学而不思则罔,死而不学则殆"学一点东西后仔细思考思考一定会有更多收获。

 

其实上边的代码中也有些许问题的哦。可以思考思考,例如:没有添加多线程的支持。。。。。。后续

 

 

原创粉丝点击