哈喽大家好呀!下面是我对双链表的实现笔记~和我一起来看一下吧!要想这类链表更好的实现还需要使用画图功能,才不会乱套
目录
一、链表的分类
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构:
1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结 构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都 是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带 来很多优势,实现反而简单了,后面我们代码实现了就知道了。
二、双链表的实现
双链表这里使用带哨兵位的结构:
双向链表的初始化
LTNode* LTInit()
{
LTNode* phead=BuyLTNode(-1);//申请一个结点放phead
phead->next = phead;
phead->prev = phead;
return phead;
}
双向链表的销毁
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
双向链表的打印
void LTPrint(LTNode* phead)
{
assert(phead);
printf("guard<==>");
LTNode* cur = phead->next;
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 = BuyLTNode(x);tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
头插
void LTPushFront(LTNode* phead, LTDatatype x)
{
assert(phead);LTNode* newnode = BuyLTNode(x);
newnode->next = phead->next;
phead->next->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
}
结点申请
LTNode* BuyLTNode(LTDatatype x)
{
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode==NULL)
{
perror("malloc fail");
return NULL;
}
newnode->data = x;
newnode->next = NULL;
newnode->prev = NULL;
return newnode;
}
双向链表的删除
删除前要先判断链表是否为空
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead->next == phead;//相等返回true,否则false
}
后删
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;
//free(tail);//先后有什么区别
}
头删
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
LTNode* next = phead->next;//找到头节点
phead->next = next->next;
next->next->prev = phead;
free(next);
}
任意位置的插入和删除
//在Pos前插入
void LTInsert(LTNode* pos, LTDatatype x)
{
assert(pos);
LTNode* newnode = BuyLTNode(x);
LTNode* posprev = pos->prev;
posprev->next =newnode ;
newnode->prev = posprev;
newnode->next = pos;
pos->prev = newnode;
}
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* posprev = pos->prev;
LTNode* next = pos->next;
posprev->next = next;
next->prev = posprev;
free(pos);
}
接下来是对双链表的测试使用
#define _CRT_SECURE_NO_WARNINGS 1
#include"list.h"
void Testlist1()
{
LTNode* plist = LTInit();
LTPushBack(plist, 1);
LTPushBack(plist, 2);
LTPushBack(plist, 3);
LTPushBack(plist, 4);
LTPrint(plist);
LTDestroy(plist);
}
void Testlist2()
{
LTNode* plist = LTInit();
LTPushFront(plist, 1);
LTPushFront(plist, 2);
LTPushFront(plist, 3);
LTPushFront(plist, 4);
LTPrint(plist);
LTPopBack(plist);
LTPrint(plist);
LTPopFront(plist);
LTPrint(plist);
LTDestroy(plist);
}
void Testlist3()
{
LTNode* plist = LTInit();
LTPushFront(plist, 1);
LTPushFront(plist, 2);
LTPushFront(plist, 3);
LTPushFront(plist, 4);
LTPrint(plist);
LTNode* pos = LTFind(plist, 3);
/*if (pos)
{
LTInsert(pos, 20);
}
LTPrint(plist);*/
if (pos)
{
LTErase(pos);
}
LTPrint(plist);
LTDestroy(plist);
}
int main()
{
Testlist3();
return 0;
}
测试结果