/*
* @Description:
* @Author: lsc
* @Date: 2022-02-24 21:29:05
* @LastEditTime: 2022-02-24 21:49:45
* @FilePath: \share\13.数据结构\4.练习数据结构\2.带头结点的单链表.c
*/
#include <stdio.h>
#include <stdlib.h>
typedef int Elemtype ;
//链表中的节点的类型
typedef struct node
{
Elemtype data ;//数据域
struct node * next ; //指针域 保存了逻辑关系下一个节点的地址
}NODE;
//头结点的类型
typedef struct list
{
int n; //链表的节点数量
NODE * first ; //指向链表的第一个节点
NODE * last ; //指向链表的最后一个节点
//按需增加
}LIST;
/*
新建一个头结点 并初始化
*/
LIST * create_list()
{
//为新建的头结点申请空间 并赋值初始化
LIST * l = (LIST*)malloc(sizeof(LIST));
l->n = 0;
l->first = l->last = NULL;
return l;
}
/*
往头结点管理的链表中加入数据域为x的链表节点
*/
void insert_node(LIST * l , Elemtype x)
{
//第一步 为新节点分配空间 并赋值初始化
NODE * p = (NODE*)malloc(sizeof(NODE));
p->data = x;
p->next = NULL;
//第二步 把新节点加入到带头结点的链表中去
//分情况
if(l->n == 0)//如果是第一个链表的节点 (链表原先为空)
{
l->first = p;
l->last = p;
}
else //如果不是第一个链表的节点
{
#if 1
//尾插
l->last->next = p ;
l->last = p;
#else
//头插
p->next = l->first;
l->first = p;
#endif
}
l->n ++ ;
}
//打印整个链表的节点的数据域
void printf_list(LIST * l)
{
NODE * first = l->first;
while(first != NULL)
{
printf("%d ",first->data);
first = first->next;
}
printf("\n");
//还可以用l->n 这个条件
}
//清空整个链表 把所有的链表节点释放 但是保留头结点
void clear_list(LIST * l)
{
NODE * p = l->first;
//记得先保存要删除节点的下一个节点
NODE * q = NULL;
//释放链表
while(p != NULL)
{
//先保存要删除节点的下一个
q = p->next;
//释放掉p
p->data = 0;
p->next = NULL;
free(p);
//再让p指向下一个要删除的节点
p = q ;
}
//更新头结点的信息
l->n = 0;
l->first = l->last = NULL;
}
//销毁整个链表 包括头结点全部释放掉
void destroy_list(LIST * l)
{
//先清空链表
clear_list(l);
//销毁头结点
free(l);
}
//查找数据域为x的链表节点是否存在 找到返回1 没找到返回0
void find_x(LIST * l , int x)
{
NODE * first = l->first;
while(first != NULL)
{
if(first->data == x)
{
printf("找到了\n");
return ;
}
first = first->next;
}
printf("没找到\n");
//也可以用l->n这个条件
}
/*删除一个链表中数据域为x的节点
如果多个 删除第一个
如果没有 不操作
*/
void delete_x(LIST *l , int x )
{
NODE *p = l->first; //p用来遍历链表 查找要删除的节点
NODE *r = NULL ; // r 用来保存要删除节点的上一个节点
//查找要删除的元素并保存他的前一个节点(如果是删除第一个节点除外)
while(p != NULL) // <==> while(p)
{
if(p->data == x)
{
break;
}
r = p;
p=p->next;
}
//上述while循环结束有两种情况
//第一种通过break跳出 表示找到了要删除的节点 此时p一定不等于NULL
//第二种通过while的条件(p!=NULL)不满足跳出 此时p一定等于NULL 表示没有找到要删除的节点
if(p != NULL) // 表示找到了要删除的节点
{
//分情况删除
if(p == l->first) //要删除的节点是第一个节点
{
//先让头结点的first指针指向要删除节点的下一个节点
l->first = l->first->next ;
//free掉p
p->data =0;
p->next =NULL;
free(p);
}
else if(p->next == NULL) //要删除的节点是最后一个节点
{
r->next = NULL ; //r即将作为最后一个节点 将他的指针域置NULL
//让头结点的last指针指向倒数第二个节点 也就是r
l->last = r ;
//free掉p
p->data =0;
p->next =NULL;
free(p);
}
else //要删除的节点是中间节点
{
r->next = p->next;
p->data =0;
p->next =NULL;
free(p);
}
//更新头结点的信息
l->n-- ;
}
}
int main()
{
LIST * p = create_list();
int i;
for(i = 0 ; i < 5; i++)
{
insert_node(p,i);//
}
printf_list(p);//打印链表 0 1 2 3 4
find_x(p,1);//
find_x(p,5);//
delete_x(p,0);
printf_list(p);// 1234
// destroy_list(p);
clear_list(p);
printf_list(p);
}
带头结点的单链表 增删改查 C语言
于 2022-02-24 21:51:34 首次发布