赞
踩
单链表在之前的博客里已经详细讲解过了 (指路导航 无哨兵位单向非循环链表),接下来讲解的是 双向带头循环链表。
注意:要转图请提前打招呼
首先我们要确定的问题是带哨兵位的链表,需要传啥类型的实参?
由图见,因为带哨兵位,不对phead进行修改,所以只需要传一级指针。
// 带头+双向+循环链表增删查改
typedef int LTDataType;
typedef struct ListNode {
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}LTNode;
// 创建返回链表的头结点 LTNode* ListCreate(); // 双向链表销毁 void ListDestroy(LTNode* phead); // 双向链表打印 void ListPrint(LTNode* phead); // 双向链表尾插 void ListPushBack(LTNode* phead, LTDataType x); // 双向链表尾删 void ListPopBack(LTNode* phead); // 双向链表头插 void ListPushFront(LTNode* phead, LTDataType x); // 双向链表头删 void ListPopFront(LTNode* phead); // 双向链表查找 LTNode* ListFind(LTNode* phead, LTDataType x); // 双向链表在pos的前面进行插入 void ListInsert(LTNode* pos, LTDataType x); // 双向链表删除pos位置的结点 void ListErase(LTNode* pos);
开辟一个哨兵位结点,结点next和prev指向自己。
LTNode* ListCreate()
{
LTNode* phead = (LTNode*)malloc(sizeof(LTNode));
phead->next = phead;
phead->prev = phead;
return phead;
}
void ListDestroy(LTNode* phead)
{
assert(phead);
// 逐个销毁
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
逐个打印、注意结束条件即可。
void ListPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
老套路、不废话。
void ListPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = BuyListNode(x);
LTNode* tail = phead->prev;
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
void ListPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead); // 不能删除哨兵位
LTNode* oldtail = phead->prev;
LTNode* newtail = oldtail->prev;
phead->prev = newtail;
newtail->next = phead;
free(oldtail);
}
void ListPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* first = phead->next;
LTNode* newnode = BuyListNode(x);
phead->next = newnode;
newnode->prev = phead;
newnode->next = first;
first->prev = newnode;
}
void ListPopFront(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
LTNode* first = phead->next, * second = first->next;
//phead first second
phead->next = second;
second->prev = phead;
free(first);
}
遍历思想。
LTNode* ListFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
void ListInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* prevnode = pos->prev;
LTNode* newnode = BuyListNode(x);
// prevnode newnode pos
prevnode->next = newnode;
newnode->prev = prevnode;
newnode->next = pos;
pos->prev = newnode;
}
void ListErase(LTNode* pos)
{
assert(pos);
LTNode* next = pos->next, * prev = pos->prev;
// prev pos next
prev->next = next;
next->prev = pos;
}
带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了。
码文不易,欢迎三连,笔芯感谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。