typedef int DLDataType;
typedef struct DLinkList {
DLDataType data;
struct DLinkList* prev;
struct DLinkList* next;
}DList;
接下去我们来看看双链表的接口算法实现。内容还是和单链表基本一致,只是内部实现的算法逻辑需要做一个改动
/*初始化结点*/
DList* DlistInit()
{
DList* phead = DListBugNode(-1);
phead->prev = phead;
phead->next = phead;
return phead;
}
DList* phead = DlistInit();
/*开辟一个结点空间*/
DList* DListBugNode(DLDataType x)
{
DList* newnode = (DList*)malloc(sizeof(DList));
if (newnode == NULL) {
perror("fail malloc");
exit(-1);
}
newnode->data = x;
newnode->prev = NULL;
newnode->next = NULL;
return newnode;
}
//1、首先需要找到尾指针
DList* tail = phead->prev;
//2、修改指针域进行插入
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
那有同学说,真的就是这么简单吗?是的,真的就是这样。为什么不禁锢你的思维,我们再来看一种特殊的
//1.先找到尾指针
DList* tail = phead->prev;
//2.保存待删结点的上一个结点
DList* pre = tail->prev;
//3.修改指针域进行删除
pre->next = phead;
phead->prev = pre;
free(tail);
DList* newnode = DListBugNode(x);
先去修改待插入结点和首结点的指针指向
,若是你直接去修改头结点和待插入结点的指针指向,因为头结点的【next】域存放的是首结点的地址,若是随意修改,就找不到首结点了//需要考虑顺序
newnode->next = phead->next;
phead->next->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
DList* first = phead->next;
//无需考虑顺序
phead->next = newnode;
newnode->prev = phead;
newnode->next = first;
first->prev = newnode;
接下来看看特殊的插入
cur->next->next
】这样的代码,所以会定义一些变量来帮助大家理解DList* cur = phead->next;
DList* nextNode = cur->next;
phead->next = nextNode;
nextNode->prev = phead;
free(cur);
/*查找*/
DList* DListFind(DList* phead, DLDataType x)
{
DList* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
}
DList* pre = pos->prev;
pre->next = newnode;
newnode->prev = pre;
newnode->next = pos;
pos->prev = newnode;
/*插入 - 万能版*/
void DListInsert2(DList* phead, DList* pos, DLDataType x)
{
if (pos == phead->next)
DListPushFront(phead, x);
else if (pos == phead)
DListPushBack(phead, x);
else
{
DList* pre = pos->prev;
DList* newnode = DListBugNode(x);
pre->next = newnode;
newnode->prev = pre;
newnode->next = pos;
pos->prev = newnode;
}
}
/*头插*/
DListInsert1(phead->next, x);
/*尾插*/
DListInsert1(phead, x);
/*插入 - 复用版*/
void DListInsert1(DList* pos, DLDataType x)
{
assert(pos);
DList* pre = pos->prev;
DList* newnode = DListBugNode(x);
pre->next = newnode;
newnode->prev = pre;
newnode->next = pos;
pos->prev = newnode;
}
Insert
),一定有删除(Erase
)/*删除 - 万能版*/
void DListErase2(DList* phead, DList* pos)
{
assert(pos);
if (pos == phead->next)
DListPopFront(phead); //传入的是phead,不传pos,否则会出错【用的还是同一个头】
else if (pos == phead->prev)
DListPopBack(phead); //传入的是phead,不传pos,否则会出错
else
{
DList* pre = pos->prev;
DList* nextNode = pos->next;
free(pos);
pre->next = nextNode;
nextNode->prev = pre;
}
}
/*头删*/
DListErase1(phead->next);
/*尾删*/
DListErase1(phead->prev);
/*删除 - 复用版*/
void DListErase1(DList* pos)
{
assert(pos);
DList* pre = pos->prev;
DList* nextNode = pos->next;
free(pos);
pre->next = nextNode;
nextNode->prev = pre;
}
可以看出,直接万用版比较灵活,就是需要去查找位置,直接复用版只能进行头插和尾插,比较方便,无需查找位置。看自己喜好使用
/*打印*/
void DListPrint(DList* phead)
{
DList* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
bool DListEmpty(DList* phead)
{
return phead->next == phead;
}
typedef int DLDataType;
/*求解链表的大小*/
size_t DListSize(DList* phead)
{
size_t sz = 0;
DList* cur = phead->next;
while (cur != phead)
{
sz++;
cur = cur->next;
}
return sz;
}
/*释放链表*/
void DListDestroy(DList* phead)
{
DList* cur = phead->next;
while (cur != phead)
{
DList* nextNode = cur->next;
free(cur);
cur = nextNode; //迭代
}
free(phead); //链表释放完后释放头结点
}
#pragma once
#include
#include
#include
#include
typedef int DLDataType;
typedef struct DLinkList {
DLDataType data;
struct DLinkList* prev;
struct DLinkList* next;
}DList;
DList* DListBugNode(DLDataType x);
DList* DlistInit();
void DListPushBack(DList* phead, DLDataType x);
void DListPopBack(DList* phead);
void DListPushFront(DList* phead, DLDataType x);
void DListPopFront(DList* phead);
void DListInsert1(DList* pos, DLDataType x);
void DListInsert2(DList* phead, DList* pos, DLDataType x);
void DListErase1(DList* pos);
void DListErase2(DList* phead, DList* pos);
void DListPrint(DList* phead);
DList* DListFind(DList* phead, DLDataType x);
bool DListEmpty(DList* phead);
size_t DListSize(DList* phead);
void DListDestroy(DList* phead);
DList.c
#define _CRT_SECURE_NO_WARNINGS 1
/*
* 带头双向循环链表
*/
#include "DList.h";
/*开辟一个结点空间*/
DList* DListBugNode(DLDataType x)
{
DList* newnode = (DList*)malloc(sizeof(DList));
if (newnode == NULL) {
perror("fail malloc");
exit(-1);
}
newnode->data = x;
newnode->prev = NULL;
newnode->next = NULL;
return newnode;
}
/*初始化结点*/
DList* DlistInit()
{
DList* phead = DListBugNode(-1);
phead->prev = phead;
phead->next = phead;
return phead;
}
/*尾插*/
void DListPushBack(DList* phead, DLDataType x)
{
//assert(phead);
//DList* newnode = DListBugNode(x);
1、首先需要找到尾指针
//DList* tail = phead->prev;
2、修改指针域进行插入
//tail->next = newnode;
//newnode->prev = tail;
//newnode->next = phead;
//phead->prev = newnode;
DListInsert1(phead, x);
}
/*尾删*/
void DListPopBack(DList* phead)
{
//assert(phead);
1.先找到尾指针
//DList* tail = phead->prev;
2.保存待删结点的上一个结点
//DList* pre = tail->prev;
3.修改指针域进行删除
//pre->next = phead;
//phead->prev = pre;
//free(tail);
DListErase1(phead->prev);
}
/*头插*/
void DListPushFront(DList* phead, DLDataType x)
{
//assert(phead);
//DList* newnode = DListBugNode(x);
//需要考虑顺序
//newnode->next = phead->next;
//phead->next->prev = newnode;
//
//phead->next = newnode;
//newnode->prev = phead;
//可以先保存头结点的下一结点
//DList* first = phead->next;
无需考虑顺序
//phead->next = newnode;
//newnode->prev = phead;
//newnode->next = first;
//first->prev = newnode;
DListInsert1(phead->next, x);
}
/*头删*/
void DListPopFront(DList* phead)
{
//assert(phead);
//DList* cur = phead->next;
//DList* nextNode = cur->next;
//phead->next = nextNode;
//nextNode->prev = phead;
//free(cur);
DListErase1(phead->next);
}
/*查找*/
DList* DListFind(DList* phead, DLDataType x)
{
DList* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
}
/*插入 - 复用版*/
void DListInsert1(DList* pos, DLDataType x)
{
assert(pos);
DList* pre = pos->prev;
DList* newnode = DListBugNode(x);
pre->next = newnode;
newnode->prev = pre;
newnode->next = pos;
pos->prev = newnode;
}
/*插入 - 万能版*/
void DListInsert2(DList* phead, DList* pos, DLDataType x)
{
if (pos == phead->next)
DListPushFront(phead, x);
else if (pos == phead)
DListPushBack(phead, x);
else
{
DList* pre = pos->prev;
DList* newnode = DListBugNode(x);
pre->next = newnode;
newnode->prev = pre;
newnode->next = pos;
pos->prev = newnode;
}
}
/*删除 - 复用版*/
void DListErase1(DList* pos)
{
assert(pos);
DList* pre = pos->prev;
DList* nextNode = pos->next;
free(pos);
pre->next = nextNode;
nextNode->prev = pre;
}
/*删除 - 万能版*/
void DListErase2(DList* phead, DList* pos)
{
assert(pos);
if (pos == phead->next)
DListPopFront(phead);
else if (pos == phead->prev)
DListPopBack(phead);
else
{
DList* pre = pos->prev;
DList* nextNode = pos->next;
free(pos);
pre->next = nextNode;
nextNode->prev = pre;
}
}
/*打印*/
void DListPrint(DList* phead)
{
DList* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
/*判空*/
bool DListEmpty(DList* phead)
{
return phead->next == phead;
}
/*求解链表的大小*/
size_t DListSize(DList* phead)
{
size_t sz = 0;
DList* cur = phead->next;
while (cur != phead)
{
sz++;
cur = cur->next;
}
return sz;
}
/*释放链表*/
void DListDestroy(DList* phead)
{
DList* cur = phead->next;
while (cur != phead)
{
DList* nextNode = cur->next;
free(cur);
cur = nextNode; //迭代
}
free(phead); //链表释放完后释放头结点
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "DList.h"
/*头插、尾插、头删、尾删*/
void DListTest1()
{
DList* phead = DlistInit();
DListPushBack(phead, 1);
DListPushBack(phead, 2);
DListPushBack(phead, 3);
DListPushBack(phead, 4);
DListPushBack(phead, 5);
DListPrint(phead);
DListPopBack(phead);
DListPrint(phead);
DListPushFront(phead, 9);
DListPushFront(phead, 11);
DListPrint(phead);
DListPopFront(phead);
DListPopFront(phead);
DListPopFront(phead);
DListPopFront(phead);
DListPopFront(phead);
//DListPopFront(phead);
DListPrint(phead); //此时头结点的prev和next相同,都指向自己
DListDestroy(phead);
}
/*查找结点*/
void DListTest2()
{
DList* phead = DlistInit();
DListPushBack(phead, 1);
DListPushBack(phead, 2);
DListPushBack(phead, 3);
DListPushBack(phead, 4);
DListPushBack(phead, 5);
DListPrint(phead);
DList* pos = DListFind(phead, 3);
if (pos)
{
pos->data *= 10;
}
DListPrint(phead);
DListDestroy(phead);
}
/*Insert插入 - 直接复用版*/
void DListTest3()
{
DList* phead = DlistInit();
DListPushFront(phead, 1);
DListPushFront(phead, 2);
DListPushFront(phead, 3);
DListPushFront(phead, 4);
DListPushFront(phead, 5);
DListPrint(phead);
DListPushBack(phead, 6);
DListPushBack(phead, 7);
DListPushBack(phead, 8);
DListPushBack(phead, 9);
DListPushBack(phead, 10);
DListPrint(phead);
DListDestroy(phead);
}
/*Insert插入 - 直接万用版*/
void DListTest4()
{
DList* phead = DlistInit();
DListPushBack(phead, 1);
DListPushBack(phead, 2);
DListPushBack(phead, 3);
DListPushBack(phead, 4);
DListPushBack(phead, 5);
DListPrint(phead);
DList* pos = DListFind(phead, 3); //中间结点
if (pos)
{
DListInsert2(phead, pos, 9);
}
DListPrint(phead);
pos = DListFind(phead, 1); //首结点 - 头插
if (pos)
{
DListInsert2(phead, pos, 99);
}
DListPrint(phead);
pos = DListFind(phead, -1); //链表头结点 - 尾插
if (pos)
{
DListInsert2(phead, pos, 999);
}
DListPrint(phead);
DListDestroy(phead);
}
/*Erase删除 - 直接复用版*/
void DListTest5()
{
DList* phead = DlistInit();
DListPushFront(phead, 1);
DListPushFront(phead, 2);
DListPushFront(phead, 3);
DListPushFront(phead, 4);
DListPushFront(phead, 5);
DListPushBack(phead, 6);
DListPushBack(phead, 7);
DListPushBack(phead, 8);
DListPushBack(phead, 9);
DListPushBack(phead, 10);
DListPrint(phead);
DListPopFront(phead);
DListPopBack(phead);
DListPrint(phead);
DListPopFront(phead);
DListPopBack(phead);
DListPrint(phead);
DListPopFront(phead);
DListPopBack(phead);
DListPrint(phead);
DListPopFront(phead);
DListPopBack(phead);
DListPrint(phead);
DListDestroy(phead);
}
/*Erase删除 - 直接万用版*/
void DListTest6()
{
DList* phead = DlistInit();
DListPushBack(phead, 1);
DListPushBack(phead, 2);
DListPushBack(phead, 3);
DListPushBack(phead, 4);
DListPushBack(phead, 5);
DListPrint(phead);
DList* pos = DListFind(phead, 2);
if (pos)
DListErase2(phead, pos);
DListPrint(phead);
pos = DListFind(phead, 5);
if (pos)
DListErase2(phead, pos);
DListPrint(phead);
pos = DListFind(phead, 1);
if (pos)
DListErase2(phead, pos);
DListPrint(phead);
DListDestroy(phead);
}
/*头删复用Erase*/
void DListTest7()
{
DList* phead = DlistInit();
DListPushBack(phead, 1);
DListPushBack(phead, 2);
DListPushBack(phead, 3);
DListPushBack(phead, 4);
DListPushBack(phead, 5);
DListPrint(phead);
DListPopFront(phead);
DListPrint(phead);
DListPopFront(phead);
DListPrint(phead);
DListPopFront(phead);
DListPrint(phead);
DListPopFront(phead);
DListPrint(phead);
DListPopFront(phead);
DListPrint(phead);
DListDestroy(phead);
}
/*。。。*/
void DListTest8()
{
DList* phead = DlistInit();
bool ret = DListEmpty(phead);
if (ret)
printf("链表为空\n");
else
printf("链表不为空\n");
DListPushBack(phead, 1);
DListPushBack(phead, 2);
DListPushBack(phead, 3);
DListPushBack(phead, 4);
DListPushBack(phead, 5);
DListPrint(phead);
ret = DListEmpty(phead);
if (ret)
printf("链表为空\n");
else
printf("链表不为空\n");
size_t sz = DListSize(phead);
printf("当前链表大小为:%d\n", sz);
DListDestroy(phead);
}
int main(void)
{
//DListTest1();
//DListTest2();
//DListTest3();
//DListTest4();
//DListTest5();
//DListTest6();
//DListTest7();
DListTest8();
return 0;
}
OK,以上就是本文所要介绍的所有内容,非常感谢您的观看,如有疑问请于评论区留言或者私信我都可以🍀