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;
}
}
}
具体的实现效果如下图所示:
一个双向链表就实现完成了,该双向链表具有实际意义,不仅仅是作为演示使用的,可以使用在实际的项目之中。