提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前期准备
1.头文件
typedef int LNodeData;
typedef struct ListNode
{
struct ListNode* prev;
LNodeData data;
struct ListNode* next;
}LNode;
//创建结点
LNode* BuyListNode(LNodeData x);
//初始化
LNode* ListInit();
//打印
void ListPrint(LNode* phead);
//头插
void ListPushFront(LNode* phead, LNodeData x);
//尾插
void ListPushBack(LNode* phead, LNodeData x);
//头删
void ListPopFront(LNode* phead);
//尾删
void ListPopBack(LNode* phead);
//判空
bool ListEmpty(LNode* phead);
//查找
LNode* ListFind(LNode* phead, LNodeData x);
//长度
int ListSize(LNode* phead);
//在pos之前插入
void ListInsert(LNode* pos, LNodeData x);
//在pos位置删除
void ListErase(LNode* pos);
//销毁
void ListDestory(LNode* phead);
2.创建结点
LNode* BuyListNode(LNodeData x)
{
LNode* newnode = (LNode*)malloc(sizeof(LNode));
if (newnode == NULL)
{
printf("malloc fail");
exit(-1);
}
newnode->next = NULL;
newnode->prev = NULL;
newnode->data = x;
return newnode;
}
3.打印
//打印
void ListPrint(LNode* phead)
{
LNode* cur = phead->next;
while (cur!= phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
4.销毁
//销毁
void ListDestory(LNode* phead)
{
assert(phead);
LNode* cur = phead->next;
while(cur != phead)
{
LNode* next = cur->next;
ListErase(cur);
cur = next;
}
free(phead);
}
一、头插和尾插
1.头插
//头插
void ListPushFront(LNode* phead, LNodeData x)
{
//三种方法
assert(phead);
LNode* newnode = BuyListNode(x);
//无需按序写代码,记得保存后一位的地址
LNode* next = phead->next;
phead->next = newnode;
newnode->prev = phead;
newnode->next = next;
next->prev = newnode;
//需要按照顺序写
newnode->next = phead->next;
phead->next->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
ListInsert(phead->next, x);//之后函数的复用实现头插
//三者选其一即可
}
2.尾插
//尾插
void ListPushBack(LNode* phead, LNodeData x)
{
//三种方法
assert(phead);
LNode* newnode = BuyListNode(x);
//无需按序,记得存尾指针
LNode* tail = phead->prev;
phead->prev = newnode;
newnode->prev = tail;
newnode->next = phead;
tail->next = newnode;
//需要按序
newnode->prev = phead->prev;
phead->prev->next = newnode;
phead->prev = newnode;
newnode->next = phead;
ListInsert(phead, x);//之后可函数的复用来实现尾插
//三者选其一即可
}
二、头删和尾删
1.头删
//头删
void ListPopFront(LNode* phead)
{
assert(phead);
assert(!ListEmpty(phead));//判断是否为空
//LNode* next = phead->next;
//phead->next = next->next;
//next->prev = phead;
//free(next);
//用有序的话,free不掉头节点
ListErase(phead->next);//函数的复用
}
2.尾删
//尾删
void ListPopBack(LNode* phead)
{
assert(phead);
assert(!ListEmpty(phead));//判断是否为空
LNode* tail = phead->prev;
//无需按序
LNode* tailPrev = tail->prev;
phead->prev = tailPrev;
tailPrev->next= phead;
//需要按序
phead->prev = tail->prev;
tail->prev->next = phead;
free(tail);
ListErase(phead->prev);//函数的复用
//三种方法任选其一即可
}
三、判空、长度和查找
1.判空
//判空
bool ListEmpty(LNode* phead)
{
assert(phead);
return phead->next==phead;//true为空,false不为空
}
2.长度
//长度
int ListSize(LNode* phead)
{
assert(phead);
LNode* cur = phead->next;
int size = 0;
while (cur != phead)
{
size++;
cur = cur->next;
}
return size;
}
3.查找
//查找
LNode* ListFind(LNode* phead, LNodeData x)
{
assert(phead);
LNode* cur = phead->next;
while (cur != phead)//当cur等于哨兵位时,结束链表
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
四、插入和删除
1.插入
//在pos之前插入
void ListInsert(LNode* pos, LNodeData x)
{
assert(pos);
LNode* newnode = BuyListNode(x);
//无需按序
LNode* prev = pos->prev;
newnode->next = pos;
newnode->prev = prev;
prev->next = newnode;
pos->prev = newnode;
//需要按序
newnode->prev = pos->prev;
pos->prev->next = newnode;
newnode->next = pos;
pos->prev = newnode;
}
2.删除
//在pos位置删除
void ListErase(LNode* pos)
{
assert(pos);
LNode* next = pos->next;//保存前一个和后一个
LNode* prev = pos->prev;
next->prev = prev;
prev->next = next;
free(pos);
}
五、实现
void test()
{
LNode* plist = ListInit();
//尾插
ListPushBack(plist, 5);
ListPushBack(plist, 4);
ListPushBack(plist, 3);
ListPushBack(plist, 2);
ListPushBack(plist, 1);
//头插
ListPushFront(plist, 5);
ListPushFront(plist, 4);
ListPushFront(plist, 3);
ListPushFront(plist, 2);
ListPushFront(plist, 1);
ListPushFront(plist, 5);
ListPushFront(plist, 4);
ListPushFront(plist, 3);
ListPushFront(plist, 2);
ListPushFront(plist, 1);
ListPrint(plist);
//头删
ListPopFront(plist);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
//尾删
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
//查找
LNode* pos = ListFind(plist, 2);
if (pos)
{
printf("找到了\n");
}
else
{
printf("没找到\n");
}
//长度
printf("%d\n", ListSize(plist));
//插入
ListInsert(pos, 20);
ListPrint(plist);
//删除
ListErase(pos);
ListPrint(plist);
//销毁
ListDestory(plist);
plist = NULL;
}
int main()
{
test();
return 0;
}
总结
以上为带头双向循环链表的实现过程,这是链表中结构最复杂但写起来最简单的一个链表,链表已经全部写完,下一步开始写栈,队列,二叉树等等结构,以及他们的OJ题。