上篇博客我们提到的单链表为:无头单向非循环链表。其特点是结构简单,但一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。无头单向非循环链表这种结构在笔试面试中出现很多。
本篇博客将为大家讲解链表的另外一种结构:带头双向循环链表。该结构特点是结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面会演示代码的实现。
typedef int LTDatatype;
typedef struct ListNode
{
struct ListNode* prev;
LTDatatype data;
struct ListNode* next;
}LTNode;
双向链表的初始化:
LTNode* LTInit()
{
LTNode* phead = BuyListNode(-1);
phead->next = phead;
phead->prev = phead;
return phead;
}
动态申请一个结点:
LTNode* BuyListNode(LTDatatype x)
{
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL)
{
printf("malloc fail!\n");
return NULL;
}
newnode->data = x;
newnode->next = NULL;
newnode->prev = NULL;
return newnode;
}
双向链表的打印:
void LTPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
printf("guard<==>");
while (cur != phead)
{
printf("%d<==>", cur->data);
cur = cur->next;
}
printf("\n");
}
双向链表的尾插:
void LTPushBack(LTNode* phead, LTDatatype x)
{
assert(phead);
LTNode* tail = phead->prev;
LTNode* newnode = BuyListNode(x);
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
双向链表的头插:
void LTPushFront(LTNode* phead, LTDatatype x)
{
LTNode* newnode = BuyListNode(x);
LTNode* first = phead->next;
newnode->next = first;
first->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
}
判断双向链表是否为空:
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead->next == phead;
}
双向链表的尾删:
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
LTNode* tail = phead->prev;
LTNode* tailPrev = tail->prev;
free(tail);
tailPrev->next = phead;
phead->prev = tailPrev;
}
双向链表的头删:
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
LTNode* frist = phead->next;
LTNode* fristNext = frist->next;
free(frist);
phead->next = fristNext;
fristNext->prev = phead;
}
双向链表中查找某个结点:
LTNode* LTFind(LTNode* phead, LTDatatype x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
在双向链表pos结点前插入结点:
void LTInsert(LTNode* pos, LTDatatype x)
{
assert(pos);
LTNode* posPrev = pos->prev;
LTNode* newnode = BuyListNode(x);
posPrev->next = newnode;
newnode->prev = posPrev;
newnode->next = pos;
pos->prev = newnode;
}
删除双向链表pos处的结点:
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* posPrev = pos->prev;
LTNode* posNext = pos->next;
posPrev->next = posNext;
posNext->prev = posPrev;
free(pos);
}
销毁双向链表:
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
感谢大家能够看完这篇博客,创作时长,小伙伴们觉得我的博客对你有帮助,不妨留下你的点赞的收藏,关注我,带你了解不一样的数据结构。