单链表的实现 | 附学生信息管理系统的实现

目录

1.前言:

2.单链表的相关概念:

2.1定义:

2.2形式:

2.3特点:

3.常见功能及代码 :

3.1创建节点:

3.2头插:

3.3尾插:

3.4头删:

3.5尾删:

3.6插入(指定位置pos之前)

3.7插入(在指定位置pos之后)

3.8删除(指定位置pos前)

3.9删除(指定位置pos之后)

3.10打印链表:

3.11查找

3.12销毁链表:

4.总代码:

4.1 SList.h

4.2 SList.c

4.3 test.c

5.附:学生信息管理与信息系统:

6.总结:


1.前言:

今天,小邓儿带咱们来看看一个常见的数据结构——“单链表”。通过今天的学习,你将熟练地掌握单链表,还可以将其应用在学生信息管理系统中。废话不多说,咱们开始今天的探秘。

2.单链表的相关概念:

2.1定义:

单链表(Singly Linked List)是一种链式存储的线性数据结构,由一系列节点(Node)组成,每个节点包含两个部分:

  • 数据域(Data):存储实际的数据元素。
  • 指针域(Next):存储指向下一个节点的引用(或指针)。

2.2形式:

以整型数据为例:

2.3特点

  • 节点通过指针依次连接,形成链状结构。
  • 最后一个节点的指针域为 null(或 None),表示链表的结束。
  • 链表的大小是动态的,可以灵活地插入和删除节点。

3.常见功能及代码 :

3.1创建节点:

3.2头插:

思路:

1.定义一个新节点newnode;

2.newnode的下一个结点指向头节点;

3.将newnode作为新的头节点。

代码:

3.3尾插:

思路:

1.判断该链表是否为空。若是空链表,同头插思路相同;

2.若是不为空。遍历链表,将最后一个节点的下一个节点,指向新节点。

代码:

3.4头删:

思路:

1.判空。若为空,返回NULL;

2.不为空,定义一个next指针(指向头节点下一个节点);

3.将next作为新的头节点。

代码:

3.5尾删:

思路:

1.判空。若为空,返回NULL;

2.不为空,定义一个pre指针指向NULL,再定义一个ptail指针遍历链表;

3.当ptail的下一个节点不为空,将pre指向ptail所在位置,ptail继续遍历链表,直至ptail下一个指针为空;

4.此时,将pre的下一个指针指为空,并释放ptail指针空间。

代码:

3.6插入(指定位置pos之前)

思路:

1.判空。若为空,调用头插;

2.不为空,定义一个新节点newnode来存储要插入的数据;

3.在定义一个pre指针指向头节点(用来寻找*pos);

4.找到pos后,将pre的下一个节点指向newnode节点,并将newnode的下一个节点指向pos;

代码:

3.7插入(在指定位置pos之后)

思路:

1.判空。若为空,调用头插;

2.不为空,定义一个新节点newnode来存储要插入的数据;

3.将newnode的下一个节点指向pos的下一个节点;

4.再将pos的下一个节点指向newnode.(注意:这里的3、4步骤不可以颠倒

正常思路:

如果颠倒:(newnode的下一个节点,就不能指向原先4所在的节点。只能指向newnode节点)

代码:

3.8删除(指定位置pos前)

思路:

1.判断pos是否为头节点,是的话,头删;

2.不是头节点,定义一个pcur节点指向头节点;

3.用pcur来遍历链表,直至pcur的下一个节点是pos;

4.此时,将pcur的下一个节点指向pos的下一个节点,并释放pos节点的空间。

代码:

3.9删除(指定位置pos之后)

思路:

1.判断pos是否为头节点,是的话,头删;

2.不是头节点,定义一个pcur节点指向pos的下一个节点;

3.将pos的下一个节点指向pcur的下一个节点。

代码:

3.10打印链表:

代码:

3.11查找:

代码:

3.12销毁链表:

代码:

4.总代码:

4.1 SList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDateType;
typedef struct SLNode
{SLDateType data;struct Node* next;
}Node;
Node* BuyNode(SLDateType X);
//打印
void SLPrintf(Node*plist);
//尾插
void SLPushBack(Node** plist, SLDateType X);
//头插
void SLPushFront(Node** plist, SLDateType X);
//尾删
void SLPopback(Node** plist);
//头删
void SLPopFront(Node** plist);
//查找
Node* SLSearch(Node* plist, SLDateType X);
//指定位置前插入
void SLInsert(Node** plist, Node*pos,SLDateType X);
//指定位置之后插入
void SLInsertAfter(Node** plist, Node* pos, SLDateType X);
//删除指定位置的数据
void SLErase(Node** plist, Node* pos);
//删除指定节点后的数据
void SLEraseAfter( Node**plist,Node* pos);
//销毁
void SLDestory(Node** plist);

4.2 SList.c

#include"SList.h"
Node* BuyNode(SLDateType X)
{Node* newnode = (Node*)malloc(sizeof(SLDateType));if (newnode == NULL){perror("malloc fail\n");return NULL;}newnode->data = X;newnode->next = NULL;return newnode;
}
void SLPrintf(Node* plist)
{if(plist==NULL){exit(1);}Node* pcur = plist;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;}printf("NULL\n");
}
void SLPushBack(Node** phead, SLDateType X)
{assert(phead);Node* newnode = BuyNode(X);if (*phead == NULL){*phead = newnode;}else{Node* ptail = *phead;while (ptail->next){ptail = ptail->next;}ptail->next = newnode;}
}
void SLPushFront(Node** phead, SLDateType X)
{assert(phead);Node* newnode = BuyNode(X);newnode->next = *phead;*phead = newnode;
}
void SLPopback(Node** plist)
{assert(plist&&*plist);if ((plist && *plist) == NULL){free(*plist);*plist= NULL;}else{Node* pre = NULL;Node* ptail =* plist;while (ptail->next){pre = ptail;ptail = ptail->next;}pre->next = NULL;free(ptail);ptail = NULL;}
}
void SLPopFront(Node** plist)
{assert(plist && *plist);if ((plist && *plist) == NULL){free(*plist);*plist = NULL;}else{Node*next=(*plist)->next;free(*plist);*plist = next;}
}
Node* SLSearch(Node* plist, SLDateType X)
{assert(plist);Node* pcur = plist;while (pcur->data != X){pcur = pcur->next;}if (pcur->next){return pcur;}else return NULL;
}
void SLInsert(Node**plist,Node*pos, SLDateType X)
{assert(plist && pos);if (pos == plist){SLPushFront;}else{Node* newnode=BuyNode(X);Node* pre = *plist;while (pre->next != pos){pre = pre->next;}pre->next = newnode;newnode->next= pos;}
}
void SLInsertAfter(Node** plist, Node* pos, SLDateType X)
{assert(plist && pos);if (pos == plist){SLPushFront;}else{Node* newnode = BuyNode(X);newnode->next = pos->next;pos->next = newnode;}
}
void SLErase(Node** plist, Node* pos)
{assert(plist && pos);if (pos == *plist){SLPopFront(&plist);}else {Node* pcur = *plist;while((pcur->next) != pos){pcur = pcur->next;}pcur->next = pos->next;free(pos);pos = NULL;}
}
void SLEraseAfter(Node**plist, Node* pos)
{assert( pos);Node* pcur = pos->next;pos->next = pcur->next;free(pcur);pcur = NULL;
}
void SLDestory(Node** plist)
{Node* pcur = *plist;while (pcur){Node* pre = pcur->next;free(pcur);pcur = pre;}*plist = NULL;
}

4.3 test.c

#include"SList.h"
void test1()
{Node* p1 = (Node*)malloc(sizeof(Node));Node* p2 = (Node*)malloc(sizeof(Node));Node* p3 = (Node*)malloc(sizeof(Node));assert(p1&&p2&&p3);if (p1 == NULL){return 0;}p1->data = 1;p2->data = 2;p3->data = 3;p1->next = p2;p2->next = p3;p3->next = NULL;Node* plist = p1;SLPrintf(plist);
}
void test2()
{Node* plist = NULL;SLPushBack(&plist, 1);SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPushBack(&plist, 4);//SLPrintf(plist);SLPushFront(&plist, 5);SLPrintf(plist);SLPopback(&plist);SLPrintf(plist);SLPopFront(&plist);SLPrintf(plist);Node* P = SLSearch(plist, 2);if (P){printf("找到%d了\n", P->data);}else printf("未找到\n");SLInsert(&plist, P, 6);//SLPrintf(plist);SLInsertAfter(&plist, P, 7);SLPrintf(plist);SLErase(&plist, P);SLPrintf(plist);SLEraseAfter(&plist,7);SLPrintf(plist);SLDestory(plist);
}int main()
{test2();return 0;
}

5.附:学生信息管理与信息系统:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>typedef struct Student {char id[10];char name[20];float score;
} Stu;typedef struct LinkNode {Stu* data;struct LinkNode* next;
} Node;// 初始化单链表
void InitList(Node** L) {*L = (Node*)malloc(sizeof(Node));if (*L == NULL) {perror("malloc failed!\n");exit(1);}(*L)->next = NULL;(*L)->data = NULL;
}// 创建新结点
Node* CreateNode(Stu* x) {Node* newNode = (Node*)malloc(sizeof(Node));if (newNode == NULL) {perror("malloc failed!\n");exit(1);}newNode->data = x;newNode->next = NULL;return newNode;
}// 插入记录(尾插)
void Insert(Node** L, Stu* x) {Node* newNode = CreateNode(x);if (*L == NULL) {*L = newNode;}else {Node* ptail = *L;while (ptail->next) {ptail = ptail->next;}ptail->next = newNode;}
}// 查找功能1:按姓名查找
Node* SearchByName(Node* L, char* name) {Node* pcur = L->next;while (pcur) {if (strcmp(pcur->data->name, name) == 0) {return pcur;}pcur = pcur->next;}return NULL;
}// 查找功能2:按学号查找
Node* SearchByID(Node* L, char* id) {Node* pcur = L->next;while (pcur) {if (strcmp(pcur->data->id, id) == 0) {return pcur;}pcur = pcur->next;}return NULL;
}// 删除功能:按学号删除记录
void Delete(Node** L, char* id) {Node* c = SearchByID(*L, id);if (c == NULL) {printf("未找到学号为 %s 的记录!\n", id);return;}Node* pre = *L;while (pre->next != c) {pre = pre->next;}pre->next = c->next;free(c->data);free(c);printf("删除成功!\n");
}// 修改功能:按学号修改记录
void Change(Node** L, char* id) {Node* c = SearchByID(*L, id);if (c == NULL) {printf("未找到学号为 %s 的记录!\n", id);return;}Stu* s = (Stu*)malloc(sizeof(Stu));if (s == NULL) {perror("malloc failed!\n");exit(1);}printf("请输入修改后的信息(学号 姓名 成绩):\n");scanf("%s%s%f", s->id, s->name, &s->score);strcpy(c->data->id, s->id);strcpy(c->data->name, s->name);c->data->score = s->score;free(s);printf("修改成功!\n");
}// 输出所有记录
void DispList(Node* L) {Node* pcur = L->next;if (!pcur) {printf("链表为空,无记录可显示!\n");return;}printf("所有记录如下:\n");while (pcur) {printf("学号:%s,姓名:%s,成绩:%.2f\n",pcur->data->id, pcur->data->name, pcur->data->score);pcur = pcur->next;}
}// 销毁链表
void Destroy(Node** L) {Node* pcur = *L;while (pcur) {Node* temp = pcur;pcur = pcur->next;free(temp->data);free(temp);}*L = NULL;
}// 显示菜单
void show_screen() {printf("\n***************       功能选择     *****************\n");printf("*************** 1: 录入学生记录     ***************\n");printf("*************** 2: 添加学生记录     ***************\n");printf("*************** 3: 按学号删除记录   ***************\n");printf("*************** 4: 按学号修改记录   ***************\n");printf("*************** 5: 按姓名查找记录   ***************\n");printf("*************** 6: 显示所有记录     ***************\n");printf("*************** 7: 清屏             ***************\n");printf("*************** 8: 退出管理系统     ***************\n");
}int main() {Node* LinkStudent = NULL;InitList(&LinkStudent);while (1) {int choose;show_screen();printf("请选择:\n");scanf("%d", &choose);int c;while ((c = getchar()) != '\n' && c != EOF); // 清空scanf缓冲区switch (choose) {case 1: // 添加学生信息printf("请输入学生信息(学号 姓名 成绩),输入三次:\n");for (int i = 0; i < 3; i++) {Stu* s = (Stu*)malloc(sizeof(Stu));if (s == NULL) {perror("malloc failed!\n");exit(1);}scanf("%s%s%f", s->id, s->name, &s->score);Insert(&LinkStudent, s);}break;case 2: // 添加单条学生记录{Stu* s = (Stu*)malloc(sizeof(Stu));if (s == NULL) {perror("malloc failed!\n");exit(1);}printf("请输入学生信息(学号 姓名 成绩):\n");scanf("%s%s%f", s->id, s->name, &s->score);Insert(&LinkStudent, s);}break;case 3: // 按学号删除记录{char id[10];printf("请输入要删除的学号:");scanf("%s", id);Delete(&LinkStudent, id);}break;case 4: // 按学号修改记录{char id[10];printf("请输入要修改的学号:");scanf("%s", id);Change(&LinkStudent, id);}break;case 5: // 按姓名查找记录{char name[20];printf("请输入要查找的姓名:");scanf("%s", name);Node* result = SearchByName(LinkStudent, name);if (result) {printf("找到记录:学号:%s,姓名:%s,成绩:%.2f\n",result->data->id, result->data->name, result->data->score);}else {printf("未找到姓名为 %s 的记录!\n", name);}}break;case 6: // 显示所有记录DispList(LinkStudent);break;case 7: // 清屏system("cls");break;case 8: // 退出管理系统Destroy(&LinkStudent);printf("退出系统,拜拜!\n");return 0;default: // 输入错误printf("无效选项,请重新输入!\n");break;}}return 0;
}

6.总结:

小邓儿的本次学生信息管理系统,在插入、删除部分只用了一种方式,不是很完善,咱们可以用自行思考,看看怎么样加入其他方式,使得系统选择更多O(∩_∩)O

好了,今天的分享就到这里儿。别忘了点赞收藏😄😄😄

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/75782.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java实用工具类Localstorage

public class LocalStorageUtil {//提供ThreadLocal对象,private static ThreadLocal threadLocalnew ThreadLocal();public static Object get(){return threadLocal.get();}public static void set(Object o){threadLocal.set(o);}public static void remove(){threadLocal.r…

LLM-大语言模型浅谈

目录 核心定义 典型代表 核心原理 用途 优势与局限 未来发展方向 LLM&#xff08;Large Language Model&#xff09;大语言模型&#xff0c;指通过海量文本数据训练 能够理解和生成人类语言的深度学习模型。 核心定义 一种基于深度神经网络&#xff08;如Transformer架…

【小兔鲜】day03 Home模块与一级分类

【小兔鲜】day03 Home模块与一级分类 1. Home-整体结构搭建和分类实现1.1 页面结构 2. Home-banner轮播图功能实现 1. Home-整体结构搭建和分类实现 1.1 页面结构 分类实现 2. Home-banner轮播图功能实现 轮播图实现 在HomeBanner.vue中写出轮播图的结构 在apis目录下新建h…

C++中的多态和模板

#include <iostream> #include <cstdlib> #include <ctime> #include <string>using namespace std;// 武器基类 class Weapon { public:virtual ~Weapon() {}virtual string getName() const 0; // 获取武器名称virtual int getAtk() const 0; …

Spring 概念

Spring 是一个功能强大、灵活且广泛使用的 Java 企业级开发框架&#xff0c;它诞生于 2003 年&#xff0c;由 Rod Johnson 创建&#xff0c;初衷是简化 Java EE 的开发过程。 一、Spring 是什么&#xff1f; 简单来说&#xff1a; Spring 是一个轻量级的 Java 开发框架&#…

神经网络之损失函数

引言&#xff1a;损失函数 &#xff08;Loss Function&#xff09;是机器学习和深度学习中非常重要的一个概念。用于衡量模型的预测值与真实值之间的差异&#xff0c;从而指导模型优化其参数以最小化这种差异。 一、损失函数作用 量化误差&#xff1a;损失函数是将预测值和真实…

Java 基础-32-枚举-枚举的应用场景

在Java编程中&#xff0c;枚举&#xff08;Enum&#xff09;提供了一种强大的方式来定义一组固定的常量。它们不仅限于简单的用途&#xff0c;还可以包含构造函数、方法和字段等高级功能&#xff0c;使其适用于多种不同的应用场景。本文将探讨几种常见的使用枚举的场景&#xf…

【网络安全】安全的网络设计

网络设计是网络安全的基础&#xff0c;一个好的网络设计可以有效的防止攻击者的入侵。在本篇文章中&#xff0c;我们将详细介绍如何设计一个安全的网络&#xff0c;包括网络架构&#xff0c;网络设备&#xff0c;网络策略&#xff0c;以及如何处理网络安全事件。 一、网络架构…

网络安全-等级保护(等保) 0. 前言

各位伙伴好&#xff1a; 招投标总结已过去一年了&#xff0c;时间飞逝&#xff0c;一直忙于工作&#xff0c;等保相关的内容断断续续整理了近半年的时间&#xff0c;但一直无暇完成博客内容。 等保已经是一个成熟的体系&#xff0c;现在已进入等保2.0时代&#xff0c;相关政策…

TLS协议详解

TLS协议 一&#xff0c;TLS协议的组成 TLS协议架构模块分为两层&#xff1a;TLS记录协议&#xff0c;TLS握手协议 ① TLS记录协议&#xff1a; 是所有子协议的基层&#xff0c;规定了TLS收发数据的基本单位。所有子协议都需要通过记录协议发出&#xff0c;多个记录数据可以在…

ollama更新升级及警告解决

1. 概述 在大模型业务处理中&#xff0c;需要用到gemma3 和 qwen2.5-VL&#xff0c;当前服务器的ollama版本 0.3.11&#xff0c;无法满足要求&#xff0c;需要更新升级。 2. 实施过程 参考官网升级要求&#xff1a; curl -fsSL https://ollama.com/install.sh | sh 不知道…

ubuntu 配置固定ip

在装服务器系统的时候&#xff0c;DHCP自动获取ip时&#xff0c;路由可能会重新分配ip&#xff0c;为避免产生影响&#xff0c;可以关闭DHCP将主机设置为静态ip。 系统环境 Ubuntu 22.04-Desktop 配置方式 一、如果是装的Ubuntu图形化&#xff08;就是可以用鼠标操作点击应用…

套接字编程函数recv和send ,以及设置reuseaddress

recv就是去套接字读缓冲区读数据 阻塞模式下&#xff1a;读缓冲区没数据那就阻塞等待&#xff0c;若等待被打断返回-1设置errno为EINTR 非阻塞模式下&#xff1a;读缓冲区没数据那就返回-1&#xff0c;设置errno为EAGAIN或EWOULDBLOCK。 若连接断开返回0&#xff0c;读取成功…

《C++后端开发最全面试题-从入门到Offer》目录

当今科技行业对C++开发者的需求持续高涨,从金融科技到游戏开发,从嵌入式系统到高性能计算,C++凭借其卓越的性能和灵活性始终占据着关键地位。然而,成为一名优秀的C++工程师并非易事,不仅需要扎实的语言基础,还要掌握现代C++特性、设计模式、性能优化技巧以及各种工业级开…

设计模式简述(十)责任链模式

责任链模式 描述基本使用使用 描述 如果一个请求要经过多个类似或相关处理器的处理。 可以考虑将这些处理器添加到一个链上&#xff0c;让请求逐个经过这些处理器进行处理。 通常&#xff0c;在一个业务场景下会对整个责任链进行初始化&#xff0c;确定这个链上有哪些Handler…

初识数据结构——Java集合框架解析:List与ArrayList的完美结合

&#x1f4da; Java集合框架解析&#xff1a;List与ArrayList的完美结合 &#x1f31f; 前言&#xff1a;为什么我们需要List和ArrayList&#xff1f; 在日常开发中&#xff0c;我们经常需要处理一组数据。想象一下&#xff0c;如果你要管理一个班级的学生名单&#xff0c;或…

ReFormX:现代化的 React 表单解决方案 - 深度解析与最佳实践

ReFormX文档 表单开发一直是前端工作中最繁琐却又最常见的任务之一。从简单的登录表单到复杂的多步骤配置页面&#xff0c;开发者往往需要编写大量重复代码&#xff0c;处理繁琐的状态管理、数据验证和联动逻辑。ReFormX 应运而生&#xff0c;它不仅是一个表单组件库&#xff…

WinForm真入门(9)——RichTextBox控件详解

WinForm中RichTextBox控件详解&#xff1a;从基础到高级应用 上一文中笔者重点介绍了TextBox控件的详细用法&#xff0c;忘记的 请点击WinForm真入门(8)——TextBox控件详解&#xff0c;那么本文中的RichTextBox与TextBox有什么区别吗&#xff0c;光看名字的话&#xff0c;多了…

Draw.io 全面解析与竞品分析:图表绘制工具的深度对比

目录 一、Draw.io 全面介绍 1. 产品概述 2. 核心功能特点 3. 用户体验 4. 商业模式 二、市场竞品分析 1. 主要竞品概览 2. 深度功能对比 3. 价格策略对比 4. 技术架构对比 三、用户场景与选择建议 1. 不同场景下的工具推荐 2. 未来发展趋势 四、结论 diagrams.net…

kafka分区策略详解

Kafka 分区策略详解 Kafka 的分区策略决定了消息在生产者端如何分配到不同分区&#xff0c;以及在消费者端如何动态分配分区以实现负载均衡。以下是 Kafka 核心分区策略及其适用场景的详细解析&#xff1a; 1、生产者分区策略 生产者负责将消息发送到 Topic 的特定分区&#…