1> 将链表的相关操作自己手动完成一下
链表的排序
链表的反转(递归实现)
链表去重
代码:
linklist.h:
#ifndef LINKLIST
#define LINKLIST
#include<myhead.h>
#define MAX 100
//定义数据类型
typedef int datatype;
//定义结点类型
typedef struct Node
{
union
{
int len; //头结点数据域
datatype data; //普通结点数据域
};
struct Node *next; //指针域
}Node,*NodePtr;
//创建链表
NodePtr list_create();
//申请结点封装数据函数
NodePtr apply_node(datatype e);
//判空
int list_empty(NodePtr L);
//头插
int list_insert_head(NodePtr L,datatype e);
//链表遍历函数
int list_show(NodePtr L);
//通过位置查找结点
NodePtr list_search_pos(NodePtr L,int pos);
//任意位置插入
int list_insert_pos(NodePtr L,int pos, datatype e);
//链表头删
int list_delete_head(NodePtr L);
//链表任意位置删除
int list_delete_pos(NodePtr L, int pos);
//链表按值查找返回位置
int list_search_value(NodePtr L,datatype e);
//链表按位置进行修改
int list_update_pos(NodePtr L,int pos, datatype e);
//按值修改
int list_update_value(NodePtr L, datatype old_e, datatype new_e);
//将链表进行翻转
void list_reverse(NodePtr L);
//释放链表
void list_destroy(NodePtr L);
//递归反转函数
NodePtr list_reverse_dg(NodePtr L);
//递归反转子函数
NodePtr reverse_dg(NodePtr Pre,NodePtr Cur);
//排序
void list_sort(NodePtr L);
//去重
void list_distinct(NodePtr *L);
#endif
linklist.c:
#include "linklist.h"
//创建链表
NodePtr list_create()
{
//只需要在堆区申请一个头结点
NodePtr L = (NodePtr)malloc(sizeof(Node));
if(NULL == L)
{
printf("创建失败!\n");
return NULL;
}
//程序执行至此,说明头结点创建结束
L->len = 0; //链表长度为0
L->next = NULL; //防止野指针
printf("创建成功!\n");
return L;
}
//申请结点封装数据函数
NodePtr apply_node(datatype e)
{
//在堆区申请一个结点的大小
NodePtr p = (NodePtr)malloc(sizeof(Node));
if(NULL == p)
{
printf("结点申请失败!\n");
return NULL;
}
//给结点内容赋值
p->data = e; //数据域赋值
p->next = NULL; //指针域
return p;
}
//链表判空
int list_empty(NodePtr L)
{
return L->next == NULL;
}
//头插
int list_insert_head(NodePtr L, datatype e)
{
//判断逻辑
if(NULL==L)
{
printf("链表不合法!\n");
return -1;
}
//申请结点封装数据
NodePtr p = apply_node(e);
if(NULL==p)
{
return -1;
}
//头插逻辑
p->next = L->next;
L->next = p;
//表的变化
L->len ++;
printf("头插成功!\n");
return 0;
}
//链表遍历函数
int list_show(NodePtr L)
{
//判断逻辑
if(NULL==L || list_empty(L))
{
printf("遍历失败!\n");
return -1;
}
printf("链表中的元素分别是:");
//遍历逻辑
NodePtr q = L->next; //定义遍历指针从第一个结点出发
while(q != NULL)
{
//输出数据域
printf("%d\t", q->data);
q = q->next; //指针向后偏移一个
}
putchar(10);
}
//通过位置查找结点
NodePtr list_search_pos(NodePtr L, int pos)
{
//判断逻辑
if(NULL==L || list_empty(L) || pos<0 || pos>L->len)
{
printf("查找失败!\n");
return NULL;
}
//查找逻辑
//定义遍历指针从头结点出发
NodePtr q = L;
for(int i=0; i<pos; i++)
{
q = q->next;
}
return q; //将找到的结点地址返回
}
//任意位置插入
int list_insert_pos(NodePtr L, int pos, datatype e)
{
//判断逻辑
if(NULL==L || pos<1 || pos>L->len+1)
{
printf("插入失败!\n");
return -1;
}
//申请结点封装数据
NodePtr p = apply_node(e);
if(NULL==p)
{
return -1;
}
//调用函数查找前驱结点
NodePtr q = list_search_pos(L, pos-1);
//插入逻辑
p->next = q->next;
q->next = p;
//表的变化
L->len++;
printf("插入成功!\n");
return 0;
}
//链表头删
int list_delete_head(NodePtr L)
{
//判断逻辑
if(NULL==L || list_empty(L))
{
printf("删除失败!\n");
return -1;
}
//删除三部曲
NodePtr p = L->next; //标记
L->next = p->next; //L->next->next 孤立
free(p); //释放
p = NULL;
//表长变化
L->len--;
printf("头删成功!\n");
return 0;
}
//链表任意位置删除
int list_delete_pos(NodePtr L, int pos)
{
//判断逻辑
if(NULL==L || list_empty(L) || pos<1 || pos>L->len)
{
printf("删除失败!\n");
return -1;
}
//找到前驱结点
NodePtr q = list_search_pos(L, pos-1);
//删除逻辑
NodePtr p = q->next; //标记
q->next = q->next->next; //p->next 孤立
free(p); //释放
p = NULL;
//表的变化
L->len--;
printf("删除成功!\n");
return 0;
}
//链表按值查找返回位置
int list_search_value(NodePtr L, datatype e)
{
//判断逻辑
if(NULL==L || list_empty(L))
{
printf("查找失败!\n");
return -1;
}
//查找逻辑
//定义遍历指针从第一个结点出发
NodePtr q = L->next;
for(int index=1; q->next!=NULL; index++)
{
//判断当前结点的值是否为要找的数据
if(q->data == e)
{
return index;
}
q = q->next; //继续向后遍历
}
//程序执行至此,表示没找到
printf("没找到!\n");
return -1;
}
//链表按位置进行修改
int list_update_pos(NodePtr L, int pos, datatype e)
{
//判断逻辑
if(NULL==L || list_empty(L) || pos<1 || pos>L->len)
{
printf("修改失败!\n");
return -1;
}
//按位置查找逻辑
NodePtr p = list_search_pos(L, pos);
//修改逻辑
p->data = e;
printf("修改成功!\n");
return 0;
}
//按值进行修改
int list_update_value(NodePtr L, datatype old_e, datatype new_e)
{
//判断逻辑
if(NULL==L || list_empty(L))
{
printf("修改失败!\n");
return -1;
}
//按值查找位置
int res = list_search_value(L, old_e);
if(res == -1)
{
printf("没有要修改的值!\n");
return -1;
}
//按位置修改
list_update_pos(L, res, new_e);
printf("修改成功!\n");
return 0;
}
//将链表进行翻转
void list_reverse(NodePtr L)
{
//判断逻辑
if(NULL==L || L->len<=1)
{
printf("翻转失败!\n");
return ;
}
//翻转逻辑
NodePtr H = L->next; //将链表元素进行托付
L->next = NULL; //自己白手起家
NodePtr p = NULL; //结点的搬运工
while(H != NULL)
{
p = H; //搬运第一个结点
H = H->next; //头指针后移
//将p以头插的方式放入L中
p->next = L->next;
L->next = p;
}
printf("翻转成功!\n");
}
//释放链表
void list_destroy(NodePtr L)
{
//判断逻辑
if(NULL == L)
{
return;
}
//将所有结点进行释放
while(!list_empty(L))
{
//头删
list_delete_head(L);
}
//释放头结点
free(L);
L = NULL;
printf("释放成功!\n");
}
//递归反转子函数
NodePtr reverse_dg(NodePtr Pre,NodePtr Cur)
{
if(Cur == NULL)
{
return Pre;
}
NodePtr Next = Cur->next;
Cur->next = Pre;
return reverse_dg(Cur,Next);
}
//递归反转函数
NodePtr list_reverse_dg(NodePtr L)
{
//判断逻辑
if(L == NULL || L->next == NULL)
{
return L;
}
NodePtr First = L->next;
if(First == NULL)
{
return L;
}
NodePtr newL = reverse_dg(NULL, First);
L->next = newL;
printf("递归反转成功!\n");
return L;
}
//排序
void list_sort(NodePtr L)
{
if(L == NULL || L->next == NULL)
{
return ;
}
NodePtr Pre = NULL, Cur = NULL, Next = NULL, Sort = NULL;
int swap = 1;
//遍历
while(swap)
{
swap = 0;
Cur = L->next;
Pre = L;
while(Cur != Sort)
{
Next = Cur->next;
if(Next != NULL && Cur->data > Next->data)
{
//交换数据
datatype temp = Cur->data;
Cur->data = Next->data;
Next->data = temp;
swap = 1;
}
Pre = Cur;
Cur = Next;
}
Sort = Pre;
}
printf("排序成功!\n");
}
//去重
void list_distinct(NodePtr *L)
{
NodePtr Cur = *L;
NodePtr Pre = NULL;
//跳过头结点
if(Cur && Cur->next == NULL)
{
return ;
}
Cur = Cur->next;
while(Cur)
{
NodePtr Run = Cur;
while(Run->next)
{
//data相同就删除
if(Run->data == Run->next->data)
{
NodePtr temp = Run->next;
Run->next = temp->next;
free(temp);
}
else{
Run = Run->next;
}
}
Pre = Cur;
Cur = Cur->next; //Cur向后偏移一位
}
printf("去重成功!\n");
}
main.c:
#include "linklist.h"
int main(int argc, const char *argv[])
{
//调用函数创建一个链表
NodePtr L = list_create();
if(NULL == L)
{
return -1;
}
//调用头插函数
list_insert_head(L,520);
list_insert_head(L,1314);
list_insert_head(L,666);
list_insert_head(L,999);
//调用遍历函数
list_show(L);
//调用按值查找位置
int res = list_search_value(L, 666);
if(res != -1)
{
printf("您要找的数据在链表的第%d个位置\n", res);
}
//调用按位置进行修改函数
list_update_pos(L, 1, 12345);
list_show(L);
//调用按值修改函数
list_update_value(L, 12345, 6789);
list_show(L);
//调用翻转函数
list_reverse(L);
list_show(L);
//调用头删函数
list_delete_head(L);
list_show(L);
//调用任意位置删除函数
list_delete_pos(L,L->len);
list_show(L);
//调用任意位置插入函数
list_insert_pos(L,1,10);
list_insert_pos(L,3,10);
list_insert_pos(L,L->len+1,10);
list_show(L);
//调用递归反转函数
L = list_reverse_dg(L);
list_show(L);
//调用排序函数
list_sort(L);
list_show(L);
//调用去重函数
list_distinct(&L);
list_show(L);
//调用释放函数
list_destroy(L);
L = NULL;
return 0;
}
运行结果:
2> 使用链表完成班级管理系统(君子作业)
代码:
head.h:
#ifndef HEAD_H
#define HEAD_H
#include<myhead.h>
#define MAX 100
//定义学生类型
typedef struct Stu
{
//数据域
char name[20];
int age;
double score;
//指针域
struct Stu *next;
}Stu,* Stu_str;
//定义班级类型
typedef struct Class
{
Stu_str student; //存放学生头结点
int size; //实际人数
}Class,* Class_str;
//创建菜单
void create_menu();
//创建班级函数
Class_str class_create();
//链表判空
int empty(Class_str L);
//申请结点封装数据函数
Stu_str apply_node(char *Name, int Age, double Score);
//头插
int class_insert_head(Class_str L, char *Name, int Age, double Score);
//头删
int class_delete_head(Class_str L);
//录入学生信息
void input_student(Class_str L);
//展示学生信息
int class_show(Class_str L);
//按成绩把班级学生信息降序
void Class_sort(Class_str *L);
//展示成绩最高和最低学生的信息
void Class_maxmin(Class_str L);
//添加学生信息
int class_add(Class_str L);
//按姓名查找返回位置
int search_value(Class_str L, char *Name);
//通过位置查找结点
Stu_str search_pos(Class_str L, int pos);
//删除学生信息
int class_del(Class_str L);
//修改学生信息
int class_update(Class_str L);
//查询学生信息
int class_search(Class_str L);
//销毁班级
void destroy(Class_str L);
#endif
hs.c:
#include"head.h"
//定义创建菜单函数
void create_menu()
{
printf("\n\t\t======班级管理系统========\n");
printf("\t\t1、录入班级学生信息\n");
printf("\t\t2、展示班级学生信息\n");
printf("\t\t3、按成绩把班级学生信息降序\n");
printf("\t\t4、展示成绩最高和最低学生的信息\n");
printf("\t\t5、增加班级学生信息\n");
printf("\t\t6、删除班级学生信息\n");
printf("\t\t7、修改班级学生信息\n");
printf("\t\t8、查询班级学生信息\n");
printf("\t\t9、销毁班级\n");
printf("\t\t0、退出\n");
}
//创建班级函数
Class_str class_create()
{
//只需要在堆区申请一个结点
Class_str L = (Class_str)malloc(sizeof(Class));
if(NULL == L)
{
printf("创建班级失败!\n");
return NULL;
}
//程序执行至此,说明头结点创建结束
L->size = 0; //链表长度为0
L->student = NULL; //防止野指针
printf("班级创建成功!\n");
return L;
}
//链表判空
int empty(Class_str L)
{
return L->student == NULL;
}
//申请结点封装数据函数
Stu_str apply_node(char *Name, int Age, double Score)
{
//在堆区申请一个结点的大小
Stu_str p = (Stu_str)malloc(sizeof(Stu));
if(NULL == p)
{
printf("结点申请失败!\n");
return NULL;
}
//给结点内容赋值
strcpy(p->name,Name); //数据域赋值
p->age = Age;
p->score = Score;
p->next = NULL; //指针域
return p;
}
//头插
int class_insert_head(Class_str L, char *Name, int Age, double Score)
{
//判断逻辑
if(NULL==L)
{
printf("班级不存在!\n");
return -1;
}
//申请结点封装数据
Stu_str p = apply_node(Name, Age, Score);
if(NULL==p)
{
return -1;
}
//头插逻辑
p->next = L->student;
L->student = p;
//班级的变化
L->size ++;
return 0;
}
//头删
int class_delete_head(Class_str L)
{
//判断逻辑
if(NULL==L || empty(L))
{
printf("删除失败!\n");
return -1;
}
//删除三部曲
Stu_str p = L->student; //标记
L->student = p->next; //L->student->next 孤立
free(p); //释放
p = NULL;
//表长变化
L->size--;
return 0;
}
//录入学生信息
void input_student(Class_str L)
{
int len = 0;
printf("请输入学生人数:");
scanf("%d",&len);
getchar();
char Name[20] = {0};
int Age = 0;
double Score = 0;
for(int i=0;i<len;i++)
{
printf("请输入第%d个学生的姓名:",i+1);
scanf("%s",Name);
getchar();
printf("请输入第%d个学生的年龄:",i+1);
scanf("%d",&Age);
getchar();
printf("请输入第%d个学生的分数:",i+1);
scanf("%lf",&Score);
getchar();
class_insert_head(L,Name,Age,Score);
//班级的变化
L->size ++;
putchar(10);
}
printf("录入成功!\n");
}
//展示学生信息
int class_show(Class_str L)
{
//判断逻辑
if(NULL==L || empty(L))
{
printf("展示失败!\n");
return -1;
}
printf("班级中的学生分别是:\n");
//遍历逻辑
Stu_str q = L->student; //定义遍历指针从第一个结点出发
printf("\t姓名\t年龄\t分数\n");
while(q != NULL)
{
//输出数据域
printf("\t%s\t%d\t%lf\n",\
q->name, q->age, q->score);
q = q->next; //指针向后偏移一个
}
}
//按成绩把班级学生信息降序
void Class_sort(Class_str *L)
{
if(*L == NULL || (*L)->student == NULL)
{
return ;
}
Stu_str sorted = NULL;
Stu_str current = (*L)->student;
while (current != NULL)
{
Stu_str next = current->next;
Stu_str *pre = &sorted;
// 找到合适的插入位置
while (*pre != NULL && (*pre)->score > current->score)
{
pre = &(*pre)->next;
}
// 插入当前节点
current->next = *pre;
*pre = current;
current = next;
}
(*L)->student = sorted;
printf("排序成功!\n");
}
//展示成绩最高和最低学生的信息
void Class_maxmin(Class_str L)
{
if(L ==NULL || L->student == NULL)
{
return ;
}
Stu_str cur = L->student;
Stu_str max = L->student;
Stu_str min = L->student;
while(cur !=NULL)
{
if(cur->score > max->score)
{
max = cur;
}
if(cur->score < min->score)
{
min = cur;
}
cur = cur->next;
}
printf("成绩最好的学生信息如下\n");
printf("\t姓名\t年龄\t分数\n");
printf("\t%s\t%d\t%lf\n",\
max->name, max->age, max->score);
printf("成绩最差的学生信息如下\n");
printf("\t姓名\t年龄\t分数\n");
printf("\t%s\t%d\t%lf\n",\
min->name, min->age, min->score);
}
//添加学生信息
int class_add(Class_str L)
{
//判断逻辑
if(NULL==L )
{
printf("添加失败!\n");
return -1;
}
char Name[20] = {0};
int Age = 0;
double Score = 0;
printf("请输入添加的学生姓名:");
scanf("%s",Name);
printf("请输入添加的学生年龄:");
scanf("%d",&Age);
printf("请输入添加的学生分数:");
scanf("%lf",&Score);
class_insert_head(L, Name, Age, Score);
printf("添加成功!\n");
return 0;
}
//按姓名查找返回位置
int search_value(Class_str L, char *Name)
{
//判断逻辑
if(NULL==L || empty(L))
{
printf("查找失败!\n");
return -1;
}
//查找逻辑
//定义遍历指针从第一个结点出发
Stu_str q = L->student;
for(int index=0; index<L->size; index++)
{
//判断当前结点的值是否为要找的数据
if(strcmp(q->name,Name)==0)
{
return index;
}
q = q->next; //继续向后遍历
}
//程序执行至此,表示没找到
printf("没找到该学生!\n");
return -1;
}
//通过位置查找结点
Stu_str search_pos(Class_str L, int pos)
{
//判断逻辑
if(NULL==L || empty(L) || pos<0 || pos>L->size)
{
printf("查找失败!\n");
return NULL;
}
//查找逻辑
//定义遍历指针从头结点出发
Stu_str q = L->student;
for(int i=0; i<pos; i++)
{
q = q->next;
}
return q; //将找到的结点地址返回
}
//删除学生信息
int class_del(Class_str L)
{
//判断逻辑
if(L == NULL || L->student == NULL)
{
printf("删除失败!\n");
}
char Name[20] = {0};
printf("请输入要删除的学生姓名:");
scanf("%s",Name);
//找前驱结点
int pos = search_value(L,Name);
Stu_str q = search_pos(L,pos-1);
//删除逻辑
Stu_str p = q->next; //标记
q->next = p->next; //p->next 孤立
free(p); //释放
p = NULL;
printf("删除成功!\n");
return 0;
}
//修改学生信息
int class_update(Class_str L)
{
//判断逻辑
if(NULL==L || empty(L))
{
printf("修改失败!\n");
return -1;
}
char Name[20] = {0}, newName[20] = {0};
int Age = 0;
double Score = 0;
printf("请输入要修改的学生姓名:");
scanf("%s",Name);
putchar(10);
printf("请输入修改后的学生姓名:");
scanf("%s",newName);
printf("请输入修改后的学生年龄:");
scanf("%d",&Age);
printf("请输入修改后的学生分数:");
scanf("%lf",&Score);
//按位置查找逻辑
int pos = search_value(L,Name);
if(pos == -1)
{
return -1;
}
Stu_str p = search_pos(L, pos);
//修改逻辑
strcpy(p->name,newName);
p->age = Age;
p->score = Score;
printf("修改成功!\n");
return 0;
}
//查询学生信息
int class_search(Class_str L)
{
//判断逻辑
if(L==NULL||empty(L))
{
printf("查询失败!\n");
return -1;
}
char Name[20] = {0};
printf("请输入要查询的学生姓名:");
scanf("%s",Name);
int pos = search_value(L,Name);
if(pos == -1)
{
return -1;
}
Stu_str p = search_pos(L,pos);
printf("你查询的学生信息如下\n");
printf("\t姓名\t年龄\t分数\n");
printf("\t%s\t%d\t%lf\n",\
p->name, p->age, p->score);
return 0;
}
//销毁班级
void destroy(Class_str L)
{
//判断逻辑
if(NULL == L)
{
return;
}
//将所有结点进行释放
while(!empty(L))
{
//头删
class_delete_head(L);
}
//释放头结点
free(L);
L = NULL;
printf("销毁成功!\n");
}
main.c:
#include"head.h"
int main(int argc, const char *argv[])
{
//菜单
int menu = 0;
//创建班级
Class_str L = class_create();
if(L == NULL)
{
return -1;
}
//循环
while(1)
{
create_menu(); //创建菜单
printf("请输入操作码:");
scanf("%d",&menu);
getchar();
switch(menu)
{
case 1:
{
input_student(L); //录入学生信息
}
break;
case 2:
{
class_show(L); //展示学生信息
}
break;
case 3:
{
Class_sort(&L); //按成绩把班级学生信息降序
}
break;
case 4:
{
Class_maxmin(L); //展示成绩最高和最低学生的信息
}
break;
case 5:
{
class_add(L); //添加学生信息
}
break;
case 6:
{
class_del(L); //删除学生信息
}
break;
case 7:
{
class_update(L); //修改学生信息
}
break;
case 8:
{
class_search(L); //查询学生信息
}
break;
case 9:
{
destroy(L); //销毁班级
}
break;
case 0:goto END;
default:printf("不存在该操作码!\n");
}
}
END:
return 0;
}
运行结果:
思维导图: