C语言数据结构——带哨兵结点的循环双向链表
Posted 大桑树保安队
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言数据结构——带哨兵结点的循环双向链表相关的知识,希望对你有一定的参考价值。
循环双向链表(哨兵)
1.基本数据类型
typedef int LTDatatype;
typedef struct LTNode
{
LTDatatype data;
struct LTNode* pre;
struct LTNode* next;
}LTNode;
2.新建结点
开辟一个结点空间并返回
LTNode* BuyNewNode()
{
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
return newnode;
}
3.初始化链表
制造哨兵结点
LTNode* ListInit()
{
LTNode* phead = BuyNewNode();
assert(phead);
phead->next = phead;
phead->pre = phead;
return phead;
}
4.打印链表
void ListPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead )
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("plist\\n");
}
注意这里循环的条件,cur!=哨兵结点
5.尾插结点
void ListPushBack(LTNode* phead, LTDatatype x)
{
assert(phead);
LTNode* newnode = BuyNewNode();
assert(newnode);
newnode->data = x;
LTNode* tail = phead->pre;
tail->next = newnode;
newnode->pre = tail;
newnode->next = phead;
phead->pre = newnode;
}
6.头插结点
void ListPushFront(LTNode* phead, LTDatatype x)
{
assert(phead);
LTNode* newnode = BuyNewNode();
assert(newnode);
newnode->data = x;
LTNode* post = phead->next;
newnode->pre = phead;
newnode->next = post;
phead->next = newnode;
post->pre = newnode;
}
7.尾删结点
删除结点时,注意哨兵结点的保留
void ListPopBack(LTNode* phead)
{
assert(phead);
assert(phead->pre != phead);
LTNode* tail = phead->pre;//找到尾结点
LTNode* pretail = tail->pre;//尾结点的前一个结点
pretail->next = phead;
phead->pre = pretail;
free(tail);
}
8.头删结点
仍然注意哨兵结点的保留
void ListPopFront(LTNode* phead)
{
assert(phead);
assert(phead->next!=phead);
LTNode* post = phead->next;
LTNode* postPost = phead->next->next;
phead->next = postPost;
postPost->pre = phead;
free(post);
}
9.寻找链表结点,返回地址
遍历链表,满足条件,返回地址
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;
}
10.链表插入结点
已知链表某结点地址,在其前插入结点
void ListInsert(LTNode* pos, LTDatatype x)
{
assert(pos);
LTNode* newnode = BuyNewNode();
assert(newnode);
newnode->data = x;
LTNode* prepos = pos->pre;
//在prepos和pos之间插入x
prepos->next = newnode;
newnode->pre = prepos;
newnode->next = pos;
pos->pre = newnode;
}
由此可以将此函数复用于尾插和头插函数中
尾插复用
:
void ListPushBack(LTNode* phead, LTDatatype x)
{
assert(phead);
//插入函数在尾插中的复用
ListInsert(phead, x);
}
头插复用
:
void ListPushFront(LTNode* phead, LTDatatype x)
{
assert(phead);
//插入函数在头插中的复用
ListInsert(phead->next,x);
}
11.链表删除结点
void ListErase(LTNode* pos)
{
assert(pos);
LTNode* prepos = pos->pre;
LTNode* postpos = pos->next;
prepos->next = postpos;
postpos->pre = prepos;
free(pos);
}
由此可以将此函数复用于尾删和头删函数中
尾删复用
:
void ListPopBack(LTNode* phead)
{
assert(phead);
assert(phead->pre != phead);
//删除函数在尾删中的复用
ListErase(phead->pre);
}
头删复用
:
void ListPopFront(LTNode* phead)
{
assert(phead);
assert(phead->next!=phead);
//删除函数在头删中的复用
ListErase(phead->next);
}
12.代码演示
void test();
int main()
{
test1();
return 0;
}
void test1()
{
LTNode* plist = NULL;
//初始化
plist=ListInit();
//尾插
printf("尾插1 2 3 4 \\n");
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushBack(plist, 4);
ListPrint(plist);
//尾删
printf("尾删\\n");
ListPopBack(plist);
ListPrint(plist);
//头插
printf("头插1 2 3 4 \\n");
ListPushFront(plist, 1);
ListPushFront(plist, 2);
ListPushFront(plist, 3);
ListPushFront(plist, 4);
ListPrint(plist);
//头删
printf("头删\\n");
ListPopFront(plist);
ListPrint(plist);
//查找
printf("查找2的位置\\n");
LTNode* pos=ListFind(plist,2);
printf("2的位置在pos=%p\\n", pos);
//插入
printf("在2之前插入6\\n");
ListInsert( pos, 6);
ListPrint(plist);
}
青山不改 绿水长流
以上是关于C语言数据结构——带哨兵结点的循环双向链表的主要内容,如果未能解决你的问题,请参考以下文章