当前位置:网站首页>使用C语言实现双向链表(带头结点)
使用C语言实现双向链表(带头结点)
2022-08-09 08:58:00 【Keep_Trying_Go】
目录
1.双链表
相对于单链表来说就是多一个前驱的指针prior,指向前一个节点(主要是为了方便删除和插入)。
注:由于之前的实现的单链表总是会遇到一种情况就是,如果要删除当前的节点p的话,那么只能通过一种技巧的方式计算交换值;但是如果是需要进行更加复杂的操作的话,就会比较麻烦,可能还需要辅助的指针r来指向当前节点的前驱,这会给程序写起来和理解起来带来不便,所以为了实现当前节点能够访问前驱节点,那么提出了双链表的概念。
2.双链表的相关操作
(1)数据结构的定义
#include<stdlib.h>
#include<stdio.h>
#define MAXSIZE 10
typedef int ElemType;
typedef struct DNode {
ElemType data;
struct DNode*prior,*next;
}DNode,*DLinkList;
//清单列表
void MenuLinkList(){
printf("-------------1.插入操作-------------\n");
printf("-------------2.定位插入操作---------\n");
printf("-------------3.按序查找操作---------\n");
printf("-------------4.按值查找操作---------\n");
printf("-------------5.定位删除操作---------\n");
printf("-------------6.按值删除元素---------\n");
printf("-------------7.删除整个表元素节点---\n");
printf("-------------8.表的长度-------------\n");
printf("-------------9.打印操作-------------\n");
printf("-------------10.结束操作-------------\n");
}
(2)初始化和销毁
//初始化操作
void InitDLinkList(DLinkList&L){
L=(DNode*)malloc(sizeof(DNode));
if(L==NULL){
printf("申请空间失败!\n");
return ;
}
L->prior=NULL;
L->next=NULL;
printf("申请空间成功!\n");
}
//销毁表(头节点不销毁)
DNode* DestryDLinkList(DNode*p,DLinkList&L,int flag=9){
//从尾部开始删除节点
DNode*r=p;
while(r!=L){
DNode*s=r;
r=r->prior;
r->next=s->next;
free(s);
}
//如果是结束操作的话,直接将头节点释放
if(flag==10){
free(L);
L=NULL;
}
return r;
}
这里的销毁操作主要是从最后节点开始进行删除,更加的方便,如果从头结点开始删除的话,需要判断的条件更多,相对麻烦一点,所以采用这种方法。读者自己可以实现从前往后的删除操作。
(3)判断空和表的长度
//判空
bool Empty(DLinkList L){
if(L->next==NULL){
return true;
}else{
return false;
}
}
//表的长度
int DLinkListLength(DLinkList L){
int len=0;
DNode*p=L->next;
while(p!=NULL){
len++;
p=p->next;
}
return len;
}
(4)节点的后插操作
//节点的插入操作(后插)
DNode* InsertDLinkList(DNode*p,ElemType e){
if(p==NULL){
printf("插入的节点不合法!\n");
return NULL;
}
DNode*s=(DNode*)malloc(sizeof(DNode));
s->data=e;
s->next=p->next;
p->next=s;
s->prior=p;
printf("插入节点成功!\n");
return s;
}
//在第i个位置插入节点
void InsertIDLinkList(DLinkList&L,int i,ElemType e){
DNode*p=FindDNode(L,i);
//如果是插入到尾节点
if(p->next==NULL){
InsertDLinkList(p,e);
return ;
}
//插入到中间的节点
if(p!=NULL){
DNode*s=(DNode*)malloc(sizeof(DNode));
s->data=e;
s->next=p->next;
p->next->prior=s;
p->next=s;
s->prior=p;
printf("插入节点成功!\n");
return ;
}
}
(5)按序查找第i个节点和按值查找节点
//查找第i个位序的节点
DNode*FindDNode(DLinkList L,int i){
if(L==NULL){
printf("表为空!\n");
return NULL;
}
if(i<0||i>DLinkListLength(L)){
printf("查找的位置不正确!\n");
return NULL;
}
int j=1;
DNode*p=L->next;
while(p!=NULL&&j<i){
p=p->next;
j++;
}
return p;
}
//按值查找操作
DNode*FindDElem(DLinkList L,ElemType e){
if(L==NULL){
printf("表为空!\n");
return NULL;
}
DNode*p=L->next;
while(p->data!=e){
p=p->next;
}
return p;
}
(6)定位删除和按序删除
//定位删除节点
void DeleteDLNode(DLinkList&L,int i,ElemType&e){
DNode*p=FindDNode(L,i);
e=p->data;
//如果是尾节点直接删除
if(p->next==NULL){
p->prior->next=p->next;
free(p);
return ;
}
if(p!=NULL){
DNode*s=p;
p->prior->next=s->next;
p->next->prior=s->prior;
free(s);
return ;
}
}
//按值删除
void DeleteDElem(DLinkList&L,ElemType e){
DNode*p=FindDElem(L,e);
//如果是尾节点直接删除
if(p->next==NULL){
p->prior->next=p->next;
free(p);
return ;
}
if(p!=NULL){
DNode*s=p;
p->prior->next=s->next;
p->next->prior=s->prior;
free(s);
return ;
}
}
(7)打印操作
//打印
void PrintDLinkList(DLinkList L){
DNode*p=L->next;
while(p!=NULL){
printf("%d\t",p->data);
p=p->next;
}
printf("\n");
}
(8)主函数
int main(){
DLinkList L;
InitDLinkList(L);
//对顺序表进行插入操作
ElemType x;
int flag=-1;
DNode*p=L;
//各种操作
while(1) {
int i=0;
ElemType e=0;
MenuLinkList();
printf("请输入操作: ");
scanf("%d",&flag);
int len=0;
DNode*s;
switch(flag){
case 1:
printf("请输入元素(-1_end): ");
scanf("%d",&x);
while(x!=-1) {
p=InsertDLinkList(p,x);
printf("请输入元素(-1_end): ");
scanf("%d",&x);
}
break;
case 2:
printf("请输入元素插入位置: \n");
scanf("%d",&i);
printf("请输入元素: ");
scanf("%d",&x);
InsertIDLinkList(L,i,x);
break;
case 3:
printf("请输入查找元素位置: ");
scanf("%d",&i);
s=FindDNode(L,i);
if(s!=NULL){
printf("查找的元素为 = %d\n",s->data);
}
break;
case 4:
printf("请输入要查找的值: ");
scanf("%d",&x);
s=FindDElem(L,x);
if(s!=NULL){
printf("查找的元素存在!\n");
}else{
printf("查找的元素不存在!\n");
}
break;
case 5:
printf("请输入删除的定位位置: ");
scanf("%d",&i);
DeleteDLNode(L,i,e);
printf("删除的元素为 = %d\n",e);
break;
case 6:
printf("请输入要删除的元素: ");
scanf("%d",&e);
DeleteDElem(L,e);
break;
case 7:
p=DestryDLinkList(p,L);
printf("删除成功!\n");
break;
case 8:
len=DLinkListLength(L);
printf("表的长度 = %d\n",len);
break;
case 9:
PrintDLinkList(L);
break;
default:
DestryDLinkList(p,L,flag);
printf("结束操作\n");
}
if(flag==10){
break;
}
}
return 0;
}
(9)测试
边栏推荐
- Redis redis 】 【 the expiration of listening
- VNCTF2021 部分题目复现
- 大学四年不努力,出社会后浑浑噩噩深感无力,辞去工作,从头开始
- Where does detection go forward?
- 【GNN】2022 G-Mixup: Graph Data Augmentation for Graph Classification
- nodeMCU(ESP8266)和RC522的接线图
- uva11624 Fire! (双bfs)
- 【CNN】2022 ECCV 对比视觉Transformer的在线持续学习
- 【愚公系列】2022年08月 Go教学课程 033-结构体方法重写、方法值、方法表达式
- C#获取网卡地址
猜你喜欢
图像识别后将识别结果整理成列表,点击列表可跳转到搜索页面
大学四年不努力,出社会后浑浑噩噩深感无力,辞去工作,从头开始
The working principle of switch
公司从零开发微信小程序流程
Where does detection go forward?
消息中间件(MQ)前置知识介绍(必看)
parse <compoN> error: Custom Component‘name should be form of my-component, not myComponent or MyCom
Three handshakes, four waves
VNCTF2021 部分题目复现
6000 字+,帮你搞懂互联网架构演变历程!
随机推荐
Arduino+2片74hc595 驱动8x8(共阳)点阵(1008BS)
消息中间件(MQ)前置知识介绍(必看)
GBJ610-ASEMI超薄整流扁桥GBJ610
C#获取网卡地址
Tencent cloud server is modified to root login to install pagoda panel
go Antlr重构脚本解释器如何实现
长辈相亲
政务中心导航定位系统,让高效率办事成为可能
jdbctemplate connects to sql server, the data found in the code is inconsistent with the database, how to solve it?
数据解析之bs4学习
[V&N2020 Open] Memory Forensics
【场景化解决方案】搭建数据桥梁,Dslink打通泛微系统连接流
权限管理模型 ---- ACL、RBAC和ABAC(详解)
图像识别后将识别结果整理成列表,点击列表可跳转到搜索页面
uniapp编译到小程序后丢失static文件夹问题
parse <compoN> error: Custom Component‘name should be form of my-component, not myComponent or MyCom
【场景化解决方案】OA审批与用友U9数据集成
内存监控以及优化
【场景化解决方案】构建门店通讯录,“门店通”实现零售门店标准化运营
gin中简单的curd接口例子