/*
* @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);
}
}
不带头节点的单链表操作 增删改查
于 2022-02-23 20:34:00 首次发布