雙向鏈表 001

好久沒有寫東西了,最近準備整理整理思緒,寫點東西。

這次說說雙向鏈表吧。我這裏會有一系列的雙向鏈表問題,一步步完善現在開始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.關於句柄的概念。主要是爲了能夠多次實例化,所以有了這個概念,因爲雙向鏈表的具體信息以及操作函數都保存在了句柄中,所以可以同時實例化多個雙向鏈表,彼此之間沒有任何耦合關係。

疑惑:

剛開始會對這種通用雙向鏈表搞不清楚,主要是沒有掌握好任務的拆分。寫結點管理的時候又在考慮結點的具體數據管理。很容易就寫糊塗了,要學會拆分,只專注自己需要管理的部分,其它的不要瞎考慮,那樣只會......。

"學而不思則罔,死而不學則殆"學一點東西后仔細思考思考一定會有更多收穫。

 

其實上邊的代碼中也有些許問題的哦。可以思考思考,例如:沒有添加多線程的支持。。。。。。後續

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章