数据结构(单项链表)

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;
}

运行结果:

思维导图:

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值