双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
链式存储结构
在计算机中用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的).
它不要求逻辑上相邻的元素在物理位置上也相邻.因此它没有顺序存储结构所具有的弱点,但也同时失去了顺序表可随机存取的优点.
链式存储结构特点:
1、比顺序存储结构的存储密度小 (每个节点都由数据域和指针域组成,所以相同空间内假设全存满的话顺序比链式存储更多)。
2、逻辑上相邻的节点物理上不必相邻。
3、插入、删除灵活 (不必移动节点,只要改变节点中的指针)。
4、查找结点时链式存储要比顺序存储慢。
5、每个结点是由数据域和指针域组成。
AL_Node.h
/**
@(#)$Id: AL_Node.h 44 2013-09-13 08:50:04Z xiaoting $
@brief store data, and be used to AL_ListSingle, AL_ListDouble, AL_ListCircular and so on
Chain storage structure//
The computer using a set of arbitrary linear table storage unit stores data elements (which may be a continuous plurality of memory cells, it can be discontinuous).
It does not require the logic elements of adjacent physical location is adjacent to and therefore it is not sequential storage structure has a weakness, but also lost the sequence table can be accessed randomly advantages.
Chain store structural features:
1, compared with sequential storage density storage structure (each node consists of data fields and pointers domains, so the same space is full, then assume full order of more than chain stores).
2, the logic is not required on the adjacent node is physically adjacent.
3, insert, delete and flexible (not the mobile node, change the node as long as the pointer).
4, find the node when stored sequentially slower than the chain stores.
5, each node is a pointer to the data fields and domains.
@Author $Author: xiaoting $
@Date $Date: 2013-09-13 16:50:04 +0800 (周五, 13 九月 2013) $
@Revision $Revision: 44 $
@URL $URL: https://svn.code.sf.net/p/xiaoting/game/trunk/MyProject/AL_DataStructure/groupinc/AL_Node.h $
@Header $Header: https://svn.code.sf.net/p/xiaoting/game/trunk/MyProject/AL_DataStructure/groupinc/AL_Node.h 44 2013-09-13 08:50:04Z xiaoting $
*/
#ifndef CXX_AL_NODE_H
#define CXX_AL_NODE_H
///
// AL_Node
///
template class AL_ListSingle;
template class AL_ListDouble;
template class AL_ListCircularSingle;
template class AL_ListCircularDouble;
template class AL_StackList;
template class AL_QueueList;
template class AL_QueuePriorityList;
template
class AL_Node
{
public:
/**
* Destruction
*
* @param
* @return
* @note
* @attention
*/
~AL_Node();
protected:
private:
friend class AL_ListSingle;
friend class AL_ListDouble;
friend class AL_ListCircularSingle;
friend class AL_ListCircularDouble;
friend class AL_StackList;
friend class AL_QueueList;
friend class AL_QueuePriorityList;
/**
* Construction
*
* @param
* @return
* @note private the Construction, avoid the others use it
* @attention
*/
AL_Node();
/**
* Construction
*
* @param const T& tTemplate
* @return
* @note
* @attention private the Construction, avoid the others use it
*/
AL_Node(const T& tTemplate);
public:
protected:
private:
T m_data; //the friend class can use it directly
AL_Node *m_pPre; //previous data AL_ListDouble will use it
AL_Node *m_pNext; //next data
};
///
// AL_Node
///
/**
* Construction
*
* @param
* @return
* @note private the Construction, avoid the others use it
* @attention
*/
template
AL_Node::AL_Node():
m_pPre(NULL),
m_pNext(NULL)
{
//memset(&m_data, 0x00, sizeof(T)); //can not use memset, as to pointer or virtural pointer of class
}
/**
* Construction
*
* @param const T& tTemplate
* @return
* @note
* @attention private the Construction, avoid the others use it
*/
template
AL_Node::AL_Node(const T& tTemplate):
m_data(tTemplate),
m_pPre(NULL),
m_pNext(NULL)
{
}
/**
* Destruction
*
* @param
* @return
* @note
* @attention
*/
template
AL_Node::~AL_Node()
{
//it doesn't matter to clear the pointer or not.
m_pPre = NULL;
m_pNext = NULL;
}
#endif // CXX_AL_NODE_H
/* EOF */
AL_ListDouble.h
/**
@(#)$Id: AL_ListDouble.h 44 2013-09-13 08:50:04Z xiaoting $
@brief Also called double-linked list doubly linked list is a list in which each data node in both two pointers that point to a
direct successor and direct precursors. Therefore, two-way linked list from any one of the node point, can easily access its
predecessor and successor nodes node.
@Author $Author: xiaoting $
@Date $Date: 2013-09-13 16:50:04 +0800 (周五, 13 九月 2013) $
@Revision $Revision: 44 $
@URL $URL: https://svn.code.sf.net/p/xiaoting/game/trunk/MyProject/AL_DataStructure/groupinc/AL_ListDouble.h $
@Header $Header: https://svn.code.sf.net/p/xiaoting/game/trunk/MyProject/AL_DataStructure/groupinc/AL_ListDouble.h 44 2013-09-13 08:50:04Z xiaoting $
*/
#ifndef CXX_AL_LISTDOUBLE_H
#define CXX_AL_LISTDOUBLE_H
#ifndef CXX_AL_NODE_H
#include "AL_Node.h"
#endif
///
// AL_ListDouble
///
template
class AL_ListDouble
{
public:
static const DWORD LISTDOUBLE_POSITION_INVALID = 0xffffffff;
/**
* Construction
*
* @param
* @return
* @note
* @attention
*/
AL_ListDouble();
/**
* Destruction
*
* @param
* @return
* @note
* @attention
*/
~AL_ListDouble();
/**
* Length
*
* @param VOID
* @return DWORD
* @note get the length of the list
* @attention
*/
DWORD Length() const;
/**
* Find
*
* @param const T& tTemplate
* @return DWORD
* @note find the position of tTemplate
* @attention if not find, will be return 0xffffffff
*/
DWORD Find(const T& tTemplate) const;
/**
* IsElement
*
* @param const T& tTemplate
* @return BOOL
* @note the tTemplate is in the list?
* @attention
*/
BOOL IsElement(const T& tTemplate) const;
/**
* Insert
*
* @param DWORD dwIndex
* @param const T& tTemplate
* @return BOOL
* @note inset the tTemplate into the list at the position
* @attention
*/
BOOL Insert(DWORD dwIndex,const T& tTemplate);
/**
* InsertBegin
*
* @param const T& tTemplate
* @return BOOL
* @note inset the tTemplate into the list at the position
* @attention
*/
BOOL InsertBegin(const T& tTemplate);
/**
* InsertEnd
*
* @param const T& tTemplate
* @return BOOL
* @note inset the tTemplate into the list at the position
* @attention
*/
BOOL InsertEnd(const T& tTemplate);
/**
* Remove
*
* @param const T& tTemplate
* @return BOOL
* @note remove the tTemplate into the list
* @attention
*/
BOOL Remove(const T& tTemplate);
/**
* IsEmpty
*
* @param VOID
* @return BOOL
* @note the list has data?
* @attention
*/
BOOL IsEmpty() const;
/**
* Get
*
* @param T& tTypeOut
* @param DWORD dwIndex
* @return BOOL
* @note get the T at the position
* @attention the dwIndex must is little than the list length
*/
BOOL Get(T& tTypeOut, DWORD dwIndex) const;
/**
* Set
*
* @param T& tTypeOut
* @param DWORD dwIndex
* @param const T& tTemplate
* @return BOOL
* @note Replaced with the element element element on position index, and returns the old element...
* @attention Index must in the list
*/
BOOL Set(T& tTypeOut, DWORD dwIndex, const T& tTemplate);
/**
* Clear
*
* @param VOID
* @return VOID
* @note clear the data in the list
* @attention all data will be clear
*/
VOID Clear();
protected:
private:
/**
* GetNodeByIndex
*
* @param DWORD dwIndex
* @return AL_Node*
* @note get the const T& at the position
* @attention the dwIndex must is little than the list length
*/
AL_Node* GetNodeByIndex(DWORD dwIndex) const;
public:
protected:
private:
AL_Node* m_pHeader;
DWORD m_dwSize;
};
///
// AL_ListDouble
///
/**
* Construction
*
* @param
* @return
* @note
* @attention
*/
template
AL_ListDouble::AL_ListDouble():
m_pHeader(NULL),
m_dwSize(0x00)
{
m_pHeader = new AL_Node;
}
/**
* Destruction
*
* @param
* @return
* @note
* @attention
*/
template
AL_ListDouble::~AL_ListDouble()
{
Clear();
//delete the header
if (NULL != m_pHeader) {
delete m_pHeader;
m_pHeader = NULL;
}
}
/**
* Length
*
* @param
* @return
* @note get the length of the list
* @attention
*/
template DWORD
AL_ListDouble::Length() const
{
return m_dwSize;
/*
if (TRUE == IsEmpty()) {
return 0;
}
AL_Node* pMove = NULL;
DWORD dwCount = 1;
pMove = m_pHeader->m_pNext;
while (NULL != pMove->m_pNext) {
dwCount ++;
pMove = pMove->m_pNext;
}
return dwCount;
*/
}
/**
* Find
*
* @param const T& tTemplate
* @return DWORD
* @note find the position of tTemplate
* @attention if not find, will be return 0xffffffff
*/
template DWORD
AL_ListDouble::Find(const T& tTemplate) const
{
if (TRUE == IsEmpty()) {
return LISTDOUBLE_POSITION_INVALID;
}
AL_Node* pMove = NULL;
DWORD dwCount = 1;
//loop the next data;
pMove = m_pHeader->m_pNext;
while (NULL != pMove->m_pNext) {
if (tTemplate == pMove->m_data) {
//find the data
return dwCount-1;
}
dwCount ++;
pMove = pMove->m_pNext;
}
//the end
if (tTemplate == pMove->m_data) {
//find the data
return dwCount-1;
}
return LISTDOUBLE_POSITION_INVALID;
}
/**
* IsElement
*
* @param const T& tTemplate
* @return BOOL
* @note the tTemplate is in the list?
* @attention
*/
template BOOL
AL_ListDouble::IsElement(const T& tTemplate) const
{
if (LISTDOUBLE_POSITION_INVALID == Find(tTemplate )) {
return FALSE;
}
return TRUE;
}
/**
* Insert
*
* @param const T& tTemplate
* @param DWORD dwIndex
* @return BOOL
* @note inset the tTemplate into the list at the position
* @attention
*/
template BOOL
AL_ListDouble::Insert(DWORD dwIndex, const T& tTemplate)
{
if (dwIndex > Length()) {
//can not insert to this position
return FALSE;
}
AL_Node* pInsert = new AL_Node;
pInsert->m_data = tTemplate;
AL_Node* pPre = NULL;
//get the previous Node
if (0x00 == dwIndex) {
pPre = m_pHeader;
}
else {
pPre = GetNodeByIndex(dwIndex - 1);
}
if ((NULL == pPre)) {
//error
return FALSE;
}
if (Length() == dwIndex){
//end
pPre->m_pNext = pInsert;
pInsert->m_pPre = pPre;
}
else {
//among of the list
AL_Node* pIndexNode = pPre->m_pNext;
if ((NULL == pIndexNode)) {
//error
return FALSE;
}
pInsert->m_pNext = pIndexNode;
pIndexNode->m_pPre = pInsert;
pPre->m_pNext = pInsert;
pInsert->m_pPre = pPre;
}
m_dwSize++;
return TRUE;
}
/**
* InsertBegin
*
* @param const T& tTemplate
* @return BOOL
* @note inset the tTemplate into the list at the position
* @attention
*/
template BOOL
AL_ListDouble::InsertBegin(const T& tTemplate)
{
return Insert(0, tTemplate);
}
/**
* InsertEnd
*
* @param const T& tTemplate
* @return BOOL
* @note inset the tTemplate into the list at the position
* @attention
*/
template BOOL
AL_ListDouble::InsertEnd(const T& tTemplate)
{
return Insert(Length(), tTemplate);
}
/**
* Remove
*
* @param const T& tTemplate
* @return BOOL
* @note remove the tTemplate into the list
* @attention
*/
template BOOL
AL_ListDouble::Remove(const T& tTemplate)
{
if (TRUE == IsEmpty()) {
return FALSE;
}
DWORD dwPosition = Find(tTemplate);
if (LISTDOUBLE_POSITION_INVALID == dwPosition) {
//can not find the data
return FALSE;
}
AL_Node* pDelete = GetNodeByIndex(dwPosition);
if (NULL == pDelete) {
//error
return FALSE;
}
AL_Node* pPre = NULL;
//get the previous Node
if (0x00 == dwPosition) {
pPre = m_pHeader;
}
else {
pPre = pDelete->m_pPre;
}
if (NULL == pPre) {
//error
return FALSE;
}
pPre->m_pNext = pDelete->m_pNext;
AL_Node* pNext = pDelete->m_pNext;
if (NULL != pNext) {
//among of the list
pNext->m_pPre = pPre;
}
delete pDelete;
pDelete = NULL;
m_dwSize--;
return TRUE;
}
/**
* IsEmpty
*
* @param
* @return BOOL
* @note the list has data?
* @attention
*/
template BOOL
AL_ListDouble::IsEmpty() const
{
return (NULL == m_pHeader->m_pNext) ? TRUE:FALSE;
}
/**
* Get
*
* @param T& tTypeOut
* @param DWORD dwIndex
* @return BOOL
* @note get the T at the position
* @attention the dwIndex must is little than the list length
*/
template BOOL
AL_ListDouble::Get(T& tTypeOut, DWORD dwIndex) const
{
if (TRUE == IsEmpty()) {
//error
return FALSE;
}
if (Length()-1 < dwIndex) {
//error
return FALSE;
}
AL_Node* pGet = GetNodeByIndex(dwIndex);
if (NULL == pGet) {
//error
return FALSE;
}
tTypeOut = pGet->m_data;
return TRUE;
}
/**
* Set
*
* @param T& tTypeOut
* @param DWORD dwIndex
* @param const T& tTemplate
* @return BOOL
* @note Replaced with the element element element on position index, and returns the old element...
* @attention Index must in the list
*/
template BOOL
AL_ListDouble::Set(T& tTypeOut, DWORD dwIndex, const T& tTemplate)
{
if (Length()-1 < dwIndex) {
//error
return FALSE;
}
AL_Node* pSet = GetNodeByIndex(dwIndex);
if (NULL == pSet) {
//error
return FALSE;
}
tTypeOut = pSet->m_data;
pSet->m_data = tTemplate;
return TRUE;
}
/**
* Clear
*
* @param VOID
* @return VOID
* @note clear the data in the list
* @attention all data will be clear
*/
template VOID
AL_ListDouble::Clear()
{
if (TRUE == IsEmpty()) {
//No data,
return;
}
AL_Node* pDelete = NULL;
while(NULL != m_pHeader->m_pNext){
//get the node
pDelete = m_pHeader->m_pNext;
m_pHeader->m_pNext = pDelete->m_pNext;
delete pDelete;
pDelete = NULL;
}
m_dwSize = 0x00;
}
/**
* GetNodeByIndex
*
* @param DWORD dwIndex
* @return AL_Node*
* @note get the const T& at the position
* @attention the dwIndex must is little than the list length
*/
template AL_Node*
AL_ListDouble::GetNodeByIndex(DWORD dwIndex) const
{
if (Length()-1 < dwIndex) {
//error
return NULL;
}
AL_Node* pMove = NULL;
DWORD dwCount = 1;
//loop the next data;
pMove = m_pHeader->m_pNext;
while (NULL != pMove->m_pNext) {
if (dwCount-1 == dwIndex) {
//get this place
return pMove;
}
dwCount ++;
pMove = pMove->m_pNext;
}
//the end
return pMove;
/* //test code
//forward loop (only for test)
//get the end node
AL_Node* pEnd = NULL;
AL_Node* pMove = NULL;
//loop the next data;
pMove = m_pHeader->m_pNext;
while (NULL != pMove->m_pNext) {
pMove = pMove->m_pNext;
}
pEnd = pMove;
pMove = NULL;
DWORD dwCount = Length();
//loop the next data;
pMove = pEnd;
while (m_pHeader != pMove->m_pPre) {
if (dwCount-1 == dwIndex) {
//get this place
return pMove;
}
dwCount --;
pMove = pMove->m_pPre;
}
//the end
return pMove;
*/
}
#endif // CXX_AL_LISTDOUBLE_H
/* EOF */
测试代码
#ifdef TEST_AL_LISTDOUBLE
AL_ListDouble cListDouble;
BOOL bEmpty = cListDouble.IsEmpty();
std::cout<