数据结构-双向链表的基本操作 详解(c语言实现)
Posted 许同学。。
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构-双向链表的基本操作 详解(c语言实现)相关的知识,希望对你有一定的参考价值。
1.创造一个节点,函数实现
DListNode* BuyListNode(Datetype x)
{
DListNode*node = (DListNode*)malloc(sizeof(DListNode));
node->date = x;
node->next = NULL;
node->prev = NULL;
return node;
}
2. 初始化
DListNode* DListInit()
{
DListNode*plist = BuyListNode(0);
plist->date = 0;
plist->next = plist;
plist->prev = plist;
return plist;
}
//既然是双向循环链表,初始化的时候,prev与next需要指向自己。
既然是双向循环链表,初始化的时候,prev与next需要指向自己。
3.判空
int DListIsEmpty(DListNode*plist)
{
return plist->next == plist ? 1 : 0;
}
只有一个头节点的时候,链表为空。
4.头插
void DListPushFront(DListNode*plist,Datetype x)
{
DListNode*first = plist->next;
DListNode*newnode = BuyListNode(x);
newnode->prev = plist;
plist->next = newnode;
newnode->next=first;
first->prev = newnode;
}
//只有一个头结点时,代码也是正确的。
只有一个头节点时,代码也是正确的。
5.尾插
void DListPushBack(DListNode*plist,Datetype x)
{
if (DListIsEmpty(plist))
{
return;
}
//如果是空表的话,就与尾插这个定义矛盾了。
DListNode*tail = plist->prev;
DListNode*newnode = BuyListNode(x);
tail->next = newnode;
newnode->prev = tail;
newnode->next = plist;
plist->prev = newnode;
}
尾插肯定需要找尾。
6.头删
void DListPopFront(DListNode*plist)
{
if (DListIsEmpty(plist))
{
return;
}
DListNode*first = plist->next;
DListNode*next = first->next;
free(first);
first = NULL;
plist->next = next;
next->prev = plist;
}
一个头节点与一个节点和一个头节点与多个节点代码都是一样的。
7.尾删
void DListPopBack(DListNode*plist)
{
if (DListIsEmpty(plist))
{
return;
}
DListNode*tail = plist->prev;
DListNode*tailprev = tail->prev;
free(tail);
tail = tailprev;
tail->next = plist;
plist->prev = tail;
}
一个头节点与一个节点和一个头节点与多个节点代码都是一样的。
8.查找数据
DListNode* DListFind(DListNode*plist,Datetype x)
{
DListNode*cur = plist->next;
while (cur != plist)
{
if (cur->date == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
查找数据成功后 就返回数据的地址 。
9.在pos下一个位置插入数据
void DListInsertAfter(DListNode*pos, Datetype x)
{
assert(pos);//保证传过来的地址不能为空
DListNode*next = pos->next;
DListNode*newnode = BuyListNode(x);
pos->next = newnode;
newnode->prev = pos;
newnode->next = next;
next->prev = newnode;
}
需要注意的是 pos不能为空。
10.在pos的上一个位置插入数据
void DListInsertBefore(DListNode*pos, Datetype x)
{
assert(pos);
DListNode*prev = pos->prev;
DListNode*newnode = BuyListNode(x);
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
一个头节点和一个有效节点时 代码也正确。
11.修改pos位置的数据
void DListModify(DListNode*pos, Datetype x)
{
assert(pos);
pos->date = x;
}
12.删除pos位置的数据
void DListErase(DListNode*pos)
{
assert(pos);
DListNode*next = pos->next;
DListNode*prev = pos->prev;
free(pos);
pos = next;
prev->next = next;
next->prev = prev;
}
13.链表的有效长度(不包括头节点)
int DListSize(DListNode*plist)
{
DListNode*cur = plist->next;
int size = 0;
while (cur != plist)
{
cur = cur->next;
++size;
}
return size;
}
14.打印链表(测试各个接口)
void Print(DListNode*plist)
{
DListNode*cur = plist->next;
while (cur != plist)
{
printf("%3d", cur->date);
cur = cur->next;
}
printf("\\n");
}
15.销毁链表
void Destory(DListNode*plist)
{
DListNode*cur = plist->next;
while (cur != plist)
{
DListNode*next = cur->next;
free(cur);
cur = next;
}
free(plist);
plist = cur = NULL;
}
//因为这里传的是一级指针,主函数定义的phead也需要置空,防止phead成为野指针。
因为这里传的是一级指针,主函数定义的phead也需要置空,防止phead成为野指针。
16.测试
test()
{
//头插3个数据
DListNode*phead = DListInit();
DListPushFront(phead, 3);
DListPushFront(phead, 2);
DListPushFront(phead, 1);
Print(phead);
//尾插3个数据
DListPushBack(phead, 4);
DListPushBack(phead, 5);
DListPushBack(phead, 6);
Print(phead);
//头删1个数据
DListPopFront(phead);
Print(phead);
//尾删1个数据
DListPopBack(phead);
Print(phead);
//查找数据,如果查找数据成功了,就返回数据的地址,失败,就返回空。
DListNode* pos = DListFind(phead, 3);
if (pos)
{
printf(" Date found");
printf("\\n");
}
//在pos下一个位置插入1个数据
DListInsertAfter(pos, 7);
Print(phead);
//在pos的上一个位置插入1个数据
DListInsertBefore(pos, 8);
Print(phead);
//将pos位置的数据改变
DListModify(pos, 9);
Print(phead);
//消除pos位置的数据
DListErase(pos);
Print(phead);
//计算出链表中的有效数字
printf(" %d\\n",DListSize(phead));
Destory(phead);
phead = NULL;//防止phead成为野指针
}
双向链表的基本操作就分享到这里了,谢谢你的浏览,如果这篇博文对你有帮助的话,可以点个赞,顺手再来个关注。
下期将发布与字符串函数的相关内容的文章。
以上是关于数据结构-双向链表的基本操作 详解(c语言实现)的主要内容,如果未能解决你的问题,请参考以下文章