【数据结构】双向单链循环链表


前言

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列节点组成,节点可以动态增加或者删除,节点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址(双向链表还存放上一个节点地址)的指针域。单向链表操作时只能从头节点操作,删除节点时获取前驱节点麻烦,难以取到尾节点,而双向单链循环链表弥补了以上不足。


一、结构简介

双向单链循环链表在单向链表的基础上,在指针域中增加了前驱(上一个节点)的节点地址,而头节点的前驱指针指向尾节点,如下图。

二、具体代码

代码如下(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下学习测试编写,供学习交流使用,水平有限,错误不当之处,望指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值