严蔚敏数据结构-单链表的增删改查即整表删除(综合程序(理解为主))——中职
作者:互联网
严蔚敏数据结构-单链表的增删改查即整表删除
(基于个人思想上的理解敲出的)
综合程序(理解为主)
/*
严蔚敏数据结构-单链表的增删改查即整表删除
(基于个人思想上的理解敲出的)
综合程序(理解为主)
*/
//头文件
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//结构
typedef struct List //该链表结构
{
int data; //数据域
struct List *NEXT; //指针域
}Sqlist, *PList;
//函数声明
PList List_initialize(void); //初始化链表,并返回带头结点的指针
void List_Custom_assignment(PList); //用户自定义开辟结点数和各个结点的赋值
void List_printf(PList); //输出链表
void List_input(PList); //链表的插入
void List_Drop(PList); //链表的删除
void List_alter(PList); //链表的更改
void List_find(PList); //链表的查找
void List_The_whole_table_delete(PList); //链表的整表删除,保留头结点
//函数区
PList List_initialize(void) //初始化链表,并返回带头结点的指针
{
PList PHead = NULL; //将头指针挂起
PHead = (PList)malloc(sizeof(Sqlist)); //开辟头结点
if (NULL == PHead) //判断是否开辟成功
{
printf("初始化失败,检查程序!\n"); //提醒用户出错位置
exit(1); //非正常退出程序
}
PHead->NEXT = NULL; //头结点的指针域挂起
return PHead; //返回带头结点的头指针
}
void List_Custom_assignment(PList PHead) //用户自定义开辟结点数和各个结点的赋值
{
PList PTail = NULL; //建立临时操作指针
PList PNEW = NULL; //建立临时操作指针
int i, val, len;
printf("输入开辟的结点个数:"); //提醒用户
scanf_s("%d", &len); //输入值给len
PTail = PHead; //将头指针的权限该给PTail
for (i = 0;i < len;i++) //建立链表
{
printf("输入第%d个结点的值:", i + 1); //提醒用户
scanf_s("%d", &val); //val存放用户输入的值
PNEW = (PList)malloc(sizeof(Sqlist)); //开辟新结点
if (NULL == PNEW)
{
printf("建立链表失败,开辟新结点失效,检查程序!\n");//提醒用户错误位置
exit(1); //非正常退出程序
}
PNEW->data = val; //数据发生给新结点的数据域
PNEW->NEXT = NULL; //将新结点的指针域挂起
PTail->NEXT = PNEW; //将新结点挂在前一个结点上
PTail = PNEW; //将PTail指向新结点
}
}
void List_printf(PList PHead) //输出链表
{
PList PTail = NULL; //挂起移动操作的指针
PTail = PHead->NEXT; //将PTail指向第一个结点
printf("\n该链表的值为:"); //提示用户
while (PTail) //只要当前结点有数据
{
printf("%d ", PTail->data); //输出该结点的数据域
PTail = PTail->NEXT; //将PTail指向下一个结点
}
printf("\n");
}
void List_input(PList PHead) //链表的插入
{
PList s = NULL; //s是新结点的指针
PList p = NULL; //临时操作的指针
int val;
int i; //严书中是主函数发送了实参(插入的位置),这里使用i值存储需要插入的位置
int j = 0;
printf("输入插入的值:"); //提示用户
scanf_s("%d", &val); //严书中是主函数发送了实参(插入的位置),这里使用val值存储需要插入的位置
printf("输入插入的位置:"); //提示用户
scanf_s("%d", &i); //严书中是主函数发送了实参(插入的位置),这里使用i值存储需要插入的位置
p = PHead; //将头指针权限赋给p
while (p && j < i - 1) //因为需要循环到达需要插入位置的前一个结点,所以i - 1
{
p = p->NEXT; //p指向下一个结点
j++; //记录j值
}
if ( NULL == p || j > i || 0 >= i ) //严书中是if(!p || j > i),!p的意思就是p为NULL时,且少个约束(i <= 0)
{
printf("插入位置有误,重新输入"); //显示出错位置
exit(1); //非正常终止程序
}
s = (PList)malloc(sizeof(Sqlist)); //开辟的新结点
s->data = val; //用户输入的值发送给s的数据域
s->NEXT = p->NEXT; //严书是p->next,程序应有改动,意思差不多,将新结点指向插入位置的后一个结点
p->NEXT = s; //将新结点的前一个结点指向新结点
}
void List_Drop(PList L) //链表的删除
{
PList P = NULL; //建立移动的指针
PList Q = NULL; //建立移动的指针
int j = 0, i;
printf("你要删除第几个结点:"); //显示提醒用户
scanf_s("%d", &i); //删除的值是i
P = L; //将头指针的权限给PTail
while (P->NEXT && j < i - 1) //确保当前结点不为尾结点,且未到指定的位置
{
P = P->NEXT; //指向下一个结点
j++; //记录
}
if (NULL == P->NEXT || j > i || i <= 0) //判断输入的值是否合法
{
printf("你删除的位置有误,重新删除!\n"); //提醒用户
exit(1); //非正常退出程序
}
Q = P->NEXT; //因为当前指向的是需要删除结点的前一个,所以将Q指向需要删除的结点
P->NEXT = Q->NEXT; //将需要被删除的结点的上一个结点指向需要被删除的结点的下一个结点
free(Q); //释放被删除的结点,完成删除
}
void List_alter(PList PHead) //链表的更改
{
PList PTail = NULL; //建立移动的指针
int k, i, j;
printf("输入你要更改值的位置:");
scanf_s("%d", &i);
printf("输入你要更改的新值:");
scanf_s("%d", &j);
PTail = PHead; //赋予头指针的权限
for (k = 1;k <= i;k++) //找到需要删除的位置
{
PTail = PTail->NEXT; //指向下一个结点
}
if (i <= 0 || NULL == PTail) //判断更改的值是否合法
{
printf("你更改的位置有误,重新删除!\n"); //提醒用户
exit(1); //非正常退出程序
}
PTail->data = j; //更改数据域
}
void List_find(PList L) //链表的查找
{
PList P = NULL; //建立移动的指针
int i, j = 1;
printf("输入要查找的值的位置:");
scanf_s("%d", &i);
P = L->NEXT; //是P指向第一个结点
while (P && j < i) //未到更改位置
{
P = P->NEXT; //指向下一个结点
j++; //记录
}
if (P == NULL || j > i || i <= 0) //判断查找值是否合法
{
printf("你查找的位置有误,重新查找!\n"); //提醒用户
exit(1); //非正常退出程序
}
printf("第%d个结点上的值为:%d\n", i, P->data);
}
void List_The_whole_table_delete(PList PHead) //链表的整表删除,保留头结点
{
PList PTail = NULL; //建立移动的指针
PList PQ = NULL; //建立移动的指针
PTail = PHead->NEXT; //PTail指向第一个结点
while (PTail)
{
PQ = PTail->NEXT; //PQ指向下一个结点
free(PTail); //释放老结点
PTail = PQ; //都指向PQ所指的结点
}
PHead->NEXT = NULL; //整表删除完毕,挂起头结点的指针域
}
//主函数
int main(void)
{
PList PHead = NULL; //头指针
char val, j;
PHead = List_initialize(); //初始化链表,并返回带头结点的指针,用头指针指向
List_Custom_assignment(PHead); //用户自定义开辟结点数和各个结点的赋值
List_printf(PHead); //输出链表
/*链表的增删改查即整表删除功能演示开始*/
List_input(PHead); //链表的插入
List_printf(PHead); //输出插入值后的链表
List_Drop(PHead); //链表的删除
List_printf(PHead); //输出删除值后的链表
List_alter(PHead); //链表的更改
List_printf(PHead); //输出更改值后的链表
List_find(PHead); //链表的查找
List_printf(PHead); //输出更改值后的链表
List_The_whole_table_delete(PHead); //链表的整表删除,保留头结点
List_printf(PHead); //输出整表删除后的链表值
return 0;
}
总结:对于循环的问题有待提高,循环时指针指向的结点很多情况下都不是我需要的指向,小细节需要注意,且对于越界的问题在编译时多次出现,需要加强对于循环流程控制的理解和对越界、指针指向等问题加重注意和加深理解。
通过本次程序的敲打,发现了很多细节的问题,需要大致整体回顾下链表的章节,在进行下一阶段的静态链表、循环链表等。然后再整体抱着理解性目的去回顾线性表的整章以及算法~
感谢观看
再次感谢~
标签:PHead,结点,PTail,中职,改查,链表,严蔚敏,List,PList 来源: https://blog.csdn.net/qq_51212951/article/details/113094495