首先,我们来看一下带头双向循环链表的结构:
目录
带头双向循环链表结点的定义:
相关操作接口:
1、初始化 && 获取一个结点
2、销毁链表
3、尾插
4、头插
5、指定元素查找
6、任意位置插入
7、 尾删
8、头删
9、任意位置删除
10、打印链表
附上完整代码:
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node* next;
struct Node* prev;
}Node, *pNode, *pList;
逻辑:因为实现的是带头结点的双向循环链表,所以初始化的时候,我们得到一个空的结点,它的 next 和 prev 都指向它自己。获取结点就是靠动态开辟空间。
pNode BuyNode(DataType d)
{
pNode ptr = (pNode)malloc(sizeof(Node));
if (ptr == NULL)
{
perror("BuyNode::malloc");
return NULL;
}
ptr->data = d;
ptr->next = NULL;
ptr->prev = NULL;
return ptr;
}
pList InitList()
{
DataType d = 0;
pNode head = BuyNode(d);
head->next = head;
head->prev = head;
return head;
}
逻辑:遍历逐个销毁。
void DestoryList(pList plist)
{
pNode cur = plist->next;
pNode next = NULL;
while (cur != plist)
{
next = cur->next;
free(cur);
cur = NULL;
cur = next;
}
}
逻辑:记录好最后一个结点和头结点。
void PushBack(pList plist, DataType d)
{
pNode head = plist;
pNode tail = head->prev;
//tail newnode head
pNode newnode = BuyNode(d);;
tail->next = newnode;
newnode->prev = tail;
newnode->next = head;
head->prev = newnode;
}
逻辑:记录好第一个结点和头结点。
void PushFront(pList plist, DataType d)
{
pNode first = plist->next;
pNode newnode = BuyNode(d);
//plist newnode first;
plist->next = newnode;
newnode->prev = plist;
newnode->next = first;
first->prev = newnode;
}
逻辑:遍历比较是否有指定元素,注意不要造成死循环。
pNode FindList(pList plist, DataType d)
{
pNode cur = NULL;
assert(plist);
cur = plist->next;
while (cur != plist)
{
if (cur->data == d)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
逻辑:记录好指定位置的前一个结点和后一个结点。
void InsertList(pNode pos, DataType d)
{
pNode newnode = NULL;
pNode prev = NULL;
assert(pos);
prev = pos->prev;
newnode = BuyNode(d);
//prev newnode pos
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
逻辑:记录好头结点和倒数第二个结点。注意链表是否只有头结点,如果只有头结点,不可以删除。
void PopBack(pList plist)
{
pNode tail = NULL;
pNode prev = NULL;
assert(plist&&plist->next != NULL);
#if 0 //方法一
tail = plist->prev;
prev = tail->prev;
//plist ... prev tail
plist->prev = prev;
prev->next = plist;
free(tail);
tail = NULL;
#endif
#if 1 //方法二
EraseList(plist->prev);
#endif
}
逻辑:记录好头结点和第二个结点。注意链表是否只有头结点,如果只有头结点,不可以删除。
void PopFront(pList plist)
{
pNode first = NULL;
pNode next = NULL;
assert(plist&&plist->next != NULL);
#if 1 //方法一
first = plist->next;
next = first->next;
//plist first next
plist->next = next;
next->prev = plist;
free(first);
first = NULL;
#endif
#if 0 //方法二
EraseList(plist->next);
#endif
}
逻辑:记录好指定位置的前一个结点和后一个结点。注意链表是否只有头结点,如果只有头结点,不可以删除。
void EraseList(pNode pos)
{
pNode prev = NULL;
pNode next = NULL;
assert(pos);
prev = pos->prev;
next = pos->next;
//prev pos next
prev->next = next;
next->prev = prev;
free(pos);
pos = NULL;
}
逻辑:遍历打印。
void PrintList(pList plist)
{
pNode cur = plist->next;
while (cur != plist)
{
printf("%d -> ", cur->data);
cur = cur->next;
}
printf("head\n");
}
总结:所有接口的实现,画图可以更好的让我们了解接口实现的逻辑,并且双向循环链表接口的实现都是很简单的,无论是插入删除,效率都是比较高的。
DList.h
#ifndef __DLIST_H__
#define __DLIST_H__
#include
#include
#include
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node* next;
struct Node* prev;
}Node, *pNode, *pList;
pList InitList();
void DestoryList(pList plist);
pNode BuyNode(DataType d);
void PushBack(pList plist, DataType d);
void PushFront(pList plist, DataType d);
pNode FindList(pList plist, DataType d);
void InsertList(pNode pos, DataType d);
void PopBack(pList plist);
void PopFront(pList plist);
void EraseList(pNode pos);
void PrintList(pList plist);
#endif //__DLIST_H__
DList.c
#include "DList.h"
pNode BuyNode(DataType d)
{
pNode ptr = (pNode)malloc(sizeof(Node));
if (ptr == NULL)
{
perror("BuyNode::malloc");
return NULL;
}
ptr->data = d;
ptr->next = NULL;
ptr->prev = NULL;
return ptr;
}
pList InitList()
{
DataType d = 0;
pNode head = BuyNode(d);
head->next = head;
head->prev = head;
return head;
}
void DestoryList(pList plist)
{
pNode cur = plist->next;
pNode next = NULL;
while (cur != plist)
{
next = cur->next;
free(cur);
cur = NULL;
cur = next;
}
}
void PushBack(pList plist, DataType d)
{
pNode head = plist;
pNode tail = head->prev;
//tail newnode head
pNode newnode = BuyNode(d);;
tail->next = newnode;
newnode->prev = tail;
newnode->next = head;
head->prev = newnode;
}
void PushFront(pList plist, DataType d)
{
pNode first = plist->next;
pNode newnode = BuyNode(d);
//plist newnode first;
plist->next = newnode;
newnode->prev = plist;
newnode->next = first;
first->prev = newnode;
}
pNode FindList(pList plist, DataType d)
{
pNode cur = NULL;
assert(plist);
cur = plist->next;
while (cur != plist)
{
if (cur->data == d)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void InsertList(pNode pos, DataType d)
{
pNode newnode = NULL;
pNode prev = NULL;
assert(pos);
prev = pos->prev;
newnode = BuyNode(d);
//prev newnode pos
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
void PopBack(pList plist)
{
pNode tail = NULL;
pNode prev = NULL;
assert(plist&&plist->next != NULL);
#if 0 //方法一
tail = plist->prev;
prev = tail->prev;
//plist ... prev tail
plist->prev = prev;
prev->next = plist;
free(tail);
tail = NULL;
#endif
#if 1 //方法二
EraseList(plist->prev);
#endif
}
void PopFront(pList plist)
{
pNode first = NULL;
pNode next = NULL;
assert(plist&&plist->next != NULL);
#if 1 //方法一
first = plist->next;
next = first->next;
//plist first next
plist->next = next;
next->prev = plist;
free(first);
first = NULL;
#endif
#if 0 //方法二
EraseList(plist->next);
#endif
}
void EraseList(pNode pos)
{
pNode prev = NULL;
pNode next = NULL;
assert(pos);
prev = pos->prev;
next = pos->next;
//prev pos next
prev->next = next;
next->prev = prev;
free(pos);
pos = NULL;
}
void PrintList(pList plist)
{
pNode cur = plist->next;
while (cur != plist)
{
printf("%d -> ", cur->data);
cur = cur->next;
}
printf("head\n");
}
test.c
#include "DList.h"
void PushBackTest()
{
pList plist;
plist = InitList();
PushBack(plist, 1);
PushBack(plist, 2);
PushBack(plist, 3);
PushBack(plist, 4);
PrintList(plist); // 1 2 3 4
DestoryList(plist);
}
void PushFrontTest()
{
pList plist = InitList();
PushFront(plist, 1);
PushFront(plist, 2);
PushFront(plist, 3);
PushFront(plist, 4);
PrintList(plist); // 4 3 2 1
DestoryList(plist);
}
void FindListTest()
{
pNode pos = NULL;
pList plist = InitList();
PushFront(plist, 1);
PushFront(plist, 2);
PushFront(plist, 3);
PushFront(plist, 4);
PrintList(plist); // 4 3 2 1
pos = FindList(plist, 3);
if (pos == NULL)
{
printf("没找到\n");
}
else
{
printf("找到了:%d\n", pos->data);
}
DestoryList(plist);
}
void InsertListTest()
{
pNode pos = NULL;
pList plist = InitList();
PushFront(plist, 1);
PushFront(plist, 2);
PushFront(plist, 3);
PushFront(plist, 4);
PrintList(plist); // 4 3 2 1
pos = FindList(plist, 3);
if (pos == NULL)
{
printf("没找到\n");
}
else
{
InsertList(pos, 5);
PrintList(plist); // 4 5 3 2 1
}
DestoryList(plist);
}
void PopBackTest()
{
pList plist = InitList();
PushFront(plist, 1);
PushFront(plist, 2);
PushFront(plist, 3);
PushFront(plist, 4);
PrintList(plist); // 4 3 2 1
PopBack(plist);
PrintList(plist); // 4 3 2
PopBack(plist);
PrintList(plist); // 4 3
PopBack(plist);
PrintList(plist); // 4
PopBack(plist);
PrintList(plist); //
DestoryList(plist);
}
void PopFrontTest()
{
pList plist = InitList();
PushFront(plist, 1);
PushFront(plist, 2);
PushFront(plist, 3);
PushFront(plist, 4);
PrintList(plist); // 4 3 2 1
PopFront(plist);
PrintList(plist); // 3 2 1
PopFront(plist);
PrintList(plist); // 2 1
PopFront(plist);
PrintList(plist); // 1
PopFront(plist);
PrintList(plist); //
DestoryList(plist);
}
void EraseListTest()
{
pNode pos = NULL;
pList plist = InitList();
PushFront(plist, 1);
PushFront(plist, 2);
PushFront(plist, 3);
PushFront(plist, 4);
PrintList(plist); // 4 3 2 1
pos = FindList(plist, 3);
if (pos == NULL)
{
printf("没找到\n");
}
else
{
EraseList(pos);
PrintList(plist); // 4 5 3 2 1
}
DestoryList(plist);
}
int main()
{
PushBackTest();
PushFrontTest();
FindListTest();
InsertListTest();
PopBackTest();
PopFrontTest();
EraseListTest();
return 0;
}