不带头节点的单链表操作 增删改查

/*
 * @Description: 
 * @Author: lsc
 * @Date: 2022-02-23 17:00:22
 * @LastEditTime: 2022-02-23 20:17:23
 * @FilePath: \share\13.数据结构\4.练习数据结构\1.不带头结点的单链表.c
 */

#include <stdio.h>
#include <stdlib.h>
/*
   对用户的输入的任意个整数(输入0就结束)建立一个链表  
               例: 输入: 1 2 3 4 5 0  
                    链表: 1->2->3->4->5
*/
typedef int Elemtype; //定义链表中的节点的类型 为int型

typedef struct node
{
    Elemtype data;// 数据域
    struct node * next;// 指针域 保存了逻辑关系下一个节点的地址
}NODE;
// NODE 等价于 struct node

NODE * creat_list()// 创建链表
{
    int x; //x用来保存从键盘输入的数据
    NODE * p = NULL; //p 指向新申请的节点空间
    NODE * first = NULL; // first 指向链表的第一个节点
    NODE * last = NULL; //last 指向链表的最后一个节点
    while (1)
    {
        scanf("%d", &x);
        if (x == 0)
        {
            break;
        }
        NODE* p = (NODE*)malloc(sizeof(NODE));//为新的节点分配空间
        p->data = x;//并赋值初始化
        p->next = NULL;
        //将新申请的节点加入到链表中
       //分情况讨论  
       
        if (first == NULL)//新加入的节点是第一个节点
        {
            first = p;
            last = p;
        }
        else //新加入的节点不是第一个节点
        {   //尾插
            last->next = p;
            last = p;
            //头插
            //p->next = first;
            //first = p;
        }
    }
    return first;
    
}

void printf_list(NODE * first) // 打印链表
{
   while(first != NULL)
   {
       printf("%d ",first->data);
       first = first->next;    
   }
   printf("\n");
   
}

NODE* free_list(NODE * first) //释放链表
{
   NODE * p = NULL; // 保存要被释放的节点的下一个节点
   while(first != NULL)
   {
       p = first->next;  //先保存要删除节点的下一个
       
       //释放掉first指向的节点
       first->data = 0;
       first->next = NULL;
       free(first);
       
       //让first继续指向下一个要释放的节点
       first = p;
       
   }    
   
}

/*
   查找一个链表中数据域为x的节点
   如果找到返回1
   如果没找到返回0
*/
int find_x(NODE * first)
{
    int x;
    printf("请输入你要查询的数字: \n");
    scanf("%d", &x);
   while(first != NULL)
   {
       if(first->data == x)
       {
           return 1;
       }
       else
       {
           first = first->next;
       }
   }
   return 0;   
}
void flag_list(int flag)
{
    if (flag)
    printf("链表中存在这个数\n");
    else
    printf("链表中不存在这个数\n");
}

/*
   删除一个链表中数据域为x的节点
   多个就删除第一个
   没有就不操作
*/

NODE * delete_x(NODE * first )
{
   int x;
   printf("请输入要删除的数字\n");
   scanf("%d", &x);
   NODE * p = first ; //p是用来遍历  
   NODE * r = NULL ; // r用来保存要删除的节点p的前驱节点
   //寻找要删除的节点 同时保存了要删除节点的前驱节点 (第一个节点的情况例外)
   while(p != NULL)
   {
       if(p->data == x) //找出要删除的那个节点
       {
           break;
       }
       else
       {
           r = p ;
           p = p->next;
       }
   }
   //分情况讨论
   //上述循环结束原因有两种
   //第一种就是通过break跳出  此时表示找到了要删除的节点 此时p一定不等于NULL
   //第二种就是通过while语句的循环条件(p != NULL)不成立跳出 此时p一定等于NULL
   if(p != NULL)    //找到了要删除的节点   接下来继续分情况删除
   {
       //要删除的节点是第一个节点
       if(p == first)
       {
           first = p->next ; //把first为p的下一个节点
           //free掉p
           p->data = 0;
           p->next = NULL;
           free(p);
           
           
       }
       else if(p->next == NULL)//要删除的节点是最后一个节点
       {
           r->next = NULL; //把倒数第二个节点的指针域清NULL  因为最后一个节点将要被删除
           
           //free掉最后一个节点p  
           p->data = 0;
           p->next = NULL;
           free(p);         
       }
       else //要删除的节点是中间节点
       {
           r->next = p->next; // p的前驱节点的指针域 保存 p的下一个节点的地址  
           
           //free掉p  
           p->data = 0;
           p->next = NULL;
           free(p);
       }
       return first;       
   }  
}
/*
   函数返回一个链表的节点个数
*/
int list_num(NODE *first)
{
   int num = 0;
   while(first != NULL)
   {
       num++;
       first = first->next;
   }
   return num;    
}
int main()
{
    NODE* p = creat_list();
    printf_list(p);
    printf("链表的节点个数为 %d\n", list_num(p));
    int flag = find_x(p);
    flag_list(flag);
//    p = free_list(p);
//    if (p == NULL)
//    {
//        printf("链表已为空\n");
//    }
    while (p != NULL)
    {
        p = delete_x(p);
        printf_list(p);
    }
    
    
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值