C语言实战5:使用双向循环链表完成个人信息的增删改查

一、新建链表

二、链表的插入

链表插入前

链表插入第一步                                                        链表插入第二步

三 、链表的删除

链表删除第一步                                           链表删除第二步

四、使用双向循环链表完成个人信息的增删改查

/***************************************************************

作用:使用链表完成个人信息的增删改查

作者:殷启翔

版本号:0.1.64

修改时间:2024.7.22

可优化方向: 1.增加查询方式,这里只有通过姓名查询,后续可以添加新的查询项

​                        2.对节点排序

​			3.修改节点数据时,不用修改整个节点,而修改节点内的某一个项

​			4.查询方式可以新增用双向链表查寻,正遍历与反遍历,循环查询的遍历结束条件容易出错

***************************************************************/

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//使用typedef命令 将 struct geren_xinxi  这个整体重新命名为 geren
//循环链表 中结构体的构成
typedef struct geren_xinxi  
{
  struct geren_xinxi * before ;  //指向上一个结构体
  char name[20];
  int age;
  char sex[10] ;
  char where[30] ;
  char  phone[11] ;
  char shijian[20] ;
  struct geren_xinxi * next ; //指向下一个结构体
}geren;
```

```c
//申请新的链表节点
geren * jiedian_xin()//返回值为新建的节点的地址
{
  geren * p ;
  p = (geren *) malloc (sizeof (geren) ) ;
  p->before = p ;
  p->next = p->before ;
  p -> before = p->next ;
  return p ;
  //新建的节点参考下图 
};
```

![新建链表结构](.\新建链表结构.png)

```c
//节点插入
//p_qian 是你想插入那个节点的前一个节点的地址  p_cha 你想插入的节点的首地址
void jiedian_zeng(geren * p_qian , geren * p_cha ) 
{
  	p_cha -> next = p_qian -> next ;
  	p_cha ->before = p_qian ;
 	p_qian ->next = p_cha ;
 	p_cha -> next -> before = p_cha ;
    //实现的操作请看下图
};
```

![链表插入前](.\链表插入前.png)

![链表插入第一步](.\链表插入第一步.png)

![链表插入第二步](.\链表插入第二步.png)

```c
//节点查
//只能查姓名存不存在 返回值为所搜索到的节点的地址 若没有这个节点返回null
geren * jiedian_cha( geren * start , char search[20] )
{
  geren * p = start ;
  do
  {
    //strcmp函数存于<string.h>内,作用比较两个字符串内容是否相等,按位比较,
    //前者大于后者返回1,前者小于后者返回-1,相同返回0 ,若其中里面不一样则直接返回,或检测到‘\0’停止
  	if (strcmp( search , p -> name) == 0 )
	{
       return p ;
    }
    p = p ->next ;
  }
  while( p != start);
  printf ("您所寻找的用户不存在\n");
  return NULL ;
};
```

![链表组成的理解图](.\链表组成的理解图.png)

```c
//节点改
//输入想修改的节点地址 在函数内部重新赋值输入
//这个结构就是很简单
//利用指针锁定储存内容的结构体,并通过“->”取里面的每一个元素的值
void jiedian_gai( geren * p )
{  
  printf("请输入姓名\n");
  scanf("%s",p -> name);
  
  printf("请输入年龄\n");
  scanf("%d", &p -> age);
  
  printf("请输入性别\n");
  scanf("%s",p -> sex);

  printf("请输入祖籍\n");
  scanf("%s",p -> where);

  printf("请输入手机号\n");
  scanf("%s",p -> phone);

  printf("请输入学时间\n");
  scanf("%s",p -> shijian);
};
```

```c
//节点删除
void jiedian_shan(geren * p )
{
  if (p -> next != p )//这里有一种特殊情况,那就是这个链表中只有它自己一个节点,若如此就是让这个链表全部删除
  {
      p -> before -> next = p -> next ;
      p -> next -> before = p -> before ;
  }
   free ( p ) ; 
   //这里比较好的点是p在这个子函数中作为一个形参
    //所以p也没有必要让它指向新的节点以保留节点首地址信息
};
```

![链表删除第一步](.\链表删除第一步.png)

![链表删除第二步](.\链表删除第二步.png)

```c
//主函数
int main ()
{
  geren * p_last ; //  指向上一层
  geren * start ;  //  链表起始地址
  geren * p_next ; //  指向下一层
  geren * p1 ;    //  临时用的节点
  geren * p2 ;    //  临时用的节点
  int choice ;
  char mingzi[20] ;
    
  market :  //后续代码的标志位
    printf("请输入您想进行的操作\n");  
    printf("第一次进入请输入1\n");
    printf("添加学生请输入2\n");
    printf("删除学生请输入3\n");
    printf("查询学生请输入4\n");
    printf("修改某名学生的信息请输入5\n");
    printf("退出系统请输入0\n");
    scanf("%d",&choice);
    switch (choice)
    {
      case 1: //第一次进入
      {
        //确认首节点,并用start储存这个节点的位置,也是建立链表的第一步
        start = jiedian_xin() ;
        jiedian_gai( start ) ;
      }
      goto market;
            
      case 2: //添加学生
      //添加学生包括了,新建节点,给节点写入数据,将新建的节点插入链表
      //这里为了方便将插入多加了一个查询后加入的功能
      {
        p1 = jiedian_xin() ;
        jiedian_gai( p1 ) ;
        printf("您想将这名同学排在哪一名同学后面?\n");
        printf("请输入那一名学生的名字\n");
        scanf("%s",mingzi);
        p2 = (geren*) jiedian_cha( start , mingzi );
        jiedian_zeng( p2 , p1 );
      }
      goto market;  

      case  3: //删除学生
      //删除指定学生,主要还是先查询到那名学生所在的节点,才能删除
      {
        printf("请输入您想删除那一名学生的名字\n");
        scanf("%s",mingzi);
        p2 = (geren*)jiedian_cha( start , mingzi );
        if (p2 != NULL)
        {
          jiedian_shan( p2 ) ;
        }
      }
      goto market;

      case 4://查询学生
      //这里只是查到节点并把那个节点的信息打印出来
      {
        printf("请输入您想查的那一名学生的名字\n");
        scanf("%s",mingzi);
        p2 = (geren*)jiedian_cha( start , mingzi );
        if (p2 != NULL)
        {
          printf("姓名:%s\n", p2 -> name);
          printf("年龄:%d\n", p2 -> age);
          printf("性别:%s\n", p2 -> sex);
          printf("祖籍:%s\n", p2 -> where);
          printf("手机号:%s\n", p2 -> phone);
          printf("入学时间:%s\n", p2 -> shijian);
        }
      }
      goto market;
      
     case 5: //修改某名学生的信息
     //先查到学生所在的节点,然后重新给他输入内容即可
      {
        printf("请输入您想信息的那一名学生的名字\n");
        scanf("%s",mingzi);
        p2 = (geren*)jiedian_cha( start , mingzi );
        if (p2 != NULL)
        {
          jiedian_gai( p2 );
        }
      }
      goto market;
      case 0: //退出系统
      {
        break ;
      }
      default:
      {
        printf("输入错误\n");
        goto market ;
      }
    }      
    return 0 ;
}
```



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

x陌北x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值