准备工作:
创建结构体指针
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}LTNode;
1.创建一个新的节点
基本思路:malloc节点,判断节点是否创造成功。
LTNode* BuyLTNode(LTDataType x)
{
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));//动态开辟节点
if (newnode == NULL)//判断是否malloc成功
{
printf("malloc fail\n");
exit(-1);//退出程序
}
newnode->data = x;//初始化
newnode->next = NULL;//置空
newnode->prev = NULL;//置空
return newnode;
}
2.尾插
基本思路:1)创建一个新节点
2)找到尾节点,链接即可
画图:
代码:
void LTNodePushBack(LTNode* phead, LTDataType x)
{
assert(phead);
//创建一个新节点
LTNode* newnode = BuyLTNode(x);
//链接节点
LTNode* tail = phead->prev;//找尾节点
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
3.头插
基本思路:1)创建一个新节点
2)找到第一个节点,链接节点
画图:
代码:
void LTNodePushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = BuyLTNode(x);
LTNode* first = phead->next;//找到第一个节点
//链接
newnode->next = first;
first->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
}
3.打印链表
基本思路:1)断言
2)创立cur节点,指向第一个节点
3)当cur == phead时,一轮结束。
画图:
代码:
void LTNodePrint(LTNode* phead)
{
LTNode* cur = phead->next;//一般情况下,不允许动头节点
while (cur != phead)//当指向phead时,循环结束
{
printf("%d ", cur->data);
cur = cur->next;//更新cur
}
printf("\n\n");
}
4.尾删
基本思路:1)断言
2)找到尾节点和倒数第二个节点,链接phead与tailPrev,free节点
画图:
代码:
void LTNPopBack(LTNode* phead)
{
//断言
assert(phead);
//找到尾节点和第二个尾节点
LTNode* tail = phead->prev;
LTNode* tailPrev = tail->prev;
//释放尾节点
free(tail);
tail = NULL;
//新的链接
tailPrev->next = phead;
phead->prev = tailPrev;
}
5.头删
基本思路:1)断言
2)找到第一个和第二个节点,链接phead和第二个节点,free第一个节点
画图:
代码:
void LTNPopFront(LTNode* phead)
{
//断言
assert(phead);
//找到第一个节点和第二个节点
LTNode* first = phead->next;
LTNode* second = first->next;
//释放内存
free(first);
first = NULL;
//链接
phead->next = second;
second->prev = phead;
}
6.找到pos的值
基本思路:1)断言
2)遍历链表,找到就返回链表,找不到就返回NULL
代码:
LTNode* LTNFind(LTNode* phead, LTDataType x)
{
//断言
assert(phead);
//创立一个节点
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
//找到返回节点
return cur;
}
cur = cur->next;
}
//找不到,返回NULL
return NULL;
}
7.在pos前插入新节点
基本思路:1)断言
2)创建一个新的节点,找到pos前的节点
3)链接newnode pos和pos的前一个
画图:
代码:
void LTNInsert(LTNode* pos, LTDataType x)
{
//断言
assert(pos);
//找到pos的前一个节点
LTNode* prev = pos->prev;
//创建一个新节点
LTNode* newnode = BuyLTNode(x);
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
8.删除pos节点
基本思路:1)断言
2)创建pos前后两个节点,链接,free掉pos节点
画图:
代码:
void LTNErase(LTNode* pos)
{
//断言
assert(pos);
//创建pos对应前后的节点
LTNode* prev = pos->prev;
LTNode* next = pos->next;
//释放节点
free(pos);
pos = NULL;
//链接
prev->next = next;
next->prev = prev;
}
9.销毁链表
基本思路:1)断言
2)创建cur指针记录
3)循环一次,一个节点一个节点释放。
4)phead最后释放,并置空。
代码:
void LTNDestroy(LTNode* phead)
{
//断言
assert(phead);
//创建cur指针
LTNode* cur = phead->prev;
//循环
while (cur != phead)
{
//记录下一个节点
LTNode* next = cur->next;
free(cur);
//更新
cur = next;
}
//释放并置空
free(phead);
phead = NULL;
}
头文件:
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
//双向带头循环链表
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}LTNode;
//尾插
void LTNodePushBack(LTNode* phead, LTDataType x);
LTNode* BuyLTNode(LTDataType x);
void LTNodePrint(LTNode* phead);
LTNode* LTNodeInit();
//头插
void LTNodePushFront(LTNode* phead, LTDataType x);
//尾删
void LTNPopBack(LTNode* phead);
//头删
void LTNPopFront(LTNode* phead);
//查找
LTNode* LTNFind(LTNode* phead, LTDataType x);
//在pos前面插入
void LTNInsert(LTNode* pos, LTDataType x);
//删除pos位置对应的值
void LTNErase(LTNode* pos);
//销毁链表
void LTNDestroy(LTNode* phead);