带头节点双向循环链表是链表系列中最为完善和健全的链表,其操作更为方便和简洁,更是省去了单链表中要考虑只有一个节点或者无节点的情况。其次,因为有着头结点,那么对于各种函数接口传参时也就可以直接在这个已经有了一个头结点的链表后面直接操作,不像是单链表,需要用到二级指针,这个一级指针即可。
1:定义
typedef struct ListNode
{
int data;
struct ListNode* prev;
struct ListNode* next;
}ListNode,*List;
一个是数据,一个是前驱指针,一个后继指针。typedef后面的可以ListNode*等价于List,为了简洁可使用。
2:创建节点
ListNode* BuyListNode(int x)
{
ListNode* tmp = new ListNode;
tmp->data = x;
tmp->next =NULL;
tmp->prev =NULL;
return tmp;
}
给予一个数值x,创建出一个节点。毕竟只是创建一个新节点,前驱后继指针就全置为空即可,最后返回这个节点。这里注意:new出来的,是这个类型的地址,既然是地址,就需要用ListNode*来接收,在返回tmp时,因为tmp是新创建的节点的地址,所以返回类型也就是ListNode*类型的,也就是返回的是新创建节点的地址。
3:初始化
ListNode* ListInit()
{
ListNode* phead = BuyListNode(0);
phead->next = phead;
phead->prev = phead;
return phead;
}
初始化就是建立一个带头结点的链表,这里先使用创建节点函数将头结点的数据域赋值为0(其他值也可),然后将头结点的后继和前驱都指向自身,最后返回节点的地址,所以函数类型是ListNode*类型。
4:查找
ListNode* ListFind(ListNode* plist,int x)
{
ListNode* tmp = plist->next;
while (tmp != plist)
{
if (tmp->data == x)
return tmp;
tmp = tmp->next;
}
return NULL;
}
这里的plist代表具有头结点的链表,查找的数据值为x,首先定义一个tmp指向头结点后面的第一个节点,当tmp节点不等于头结点时,进行训话查找操作,如果找到则返回该节点的地址,找不到返回空。
5:插入
void ListInsert( ListNode* pos, int x)
{
ListNode* newnode = BuyListNode(x);
ListNode* tmp = pos->prev;
tmp->next = newnode;
newnode->prev = tmp;
newnode->next = pos;
pos->prev = newnode;
}
插入是在pos节点前面插入新节点。既然是新节点,首先就需要通过函数来创建一个新的节点并用newnode来接收它的地址,定义一个tmp来指向pos节点的前驱(前一个节点),将tmp的后继改为newnode,再将newnode的前驱改为tmp,这样tmp指向的节点就与新节点链接起来了,然后再按照同样的办法将newnode与pos节点链接起来即可。
6:删除
void ListErase(ListNode* pos)
{
ListNode* before = pos->prev;
ListNode* after = pos->next;
before->next = after;
after->prev = before;
delete pos;
pos = NULL;
}
删除pos 处的节点,首先找到该pos节点的前驱和后继,用before和after来代表,将before与after链接后,删掉pos即可。
7:头插
void ListNodePushFront(ListNode*plist,int x)
{
/*ListInsert(plist->next, x);*/
ListNode* cur = plist->next;
ListNode* newnode = BuyListNode(x);
plist->next = newnode;
newnode->prev = plist;
newnode->next = cur;
cur->prev = newnode;
}
此处有2种方法,最快速的方法就是先写出插入函数,通过调用插入函数即可完成头插,也就是注释掉的那一行代码就可实现。第二种方法就是创建新节点然后链接,第二种方法主要是这个思路,要说实现,还是选择第一种。
8:尾插
void ListNodePushBack(ListNode* plist,int x)
{
/*ListInsert(plist, x);*/
ListNode* tail = plist->prev;
ListNode* newnode = BuyListNode(x);
tail->next = newnode;
newnode->prev = tail;
newnode->next = plist;
plist->prev = newnode;
}
依然是2种方法。最快的是利用前面所写的插入函数来做,插在最后一个,其实就是头结点的前一个,注释掉的那一行代码即可实现。最基本的就是创建节点然后链接。实现肯定还是用第一种方法,迅速简便,
9:头删
void ListNodePopFront(ListNode* plist)
{
/*ListErase(plist->next);*/
ListNode* first = plist->next;
ListNode* second = first->next;
plist->next = second;
second->prev = plist;
delete first;
first = NULL;
}
头删2种方法。第一种利用删除函数,删除头结点后面的那个节点即可,也就是pllist->next那个节点,注释掉的那一行代码即可实现。第二种就是利用头结点后面的第一个节点和后面的第二个节点,通过不断的链接实现。按照实现效果来说,还是选择第一种。
10:尾删
void ListNodePopBack(ListNode* plist)
{
/*ListErase(plist->prev);*/
ListNode* tail = plist->prev;
ListNode* tail2 = tail->prev;
tail2->next = plist;
plist->prev = tail2;
delete tail;
tail = NULL;
}
尾删2种方法。第一种是利用删除函数,结尾的节点就是头节点的前驱节点,直接删除即可,注释掉的那一行代码即可实现。第二种基础方法就是找到尾结点和尾结点的前一个节点,再不断链接实现。论实现还是第一种最方便。
11:打印
void print(List phead)
{
ListNode* cur = phead->next;
while (cur!=phead)
{
cout << cur->data << " ";
cur = cur->next;
}
cout << "\n";
}
打印函数从头结点后面的第一个节点开始(头结点不算,因为它的数据域是没什么大用的),当cur不等于头结点时,循环打印并不断后移即可。
下面是test 测试各项函数
void test()
{
ListNode* plist = ListInit();
ListNodePushBack(plist, 1);
ListNodePushBack(plist, 2);
ListNodePushBack(plist, 3);
ListNodePushBack(plist, 4);
print(plist);
ListNodePushFront(plist, 5);
ListNodePushFront(plist, 6);
print(plist);
ListNodePopFront(plist);
print(plist);
ListNodePopBack(plist);
print(plist);
ListNode* pos = ListFind(plist, 3);
ListInsert(pos, 30);
print(plist);
pos = ListFind(plist, 5);
ListInsert(pos, 50);
print(plist);
pos = ListFind(plist, 50);
ListErase(pos);
print(plist);
}
下面是全代码实现所有函数的功能
#include
using namespace std;
typedef struct ListNode
{
int data;
struct ListNode* prev;
struct ListNode* next;
}ListNode,*List;
ListNode* BuyListNode(int x)
{
ListNode* tmp = new ListNode;
tmp->data = x;
tmp->next =NULL;
tmp->prev =NULL;
return tmp;
}
ListNode* ListInit()
{
ListNode* phead = BuyListNode(0);
phead->next = phead;
phead->prev = phead;
return phead;
}
ListNode* ListFind(ListNode* plist,int x)
{
ListNode* tmp = plist->next;
while (tmp != plist)
{
if (tmp->data == x)
return tmp;
tmp = tmp->next;
}
return NULL;
}
void ListInsert( ListNode* pos, int x)
{
ListNode* newnode = BuyListNode(x);
ListNode* tmp = pos->prev;
tmp->next = newnode;
newnode->prev = tmp;
newnode->next = pos;
pos->prev = newnode;
}
void ListErase(ListNode* pos)
{
ListNode* before = pos->prev;
ListNode* after = pos->next;
before->next = after;
after->prev = before;
delete pos;
pos = NULL;
}
void ListNodePushFront(ListNode*plist,int x)
{
/*ListInsert(plist->next, x);*/
ListNode* cur = plist->next;
ListNode* newnode = BuyListNode(x);
plist->next = newnode;
newnode->prev = plist;
newnode->next = cur;
cur->prev = newnode;
}
void ListNodePushBack(ListNode* plist,int x)
{
/*ListInsert(plist, x);*/
ListNode* tail = plist->prev;
ListNode* newnode = BuyListNode(x);
tail->next = newnode;
newnode->prev = tail;
newnode->next = plist;
plist->prev = newnode;
}
void ListNodePopFront(ListNode* plist)
{
/*ListErase(plist->next);*/
ListNode* first = plist->next;
ListNode* second = first->next;
plist->next = second;
second->prev = plist;
delete first;
first = NULL;
}
void ListNodePopBack(ListNode* plist)
{
/*ListErase(plist->prev);*/
ListNode* tail = plist->prev;
ListNode* tail2 = tail->prev;
tail2->next = plist;
plist->prev = tail2;
delete tail;
tail = NULL;
}
void print(List phead)
{
ListNode* cur = phead->next;
while (cur!=phead)
{
cout << cur->data << " ";
cur = cur->next;
}
cout << "\n";
}
void test()
{
ListNode* plist = ListInit();
ListNodePushBack(plist, 1);
ListNodePushBack(plist, 2);
ListNodePushBack(plist, 3);
ListNodePushBack(plist, 4);
print(plist);
ListNodePushFront(plist, 5);
ListNodePushFront(plist, 6);
print(plist);
ListNodePopFront(plist);
print(plist);
ListNodePopBack(plist);
print(plist);
ListNode* pos = ListFind(plist, 3);
ListInsert(pos, 30);
print(plist);
pos = ListFind(plist, 5);
ListInsert(pos, 50);
print(plist);
pos = ListFind(plist, 50);
ListErase(pos);
print(plist);
}
int main()
{
test();
return 0;
}
下面是输出结果: