文章目录
一: 带头循环双链表的简介
上次的文章中我们介绍了带头非循环链表的实现情况,今天我们来介绍一下带头循环链表的情况
- 由上次的文章我们看出带头非循环双链表的尾节点和头结点没有任何直接联系 ,但是在带头循环双链表中头结点和尾结点之间建立起了直接的联系,那么这种联系是什么呢?让我们来看看今天的内容吧
- 相比于带头非循环的双链表来说循环双链表将头结点的prev指针和尾结点的next指针都利用了起来,使其在逻辑上实现了循环的效果。
- 带头指针的循环双链表图示
结点和数据类型的定义
typedef int DLDataType;
//将该链表中存储数据类型定义为int类型的
typedef struct DListNode{
DLDataType _value;
struct DListNode* _prev;
struct DListNode* _next;
}DListNode;
//双链表的结点的定义
typedef struct DList{
DListNode* head;
}DList;
//用于指向双链表的结构体指针
二:功能实现
2.1:用于申请新的结点
//申请新的结点node
DListNode* DListBuyNode(DLDataType value){
DListNode* node=(DListNode*)malloc(sizeof(DListNode));
node->_value=value;
node->_prev=NULL;
node->_next=NULL;
return node;
}
- 将新结点的_prev和_next指针设置为空
2.2:将双链表头结点进行处理
void DListInit(DList* dlist){
assert(dlist!=NULL);
DListNode* node=DListBuyNode(0);
dlist->head=node;
node->_prev=node->_next=dlist->head;
}
- 初始化后的理论结构
2.3:清空双链表
- 算法思想
- 1.找到头结点下一个结点
- 2.使用两个指针(防止链表结点的丢失)一个结点一个结点的进行删除
- 3.最后将双链表头结点设置为初始化后的状态
void DListClear(DList* dlist){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_next;
while(cur!=dlist->head){
DListNode* tmp=cur;
free(tmp);
cur=cur->_next;
}
dlist->head->_next=dlist->_head;
dlist->head->_prev=dlist->_head;
}
2.4:销毁双链表
- 算法思想
- 1.将双链表清空
- 2.将头结点释放
void DListDestory(DList* dlist){
assert(dlist!=NULL);
if(dlist->head->_next!=NULL)
DListClear(dlist);
free(dlist->head);
dlist->head=NULL;
}
2.5: 头插
- 算法思想
- 1.申请一个新的结点
- 2.将新的结点插入到头结点之后,注意:在进行结点的插入时要十分注意不能破坏整个链表的连接性
void DListPushFront(DList* dlist,DLDataType value){
assert(dlist!=NULL);
DListNode* new_node=DListBuyNode(value);
new_node->_next=dlist->head;
new_node->_prev=dlist->head;
dlist->head->_next=new_node;
dlist->head->_prev=new_node;
}
2.5:尾插
- 算法思想
- 1.申请一个新的结点
- 2.找到头结点的上一个结点
- 3.将新的结点插到头结点之前
void DListPushBack(DList* dlist,DLDataType value){
assert(dlist!=NULL);
DListNode* new_node=DListBuyNode(value);
new_node->_prev=dlist->head->_prev;
dlist->head->_prev->_next=new_node;
new_node->_next=dlist->head;
dlist->head->_prev=new_node;
}
2.6:查找
- 算法思想
- 1.找到头结点的下一个结点
- 2.使用指针遍历整个链表,当找到与指定值相等的结点的时候,返回该节点地址
- 3.没有找到则返回NULL
DListNode* DListFind(const DList* dlist,DLDataType value){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_next;
while(cur!=dlist->head){
if(cur->_value==value)
return cur;
cur=cur->_next;
}
return NULL;
}
2.7:头删
- 算法思想
- 1.找到头结点的下一个结点cur
- 2.将头结点和cur的下一个结点连接起来
- 3.释放cur指向的那个结点
void DListPopFront(DList* dlist){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_next;
dlist->head->_next=cur->_next;
cur->_next->_prev=dlist->head;
free(cur);
}
2.8:尾删
- 算法思想
- 1.找到头结点的前一个结点cur
- 2.将头结点和cur的前一个结点连接起来
- 3.释放cur指向的结点(原来的尾结点)
void DListPopBack(DList* dlist){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_prev;
cur->_prev->_next=dlist->head;
dlist->head->_prev=cur->_prev;
free(cur);
}
2.9:判空
- 算法思想
- 1.判断头结点的下一个结点是否为头结点
- 2.根据判断结果即可确定双链表是否为空
bool DListEmpty(const DList*dlist){
assert(dlist!=NULL);
if(dlist->head->_next==dlist->head)
return true;
else
return false;
}
2.10:往指定位置前插入新结点
- 算法思想
- 1.申请一个新的结点
- 2.将新的结点插入到指定结点和指定结点前一个结点之间
void DListInsert(DListNode *pos, DLDataType value){
DListNode* node=DListBuyNode(value);
node->_next=pos->_next;
pos->_next->_prev=node;
pos->_next=node;
node->_prev=pos;
}
2.11:释放特定位置的结点
- 算法思想
- 1.将指定位置的前一个结点和后一个结点进行连接
- 2.释放指定的结点
void DListErase(DListNode *pos){
pos->_prev->_next=pos->_next;
pos->_next->_prev=pos->_prev;
free(pos);
}
2.12:删除值为指定值的第一个结点
- 算法思想
- 1.找到头结点的下一个结点
- 2.遍历整个链表,查找结点值与指定值相等的结点
void ListRemove(DList * dlist, DLDataType value){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_next;
while(cur!=dlist->head){
if(cur->_value==value){
DListErase(cur);
return;
}
cur=cur->_next;
}
}
三:整体实现
DList.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int DLDataType;
typedef struct DListNode{
DLDataType _value;
struct DListNode* _prev;
struct DListNode* _next;
}DListNode;
typedef struct DList{
DListNode* head;
}DList;
void DListInit(DList* dlist);
void DListClear(DList* dlist);
void DListDestory(DList* dlist);
void DListPushFront(DList* dlist,DLDataType value);
void DListPushBack(DList* dlist,DLDataType value);
void DListPopFront(DList* dlist);
void DListPopBack(DList* dlist);
bool DListEmpty(const DList* dlist);
DListNode* DListFind(const DList *dlist,DLDataType value);
DListNode* DListBuyNode(DLDataType value);
//插
在pos的前面进行插入
void DListInsert(DListNode *pos, DLDataType value);
// 删除pos位置的节点
void DListErase(DListNode *pos);
void ListRemove(DList * dlsit, DLDataType value);
//打印
void DListPrint(const DList *dlist);
DList.c
#include"DList.h"
//申请新的结点node
DListNode* DListBuyNode(DLDataType value){
DListNode* node=(DListNode*)malloc(sizeof(DListNode));
node->_value=value;
node->_prev=NULL;
node->_next=NULL;
return node;
}
void DListClear(DList* dlist){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_next;
while(cur!=dlist->head){
DListNode* tmp=cur;
free(tmp);
cur=cur->_next;
}
dlist->head->_next=NULL;
dlist->head->_prev=NULL;
}
void DListDestory(DList* dlist){
assert(dlist!=NULL);
if(dlist->head->_next!=NULL)
DListClear(dlist);
free(dlist->head);
dlist->head=NULL;
}
void DListInit(DList* dlist){
assert(dlist!=NULL);
DListNode* node=DListBuyNode(0);
dlist->head=node;
node->_prev=node->_next=dlist->head;
}
//头插
//
void DListPushFront(DList* dlist,DLDataType value){
assert(dlist!=NULL);
DListNode* new_node=DListBuyNode(value);
new_node->_next=dlist->head;
new_node->_prev=dlist->head;
dlist->head->_next=new_node;
dlist->head->_prev=new_node;
}
//尾插
void DListPushBack(DList* dlist,DLDataType value){
assert(dlist!=NULL);
DListNode* new_node=DListBuyNode(value);
new_node->_prev=dlist->head->_prev;
dlist->head->_prev->_next=new_node;
new_node->_next=dlist->head;
dlist->head->_prev=new_node;
}
DListNode* DListFind(const DList* dlist,DLDataType value){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_next;
while(cur!=dlist->head){
if(cur->_value==value)
return cur;
cur=cur->_next;
}
return NULL;
}
void DListPopFront(DList* dlist){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_next;
dlist->head->_next=cur->_next;
cur->_next->_prev=dlist->head;
free(cur);
}
//尾删
void DListPopBack(DList* dlist){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_prev;
cur->_prev->_next=dlist->head;
dlist->head->_prev=cur->_prev;
free(cur);
}
bool DListEmpty(const DList*dlist){
assert(dlist!=NULL);
if(dlist->head->_next==dlist->head)
return true;
else
return false;
}
//插
在pos的前面进行插入
void DListInsert(DListNode *pos, DLDataType value){
DListNode* node=DListBuyNode(value);
node->_next=pos->_next;
pos->_next->_prev=node;
pos->_next=node;
node->_prev=pos;
}
// 删除pos位置的节点
void DListErase(DListNode *pos){
pos->_prev->_next=pos->_next;
pos->_next->_prev=pos->_prev;
free(pos);
}
void ListRemove(DList * dlist, DLDataType value){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_next;
while(cur!=dlist->head){
if(cur->_value==value)
DListErase(cur);
cur=cur->_next;
}
}
void DListPrint(const DList* dlist){
assert(dlist!=NULL);
DListNode* cur=dlist->head->_next;
while(cur!=dlist->head){
printf("%d<-->",cur->_value);
cur=cur->_next;
}
printf("\n");
}