有了以上单链表的基础后,实现双向带头循环链表也不是很复杂的。双向循环链表相对于单链表效率高。其本质是以空间换取了时间。
//DblCrcultList.h
#pragma once
typedef struct DbListNode{
int iData; //数据域
DbListNode* pPre; //前驱指针域
DbListNode* pNext; //后继指针域
DbListNode()
{
iData = 0;
pPre = nullptr;
pNext = nullptr;
}
}DbListNode;
//双向循环链表类
class DbCrcultList
{
public:
DbCrcultList();
~DbCrcultList();
public:
//链表结构初始化
DbListNode* InitDbCrcultList();
//销毁整个链表
DbListNode* DestroyDbCrcultList(DbListNode* pHead);
//申请链表节点所需的内存区域
DbListNode* BuyNodeFromMem();
//尾插元素
DbListNode* PushBackIntoList(DbListNode* pHead, int iData);
//头插元素
DbListNode* PushFrontIntoList(DbListNode* pHead, int iData);
//头删元素
DbListNode* PopFrontFromList(DbListNode* pHead);
//尾删元素
DbListNode* PopBackFromList(DbListNode* pHead);
//打印链表的数据
void PrintDbListData(DbListNode* pHead);
};
//DblCrcultList.cpp
#include "DblCrcultList.h"
#include <iostream>
DbCrcultList::DbCrcultList()
{
}
DbCrcultList::~DbCrcultList()
{
}
DbListNode* DbCrcultList::InitDbCrcultList()
{
//双向循环链表初始化,实际就是创建一个空的链表。该链表目前只有一个头节点,
//约定头节点的数据域为-1
//且该节点的前驱指针指向自身,后继指针也指向自身
DbListNode* pHead = BuyNodeFromMem();
pHead->iData = -1;
pHead->pNext = pHead;
pHead->pPre = pHead;
return pHead;
}
DbListNode* DbCrcultList::DestroyDbCrcultList(DbListNode* pHead)
{
if (pHead == nullptr || pHead->pNext == pHead)
{
delete pHead;
pHead = nullptr;
std::cout << "链表销毁完成!" << std::endl;
return pHead;
}
DbListNode* pCur = pHead->pNext;
DbListNode* pDel = nullptr;
while (pCur->pNext != pHead)
{
pDel = pCur;
pCur = pCur->pNext;
delete pDel;
pDel = nullptr;
}
delete pCur;
pCur = nullptr;
std::cout << "链表销毁完成!" << std::endl;
return nullptr;
}
DbListNode * DbCrcultList::BuyNodeFromMem()
{
//向内存中申请一块内存,若返回值为空,则代表内存申请失败。
DbListNode* pHead = new DbListNode();
return pHead;
}
DbListNode* DbCrcultList::PushBackIntoList(DbListNode * pHead, int iData)
{
//向双向循环链表尾部插入节点其实与单链表尾插很类似,即:
//先向操作系统申请一块内存
//把原链表的尾指针指向新节点
//新节点的前驱指针只想原链表尾节点
//新节点的后继指针指向链表头节点
//原链表的头节点指向新节点
if (pHead == nullptr)
{
return pHead;
}
DbListNode* pNewNode = BuyNodeFromMem();
pNewNode->iData = iData;
//先记录原链表的末尾节点
//再将原末尾节点的后继指针指向新节点
//再将新节点的前驱指针指向原末尾节点
//再将头节点的前驱指针指向新的末尾节点
//最后将新末尾节点的后继指针指向头节点
DbListNode* pOldTailNode = pHead->pPre;
pOldTailNode->pNext = pNewNode;
pNewNode->pPre = pOldTailNode;
pHead->pPre = pNewNode;
pNewNode->pNext = pHead;
return pHead;
}
DbListNode* DbCrcultList::PushFrontIntoList(DbListNode* pHead, int iData)
{
if (pHead == nullptr)
{
return nullptr;
}
//头插元素,即:
//把新元素的前驱指针指向头节点
//把新元素的后继指针指向头节点的原后继节点
//把头节点的原后继节点的前驱指针指向新元素
//把头节点的后继指针指向新元素
DbListNode* pNewNode = BuyNodeFromMem();
pNewNode->iData = iData;
if (pNewNode)
{
pNewNode->pPre = pHead;
pNewNode->pNext = pHead->pNext;
pHead->pNext->pPre = pNewNode;
pHead->pNext = pNewNode;
}
return pHead;
}
DbListNode* DbCrcultList::PopFrontFromList(DbListNode* pHead)
{
if (pHead == nullptr || pHead->pNext == pHead)
{
return pHead;
}
//头删元素,即:
//先将需要删除的元素记录下来
//再把头节点的后继指针指向头节点原后继的后继
//再把头节点的原后继的前驱指向头节点本身
//删除掉目标元素
//被删除的元素的地址置空
DbListNode* pDelNode = pHead->pNext;
pHead->pNext = pHead->pNext->pNext;
pHead->pNext->pPre = pHead;
delete pDelNode;
pDelNode = nullptr;
return pHead;
}
DbListNode* DbCrcultList::PopBackFromList(DbListNode* pHead)
{
if (pHead == nullptr || pHead->pNext == pHead)
{
return pHead;
}
//尾删元素,即:
//先将需要删除的元素记录下来
//再把头节点的前驱指针指向目标节点的前驱节点
//再把目标节点的前驱节点的后继节点指向头节点
//删除掉目标元素
//被删除的元素的地址置空
DbListNode* pDelNode = pHead->pPre;
pHead->pPre = pDelNode->pPre;
pDelNode->pPre->pNext = pHead;
delete pDelNode;
pDelNode = nullptr;
return pHead;
}
void DbCrcultList::PrintDbListData(DbListNode * pHead)
{
if (pHead == nullptr || pHead->pNext == pHead)
{
std::cout << "链表为空,打印失败!" << std::endl;
return;
}
//打印链表的思路如下:
//维护一个指向头节点的指针变量pCur,从头指针的位置开始遍历,
//如果pCur的后继节点指向了头节点,则代表整个链表遍历完成
DbListNode* pCur = pHead->pNext;
while (pCur != nullptr && pCur != pHead)
{
std::cout << pCur->iData << "-->";
pCur = pCur->pNext;
}
}
//main.cpp
#include "DblCrcultList.h"
#include <iostream>
int main()
{
DbCrcultList* pList = new DbCrcultList();
if (pList)
{
//初始化链表
DbListNode* pHead = pList->InitDbCrcultList();
if (pHead)
{
//尾插链表
std::cout << "尾插:" << std::endl;
pList->PushBackIntoList(pHead, 5);
pList->PushBackIntoList(pHead, 6);
pList->PushBackIntoList(pHead, 7);
pList->PushBackIntoList(pHead, 8);
pList->PushBackIntoList(pHead, 9);
pList->PrintDbListData(pHead);
std::cout << std::endl;
//头插链表
std::cout << "头插:" << std::endl;
pList->PushFrontIntoList(pHead, 1);
pList->PushFrontIntoList(pHead, 2);
pList->PushFrontIntoList(pHead, 3);
pList->PushFrontIntoList(pHead, 4);
pList->PrintDbListData(pHead);
std::cout << std::endl;
//头删链表
std::cout << "头删:" << std::endl;
pList->PopFrontFromList(pHead);
pList->PopFrontFromList(pHead);
pList->PopFrontFromList(pHead);
pList->PopFrontFromList(pHead);
pList->PopFrontFromList(pHead);
pList->PrintDbListData(pHead);
std::cout << std::endl;
//尾删链表
std::cout << "尾删:" << std::endl;
pList->PopBackFromList(pHead);
pList->PopBackFromList(pHead);
pList->PrintDbListData(pHead);
std::cout << std::endl;
//销毁链表
std::cout << "销毁整个链表:" << std::endl;
pList->DestroyDbCrcultList(pHead);
}
}
return 0;
}
运行结果: