1、雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數據結點中都有兩個指針,分別指向直接後繼和直接前驅。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。
2、如果對鏈表還不熟悉,可以看鏈表的基礎知識 和 鏈表的實現 這兩篇文章中對鏈表做了詳細的介紹,並且進行了相關的實現。有了上述的基礎知識,我們來實現雙向鏈表就很簡單了。
3、使用面向對象的方式來實現雙向鏈表,首先需要對節點進行相關的構建
class Node
{
public:
//後繼
Node *pNext;
//前驅
Node *pPrev;
T m_data;
Node()
{
memset(&m_data, 0, sizeof(m_data));
pNext = NULL;
pPrev = NULL;
}
~Node()
{
}
Node(const Node &node)
{
this->m_data = node.m_data;
this->pNext = node.pNext;
this->pPrev = node.pPrev;
}
Node & operator=(const Node &node)
{
if (this == &node)
return *this;
this->m_data = node.m_data;
this->pNext = node.pNext;
this->pPrev = node.pPrev;
}
};
該節點中有一個後繼,有一個前驅,用來從兩個方向遍歷鏈表中的元素,還有一個模板類型的數據結構。
有了上面的模型,我們就需要考慮該如何構建雙向鏈表,以及該如何實現該雙向鏈表了:
1)、鏈表能夠在頭部和尾部插入
2)、鏈表能夠在任意的位置插入
3)、鏈表能夠進行修改任意位置的值
4)、能夠銷燬整個鏈表
public:
COpenList();
COpenList(const COpenList &m_List);
~COpenList();
const COpenList& operator=(const COpenList &m_List);
const T GetHead();
const T GetTail();
void AddHead(T data);
void AddTail(T data);
void RemoveAll();
void RemoveHead();
void RemoveTail();
T GetAt(int nIndex);
void RemoveAt(int nIndex);
void SetAt(int nIndex, T num);
void InsertAfter(int nIndex, T num);
void InsertBefore(int nIndex, T num);
int GetSize() const;
bool IsEmpty();
void PrintList();
Node* GetHeadPtr();
Node* GetTailPtr();
protected:
//Link_List pHead;
Node *pHead;
Node *pTail;
int m_Lenth;
雙向鏈表的構建到此就完成了,接下來就是具體的實現了。
拷貝構造函數:
template<typename T>
COpenList<T>::COpenList(const COpenList<T> &m_List)
{
if (!IsEmpty())
{
RemoveAll();
}
Node *pTempNode = m_List.pHead;
if (NULL == pTempNode)
{
cout << "List doesn't exists" << endl;
return;
}
this->pHead = new Node;
this->pTail = new Node;
this->m_Lenth =0;
assert(pHead);
Node *pNewHead = pHead;
pNewHead->m_data = pTempNode->m_data;
pTail->m_data = pTempNode->m_data;
pTail->pNext = NULL;
pTail->pPrev = pNewHead;
pNewHead->pNext = pTail;
pNewHead->pPrev = NULL;
++m_Lenth;
while(NULL!=pTempNode->pNext)
{
if (m_Lenth == m_List.GetSize() - 1)
{
pTail->m_data = pTempNode->pNext->m_data;
pTail->pNext = NULL;
pTail->pPrev = pNewHead;
pNewHead->pNext = pTail;
}
else
{
Node *pTemp = new Node;
if (NULL != pTemp)
{
pTemp->m_data = pTempNode->pNext->m_data;
pTemp->pNext = NULL;
}
pNewHead->pNext = pTemp;
pTemp->pPrev = pNewHead;
pNewHead = pNewHead->pNext;
}
pTempNode = pTempNode->pNext;
++m_Lenth;
}
}
相關操作:
template<typename T>
const T COpenList<T>::GetHead()
{
T result = 0;
if (!IsEmpty())
result = pHead->m_data;
else
{
cerr << "EmptyList" << endl;
}
return result;
}
template<typename T>
const T COpenList<T>::GetTail()
{
T result = 0;
if (!IsEmpty())
result = pTail->m_data;
else
{
cerr << "EmptyList" << endl;
}
return result;
}
template<typename T>
bool COpenList<T>:: IsEmpty()
{
return m_Lenth==0;
}
template<typename T>
int COpenList<T>::GetSize() const
{
return m_Lenth;
}
template<typename T>
void COpenList<T>::AddHead(T data)
{
if (IsEmpty())
{
pHead = new Node;
pHead->m_data = data;
pTail = new Node;
pTail->m_data = data;
pHead->pNext = pTail;
pHead->pPrev = NULL;
pTail->pPrev = pHead;
pTail->pNext = NULL;
}
else if (1 == GetSize())
{
pHead->m_data = data;
pHead->pNext = pTail;
}
else
{
Node *pNode = new Node;
pNode->m_data = data;
pNode->pNext = pHead;
pHead->pPrev = pNode;
pHead = pNode;
}
++m_Lenth;
}
template<typename T>
void COpenList<T>::AddTail(T data)
{
if (IsEmpty())
{
pHead = new Node;
pHead->m_data = data;
pTail = new Node;
pTail->m_data = data;
pHead->pNext = pTail;
pHead->pPrev = NULL;
pTail->pNext = NULL;
pTail->pPrev = pHead;
}
else if (1 == GetSize())
{
pTail->m_data = data;
}
else
{
Node *pNode = new Node;
pNode->m_data = data;
pNode->pNext = NULL;
pTail->pNext = pNode;
pNode->pPrev = pTail;
pTail = pNode;
}
++m_Lenth;
}
template<typename T>
void COpenList<T>::RemoveAll()
{
if (IsEmpty())
return;
Node *pTemp = pHead;
Node *pTempIter = pTemp;
while (NULL != pTemp)
{
pTempIter = pTemp->pNext;
delete pTemp;
pTemp = pTempIter;
}
m_Lenth = 0;
}
template<typename T>
void COpenList<T>::RemoveHead()
{
if (IsEmpty())
return;
else if (1 == GetSize())
RemoveAll();
else
{
Node *pTemp = pHead;
pHead = pHead->pNext;
delete pTemp;
pHead->pPrev = NULL;
}
--m_Lenth;
}
template<typename T>
void COpenList<T>::RemoveTail()
{
if (IsEmpty())
return;
else if(1 == GetSize())
{
RemoveAll();
}
else
{
Node *pTemp = pTail->pPrev;
delete pTail;
pTail = pTemp;
pTail->pNext = NULL;
}
--m_Lenth;
}
template<typename T>
T COpenList<T>::GetAt(int nIndex)
{
T result = 0;
if (nIndex >= GetSize())
cerr << "Wrong Index" << endl;
else
{
int nCount = 0;
Node *pTemp = pHead;
while (pTemp)
{
if (nCount == nIndex)
{
result = pTemp->m_data;
}
pTemp = pTemp->pNext;
++nCount;
}
}
return result;
}
template<typename T>
void COpenList<T>::RemoveAt(int nIndex)
{
if (nIndex >= GetSize())
{
cerr << "Wrong Index" << endl;
return;
}
else
{
if (nIndex == 0)
{
RemoveHead();
}
else if (nIndex == GetSize()-1)
{
RemoveTail();
}
else
{
int nCount = 0;
Node *pTemp = pHead;
while (pTemp)
{
if (nCount == nIndex)
{
Node *pTempPrev = pTemp->pPrev;
Node *pTempNext = pTemp->pNext;
if (NULL != pTempPrev)
pTempPrev->pNext = pTempNext;
if (NULL != pTempNext)
pTempNext->pPrev = pTempPrev;
delete pTemp;
break;
}
pTemp = pTemp->pNext;
++nCount;
}
}
--m_Lenth;
}
}
template<typename T>
void COpenList<T>::SetAt(int nIndex, T num)
{
if (nIndex >= GetSize())
return;
else
{
int nCount = 0;
Node *pTemp = pHead;
while (pTemp)
{
if (nCount == nIndex)
{
pTemp->m_data = num;
}
pTemp = pTemp->pNext;
++nCount;
}
}
}
template<typename T>
void COpenList<T>::InsertAfter(int nIndex, T num)
{
if (nIndex >= GetSize())
return;
else
{
int nCount = 0;
Node *pTemp = pHead;
while (pTemp)
{
if (nCount == nIndex)
{
Node *pNewNode = new Node;
pNewNode->m_data = num;
pNewNode->pNext = pTemp->pNext;
pTemp->pNext = pNewNode;
pNewNode->pPrev = pTemp;
++m_Lenth;
break;
}
++nCount;
pTemp = pTemp->pNext;
}
}
}
template<typename T>
void COpenList<T>::InsertBefore(int nIndex, T num)
{
if (nIndex >= GetSize())
return;
else
{
int nCount = 0;
Node *pTemp = pHead;
while (pTemp)
{
if (nCount == nIndex)
{
Node *pNewNode = new Node;
pNewNode->m_data = num;
pNewNode->pPrev = pTemp->pPrev;
pTemp->pPrev = pNewNode;
pNewNode->pNext = pTemp;
++m_Lenth;
break;
}
++nCount;
pTemp = pTemp->pNext;
}
}
}
具體的實現效果如下圖所示:
一個雙向鏈表就實現完成了,該雙向鏈表具有實際意義,不僅僅是作爲演示使用的,可以使用在實際的項目之中。