前言
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列节点组成,节点可以动态增加或者删除,节点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址(双向链表还存放上一个节点地址)的指针域。单向链表操作时只能从头节点操作,删除节点时获取前驱节点麻烦,难以取到尾节点,而双向单链循环链表弥补了以上不足。
一、结构简介
双向单链循环链表在单向链表的基础上,在指针域中增加了前驱(上一个节点)的节点地址,而头节点的前驱指针指向尾节点,如下图。
二、具体代码
代码如下(Linux环境下编写测试, 实现功能为对节点的基础操作:增删改查,显示):
/**********************
* @file: dlink.c
* @brief: 双向单链循环链表(增删改查和显示)
* @auther: Xinshu Wang
* @version:1.0
* @date: 2022-8-23
***********************/
#include<stdio.h>
#include<stdlib.h>
struct stu //链表节点(学生信息结构体)定义
{
int id;
char name[32];
struct stu *pri, *next;
};
/********* add_node **************
* @brief: 增加链表节点函数,通过scanf函数来获取节点数据
* @param: 参数为链表的表头
* @note:
* @usage: 返回值为增加节点后的新链表的表头
********************************/
struct stu *add_node(struct stu *head)
{
struct stu *pn;
pn=malloc(sizeof(struct stu));
printf("Please input the id and name of stu:\n");
scanf("%d %s",&(pn->id),pn->name);
// printf("LINE:%d\n",__LINE__);
getchar();
pn->next=head;
if(head==NULL) //头节点为空时
pn->pri=pn;
else if(head!=NULL) //头节点不为空时
{
pn->pri=head->pri;
head->pri=pn;
}
head=pn;
return head;
}
/********* show_node *************
* @brief: 正向和反向输出(显示)链表节点信息
* @param: 参数为链表的表头
* @note:
* @usage: 返回值为空
********************************/
void show_node(struct stu *head)
{
struct stu *p;
if(head==NULL) //链表为空
{
printf("The link list is empty!\n");
}
else if(head!=NULL)
{
for(p=head;p!=NULL;p=p->next) //由头节点到尾节点输出
{
printf("id:%d\tname:%s\n",p->id,p->name);
}
printf("\n##################\n\n");
for(p=head->pri;; p=p->pri) //由尾节点到头节点输出
{
printf("id:%d\tname:%s\n",p->id,p->name);
if(p->pri->next==NULL) //尾节点(即头节点的前驱节点)的下一个节点为空
break;
}
printf("\n");
}
}
/********* delate_node *************
* @brief: 通过id来对指定节点进行删除
* @param: 参数为链表的表头
* @note:
* @usage: 返回值为删除节点后新的链表的表头
***********************************/
struct stu *delate_node(struct stu *head)
{
if(head==NULL)
{
printf("\nThe link list is empty!\n\n");
}
else if(head!=NULL)
{
int delate_id,flag=0;
struct stu *p;
printf("Please input the id to delate:\n");
scanf("%d",&delate_id);
getchar();
for(p=head; p!=NULL; p=p->next)
{
if(p->id==delate_id) //查找到节点id与搜索id相同
{
flag=1;
if(p->pri==p&&p->next==NULL) //只有一个节点时
{
head=NULL;
}
else
{
if(p->pri->next==NULL) //删除节点为头节点时
{
head=p->next;
p->next->pri=p->pri;
}
else if(p->next==NULL) //删除节点为尾节点时
{
head->pri=p->pri;
p->pri->next=NULL;
}
else //删除节点为中间节点时
{
p->pri->next=p->next;
p->next->pri=p->pri;
}
}
free(p);
}
}
if(flag==0)
{
printf("No information find!\n");
}
}
return head;
}
/********* modify_node **************
* @brief: 修改节点信息,以name为例
* @param: 参数为链表的表头
* @note:
* @usage: 返回值为修改节点后的新链表的表头
***********************************/
struct stu *modify_node(struct stu *head)
{
if(head==NULL) //空表判断
{
printf("The link list is empty!\n");
}
else if(head!=NULL)
{
struct stu *p;
int modify_id,flag=0;
printf("Please input the id to modify:\n");
scanf("%d",&modify_id);
getchar();
for(p=head;p!=NULL;p=p->next) //遍历搜索
{
if(p->id==modify_id)
{
flag=1;
printf("Please input the modified name:\n");
scanf("%s",p->name);
getchar();
}
}
if(flag==0)
{
printf("No information find!\n");
}
}
return head;
}
/********* find_node ***************
* @brief: 查找节点,以id为搜索信息
* @param: 参数为链表的表头
* @note:
* @usage: 返回值为修改节点后的新链表的表头
***********************************/
void find_node(struct stu *head)
{
if(head==NULL) //空表判断
{
printf("The link list is empty!\n");
}
else if(head!=NULL)
{
struct stu *p;
int find_id,flag=0;
printf("Please input the id to find!\n");
scanf("%d",&find_id);
getchar();
for(p=head;p!=NULL;p=p->next) //遍历搜索
{
if(find_id==p->id)
{
flag=1;
printf("Find information id:%d\tname:%s\n",p->id,p->name);
}
}
if(flag==0)
{
printf("No information find!\n");
}
}
}
int main()
{
struct stu *head;
head = NULL;
while(1)
{
printf("Please input the sel:\n");
printf("1.Add.\n");
printf("2.Modify.\n");
printf("3.Delate.\n");
printf("4.show.\n");
printf("5.find.\n");
printf("6.exit.\n");
char sel;
int exit=0;
scanf("%c",&sel);
while(getchar()!='\n');
switch(sel)
{
case '1':
{
printf("\x1b[H\x1b[2J"); //本行与下行实现清除屏幕功能
printf("\033c");
head=add_node(head);
break;
}
case '2':
{
printf("\x1b[H\x1b[2J");
printf("\033c");
head=modify_node(head);
break;
}
case '3':
{
printf("\x1b[H\x1b[2J");
printf("\033c");
head=delate_node(head);
break;
}
case '4':
{
printf("\x1b[H\x1b[2J");
printf("\033c");
show_node(head);
break;
}
case '5':
{
printf("\x1b[H\x1b[2J");
printf("\033c");
find_node(head);
break;
}
case '6':
{
printf("\x1b[H\x1b[2J");
printf("\033c");
exit=1;
break;
}
default:
{
printf("\x1b[H\x1b[2J");
printf("\033c");
break;
}
}
if(exit==1)
{
break;
}
}
}
总结
以上代码是本人在linux下学习测试编写,供学习交流使用,水平有限,错误不当之处,望指正。