目录
链表的结构非常多样,组合起来有八种链表结构,但是常用的则是两种,一种就是上一篇文章介绍的无头单向非循环链表,还有一种就是本篇文章要介绍的双向带头循环链表。
介绍:
结构最复杂的一种链表结构,一般用来单独存储数据。这个结构虽然复杂,但是使用代码实现反而相较于无头单向非循环链表在逻辑上更加简单。
接口:
基本的功能就是有以下这些:
//初始化 创建哨兵位
DLTNode* DLTInit();
//打印
void DLTPrintf(DLTNode* phead);
//尾插
void DLTpushback(DLTNode* phead, DLTdatetype x);
//头插
void DLTpushfront(DLTNode* phead, DLTdatetype x);
//尾删
void DLTpopback(DLTNode* phead);
//头删
void DLTpopfront(DLTNode* phead);
//查找
DLTNode* DLTfind(DLTNode* phead, DLTdatetype x);
//在pos前插入
void DLTInsert(DLTNode* phead, DLTdatetype x);
//删除pos位置的值
void DLTErase(DLTNode* phead);
//销毁
void DLTDestroy(DLTNode* phead);
接口实现:
初始化:
DLTNode* Creatnewnode(DLTdatetype x)
{//开辟空间
DLTNode* newnode = (DLTNode*)malloc(sizeof(DLTNode));
if (newnode == NULL)
{
perror("malloc");
return;
}
newnode->data = x;
newnode->prev = NULL;
newnode->next = NULL;
return newnode;
}
//初始化 创建哨兵位
DLTNode* DLTInit()
{
DLTNode* phead = Creatnewnode(-1);
phead->prev = phead;
phead->next = phead;
return phead;
}
打印:
//打印
void DLTPrintf(DLTNode* phead)
{
DLTNode* cur = phead->next;
printf("guard<=>");
while (cur != phead)
{
printf("%d<=>", cur->data);
cur = cur->next;
}
printf("\n");
}
尾插:
//尾插
void DLTpushback(DLTNode* phead, DLTdatetype x)
{
assert(phead);
//DLTNode* tail = phead->prev; //存尾
//DLTNode* newnode = Creatnewnode(x);
//tail->next = newnode;
//newnode->prev = tail;
//phead->prev = newnode;
//newnode->next = phead;
DLTInsert(phead, x);
//复用插入函数
}
头插:
//头插
void DLTpushfront(DLTNode* phead, DLTdatetype x)
{
assert(phead);
//DLTNode* newnode = Creatnewnode(x);
//newnode->next = phead->next;
//phead->next->prev = newnode;
//phead->next = newnode;
//newnode->prev = phead;
DLTInsert(phead->next, x);
//复用插入函数
}
尾删:
// 判空,是否只有哨兵位,没有别的节点了
bool isEmpty(DLTNode* phead)
{
assert(phead);
return phead->next == phead;
}
//尾删
void DLTpopback(DLTNode* phead)
{
assert(phead);
assert(!isEmpty(phead));
//DLTNode* end = phead->prev;
//DLTNode* last = end->prev;
//last->next = phead;
//phead->prev = last;
//free(end);
DLTErase(phead->prev);
//复用删除函数
}
头删:
// 判空,是否只有哨兵位,没有别的节点了
bool isEmpty(DLTNode* phead)
{
assert(phead);
return phead->next == phead;
}
//头删
void DLTpopfront(DLTNode* phead)
{
assert(phead);
assert(!isEmpty(phead));
//DLTNode* first = phead->next;
//DLTNode* second = first->next;
//phead->next = second;
//second->prev = phead;
//free(first);
DLTErase(phead->next);
//复用删除函数
}
查找:
//查找
DLTNode* DLTfind(DLTNode* phead, DLTdatetype x)
{
assert(phead);
DLTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
指定位置插入:
//在pos前插入
void DLTInsert(DLTNode* pos, DLTdatetype x)
{
assert(pos);
DLTNode* last = pos->prev;
DLTNode* newnode = Creatnewnode(x);
last->next = newnode;
newnode->prev = last;
newnode->next = pos;
pos->prev = newnode;
}
指定位置删除:
//删除pos位置的值
void DLTErase(DLTNode* pos)
{
assert(pos);
DLTNode* last = pos->prev;
DLTNode* Next = pos->next;
last->next = Next;
Next->prev = last;
free(pos);
}
销毁:
//销毁
void DLTDestroy(DLTNode* phead)
{
DLTNode* cur = phead->next;
while (cur != phead)
{
DLTNode* Next = cur->next;
free(cur);
cur = Next;
}
free(phead);
}
源码
附上完整代码。
声明
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int DLTdatetype;
typedef struct DListNode
{
struct DListNode* prev;
struct DListNode* next;
int data;
}DLTNode;
//初始化 创建哨兵位
DLTNode* DLTInit();
//打印
void DLTPrintf(DLTNode* phead);
//尾插
void DLTpushback(DLTNode* phead, DLTdatetype x);
//头插
void DLTpushfront(DLTNode* phead, DLTdatetype x);
//尾删
void DLTpopback(DLTNode* phead);
//头删
void DLTpopfront(DLTNode* phead);
//查找
DLTNode* DLTfind(DLTNode* phead, DLTdatetype x);
//在pos前插入
void DLTInsert(DLTNode* phead, DLTdatetype x);
//删除pos位置的值
void DLTErase(DLTNode* phead);
//销毁
void DLTDestroy(DLTNode* phead);
定义
#include"D_list.h"
DLTNode* Creatnewnode(DLTdatetype x)
{//开辟空间
DLTNode* newnode = (DLTNode*)malloc(sizeof(DLTNode));
if (newnode == NULL)
{
perror("malloc");
return;
}
newnode->data = x;
newnode->prev = NULL;
newnode->next = NULL;
return newnode;
}
//初始化 创建哨兵位
DLTNode* DLTInit()
{
DLTNode* phead = Creatnewnode(-1);
phead->prev = phead;
phead->next = phead;
return phead;
}
//打印
void DLTPrintf(DLTNode* phead)
{
DLTNode* cur = phead->next;
printf("guard<=>");
while (cur != phead)
{
printf("%d<=>", cur->data);
cur = cur->next;
}
printf("\n");
}
bool isEmpty(DLTNode* phead)
{//是否只有哨兵位,没有别的节点了
assert(phead);
return phead->next == phead;
}
//尾插
void DLTpushback(DLTNode* phead, DLTdatetype x)
{
assert(phead);
DLTInsert(phead, x);
}
//头插
void DLTpushfront(DLTNode* phead, DLTdatetype x)
{
assert(phead);
DLTInsert(phead->next, x);
}
//尾删
void DLTpopback(DLTNode* phead)
{
assert(phead);
assert(!isEmpty(phead));
DLTErase(phead->prev);
}
//头删
void DLTpopfront(DLTNode* phead)
{
assert(phead);
assert(!isEmpty(phead));
DLTErase(phead->next);
}
//查找
DLTNode* DLTfind(DLTNode* phead, DLTdatetype x)
{
assert(phead);
DLTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
//在pos前插入
void DLTInsert(DLTNode* pos, DLTdatetype x)
{
assert(pos);
DLTNode* last = pos->prev;
DLTNode* newnode = Creatnewnode(x);
last->next = newnode;
newnode->prev = last;
newnode->next = pos;
pos->prev = newnode;
}
//删除pos位置的值
void DLTErase(DLTNode* pos)
{
assert(pos);
DLTNode* last = pos->prev;
DLTNode* Next = pos->next;
last->next = Next;
Next->prev = last;
free(pos);
}
//销毁
void DLTDestroy(DLTNode* phead)
{
DLTNode* cur = phead->next;
while (cur != phead)
{
DLTNode* Next = cur->next;
free(cur);
cur = Next;
}
free(phead);
}
测试
#include"D_list.h"
void Menu()
{
printf("*******************************\n");
printf(" 1、尾插 2、头插 \n");
printf(" 3、尾删 4、头删 \n");
printf(" 5、查找 6、插入 \n");
printf(" 7、删除 8、打印 \n");
printf(" 0、退出 \n");
printf("*******************************\n");
}
int main()
{
Menu();
int input = 0;
DLTNode* plist = DLTInit();
DLTNode* tmp = NULL;
int n = 0;
int x = 0;
do
{
printf("请选择要进行的操作:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入尾插的数据个数并依次输入需要插入的数据,以空格隔开:\n");
scanf("%d", &n);
while (n--)
{
scanf("%d", &x);
DLTpushback(plist, x);
}
printf("插入成功!\n\n");
break;
case 2:
printf("请输入头插的数据个数并依次输入需要插入的数据,以空格隔开:\n");
scanf("%d", &n);
while (n--)
{
scanf("%d", &x);
DLTpushfront(plist, x);
}
printf("插入成功!\n\n");
break;
case 3:
printf("请输入需要尾删的数据个数:>");
scanf("%d", &n);
while (n--)
{
DLTpopback(plist);
}
printf("删除成功!\n\n");
break;
case 4:
printf("请输入需要头删的数据个数:>");
scanf("%d", &n);
while (n--)
{
DLTpopfront(plist);
}
printf("删除成功!\n\n");
break;
case 5:
printf("请输入查找的数据:>");
scanf("%d", &x);
tmp = DLTfind(plist, x);
if (tmp == NULL)
{
printf("无此数据!\n\n");
}
else
{
printf("查找成功!\n\n");
}
break;
case 6:
printf("请选择在那个数据的位置插入数据并输入想要插入的数据:\n");
scanf("%d %d", &n, &x);
tmp = DLTfind(plist, n);
if (tmp == NULL)
{
printf("无此数据!\n\n");
}
else
{
DLTInsert(tmp, x);
printf("插入成功\n\n");
}
break;
case 7:
printf("请输入想要删除的数据:>");
scanf("%d", &x);
tmp = DLTfind(plist, x);
if (tmp == NULL)
{
printf("无此数据!\n\n");
}
else
{
DLTErase(tmp);
printf("操作成功!\n\n");
}
break;
case 8:
DLTPrintf(plist);
printf("\n");
break;
case 0:
DLTDestroy(plist);
printf("退出程序!");
break;
}
} while (input);
return 0;
}