在此前的文章中(链接如下),只有单向链表的代码,接下来我们来写单向循环链表,并用其实现一个简单的学生信息链表https://blog.csdn.net/2301_80406299/article/details/151157051?spm=1011.2415.3001.10575&sharefrom=mp_manage_link
1、单向链表与单向循环链表的不同
单向链表:尾节点的
next
指针坚定地指向NULL
。这个NULL
像一个终点站的标志,明确告知遍历者:“链表至此结束,前方无路”。这使得单向链表在逻辑上呈现为一种线性开环结构,有头有尾,有明确的起点和终点。
单向循环链表:尾节点的
next
指针则指向了头节点。这一指向,如同将一条绳子的首尾相接,形成了一个闭合的环。它移除了结束的标志,使得遍历操作可以在链表中无限循环。因此,它是一种环形结构,没有传统意义上的“终点”。
单向循环链表代码——学生信息链表
主函数 main.c
/**
******************************************************************************
* @file main.c
* @author feng
* @version V0.0.1
* @date 2025.09.08
* @brief 使用单向循环链表实现数据的增删查改——学生信息链表
* 环境:ubuntu18.04
* 编译+执行:./project.sh
*
******************************************************************************
* @attention
*
* 本文档只供装逼学习使用,不得商用,违者必究
*
* github: https://github.com/(求我拿链接)
* CSDN: https://blog.csdn.net/(嘻嘻)
* gitee: https://gitee.com/(求我拿链接)
* 微信公众号: 没有
* 没有疑问或者建议:12345678910@qq.com
*
* ******************************************************************************
*/
#include "singly_circular_link_list.h"
int main(int argc, char const *argv[])
{
node_p head_node = sc_link_list_InitHeadNode();
if (head_node == NULL)
{
printf("头节点初始化失败!\n");
return -1;
}
node_p new_node = NULL;
int select = 0;
char name[20];
int id, grade, age;
float score;
int search_id, del_id, change_id;
while (1)
{
sc_link_list_ShowListData(head_node);
printf("\n请选择以下功能:\n");
printf("1、插入数据(头插法)\n");
printf("2、插入数据(尾插法)\n");
printf("3、删除数据\n");
printf("4、修改数据\n");
printf("5、查找数据\n");
printf("6、退出系统\n");
printf("请选择: ");
scanf("%d", &select);
while (getchar() != '\n'); // 清空输入缓冲区
switch (select)
{
case 1: // 头插法
printf("\n--- 添加学生(头插法) ---\n");
printf("姓名: "); scanf("%19s", name);
printf("学号: "); scanf("%d", &id);
printf("年级: "); scanf("%d", &grade);
printf("成绩: "); scanf("%f", &score);
printf("年龄: "); scanf("%d", &age);
while (getchar() != '\n');
new_node = sc_link_list_InitDataNode(name, id, grade, score, age);
if (!new_node) {
printf("创建节点失败!\n");
break;
}
sc_link_list_HeadInsert(head_node, new_node);
printf("添加成功!\n");
break;
case 2:
printf("\n--- 添加学生(尾插法) ---\n");
printf("姓名: "); scanf("%19s", name);
printf("学号: "); scanf("%d", &id);
printf("年级: "); scanf("%d", &grade);
printf("成绩: "); scanf("%f", &score);
printf("年龄: "); scanf("%d", &age);
while (getchar() != '\n');
new_node = sc_link_list_InitDataNode(name, id, grade, score, age);
if (!new_node) {
printf("创建节点失败!\n");
break;
}
sc_link_list_LastInsert(head_node, new_node);
printf("添加成功!\n");
break;
case 3: // 删除
printf("\n请输入要删除的学生学号: ");
scanf("%d", &del_id);
while (getchar() != '\n');
if (sc_link_list_DelNodeData(head_node, del_id) == 0) {
printf("删除成功!\n");
}
break;
case 4: // 修改
printf("\n请输入要修改的学生学号: ");
scanf("%d", &change_id);
while (getchar() != '\n');
printf("输入新的信息(留空则保持不变):\n");
printf("姓名: "); scanf("%19s", name);
printf("年级(0保持不变): "); scanf("%d", &grade);
printf("成绩(-1保持不变): "); scanf("%f", &score);
printf("年龄(0保持不变): "); scanf("%d", &age);
while (getchar() != '\n');
if (sc_link_list_ChangeNodeData(head_node, change_id,
name[0] ? name : NULL,
grade, score, age) == 0) {
printf("修改成功!\n");
}
break;
case 5:
printf("\n请输入要查找的学生学号: ");
scanf("%d", &search_id);
while (getchar() != '\n');
sc_link_list_SearchNodeData(head_node, search_id);
break;
case 6: // 退出
sc_link_list_Uninit(head_node);
printf("系统已退出!\n");
return 0;
default:
printf("无效选择,请重新输入!\n");
break;
}
}
}
头文件 singly_circular_link_list.h
/**
******************************************************************************
* @file singly_circular_link_list.h
* @author feng
* @version V0.0.1
* @date 2025.29.28
* @brief 单向循环链表的增删查改功能——学生信息链表
*
******************************************************************************
* @attention
*
* 本文档只供学习使用,不得商用,违者必究
*
* github: https://github.com/(求我拿链接)
* CSDN: https://blog.csdn.net/(嘻嘻)
* gitee: https://gitee.com/(求我拿链接)
* 微信公众号: 没有
* 没有疑问或者建议:12345678910@qq.com
*
* ******************************************************************************
*/
#ifndef SINGLY_CIRCULAR_LINK_LIST_H
#define SINGLY_CIRCULAR_LINK_LIST_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct student {
char name[20];
int id;
int grade;
float score;
int age;
} student_t;
typedef struct node {
student_t data;
struct node *next_p;
} node_t, *node_p;
node_p sc_link_list_InitHeadNode(void);
node_p sc_link_list_InitDataNode(const char *name, int id, int grade, float score, int age); // 修改3: 参数列表修改
void sc_link_list_HeadInsert(node_p head_node, node_p new_node);
void sc_link_list_LastInsert(node_p head_node, node_p new_node);
bool sc_link_list_IfEmpty(node_p head_node);
int sc_link_list_ShowListData(node_p head_node);
int sc_link_list_DelNodeData(node_p head_node, int del_id); // 修改4: 改为按学号删除
int sc_link_list_ChangeNodeData(node_p head_node, int find_id, const char *new_name, int new_grade, float new_score, int new_age); // 修改5: 参数列表修改
int sc_link_list_SearchNodeData(node_p head_node, int search_id); // 修改6: 改为按学号查找
void sc_link_list_Uninit(node_p head_node);
#endif
功能函数:singly_circular_link_list
#include "singly_circular_link_list.h"
node_p sc_link_list_InitHeadNode(void)
{
node_p p = malloc(sizeof(node_t));
if (p != NULL)
{
memset(p, 0, sizeof(node_t));
p->next_p = p;
}
return p;
}
node_p sc_link_list_InitDataNode(const char *name, int id, int grade, float score, int age)
{
node_p p = malloc(sizeof(node_t));
if (p != NULL)
{
memset(p, 0, sizeof(node_t));
strncpy(p->data.name, name, sizeof(p->data.name)-1);
p->data.id = id;
p->data.grade = grade;
p->data.score = score;
p->data.age = age;
p->next_p = p;
}
return p;
}
void sc_link_list_HeadInsert(node_p head_node, node_p new_node)
{
new_node->next_p = head_node->next_p;
head_node->next_p = new_node;
}
void sc_link_list_LastInsert(node_p head_node, node_p new_node)
{
node_p temp_p = head_node;
while (temp_p->next_p != head_node)
{
temp_p = temp_p->next_p;
}
temp_p->next_p = new_node;
new_node->next_p = head_node;
}
bool sc_link_list_IfEmpty(node_p head_node)
{
return head_node->next_p == head_node;
}
int sc_link_list_ShowListData(node_p head_node)
{
if (sc_link_list_IfEmpty(head_node))
{
printf("链表为空!\n");
return -1;
}
node_p tem_p = head_node->next_p;
int i = 0;
printf("\n==================学生信息列表===================\n");
while (tem_p != head_node)
{
printf("学生 %d:\n", i+1);
printf(" 姓名: %s\n", tem_p->data.name);
printf(" 学号: %d\n", tem_p->data.id);
printf(" 年级: %d\n", tem_p->data.grade);
printf(" 成绩: %.2f\n", tem_p->data.score);
printf(" 年龄: %d\n", tem_p->data.age);
printf("--------------------------------------------\n");
tem_p = tem_p->next_p;
i++;
}
printf("================================================\n");
return 0;
}
int sc_link_list_DelNodeData(node_p head_node, int del_id)
{
if (sc_link_list_IfEmpty(head_node))
return -1;
node_p prev_p = head_node;
node_p curr_p = head_node->next_p;
while (curr_p != head_node)
{
if (curr_p->data.id == del_id)
{
prev_p->next_p = curr_p->next_p;
free(curr_p);
return 0;
}
prev_p = curr_p;
curr_p = curr_p->next_p;
}
printf("未找到学号为 %d 的学生\n", del_id);
return -1;
}
int sc_link_list_ChangeNodeData(node_p head_node, int find_id,
const char *new_name, int new_grade,
float new_score, int new_age)
{
if (sc_link_list_IfEmpty(head_node))
return -1;
node_p tem_p = head_node->next_p;
while (tem_p != head_node)
{
if (tem_p->data.id == find_id)
{
if (new_name) strncpy(tem_p->data.name, new_name, sizeof(tem_p->data.name)-1);
if (new_grade > 0) tem_p->data.grade = new_grade;
if (new_score >= 0) tem_p->data.score = new_score;
if (new_age > 0) tem_p->data.age = new_age;
return 0;
}
tem_p = tem_p->next_p;
}
printf("未找到学号为 %d 的学生\n", find_id);
return -1;
}
int sc_link_list_SearchNodeData(node_p head_node, int search_id)
{
if (sc_link_list_IfEmpty(head_node))
return -1;
node_p tem_p = head_node->next_p;
while (tem_p != head_node)
{
if (tem_p->data.id == search_id)
{
printf("\n找到学生信息:\n");
printf(" 姓名: %s\n", tem_p->data.name);
printf(" 学号: %d\n", tem_p->data.id);
printf(" 年级: %d\n", tem_p->data.grade);
printf(" 成绩: %.2f\n", tem_p->data.score);
printf(" 年龄: %d\n", tem_p->data.age);
return 0;
}
tem_p = tem_p->next_p;
}
printf("未找到学号为 %d 的学生\n", search_id);
return -1;
}
void sc_link_list_Uninit(node_p head_node)
{
if (!head_node) return;
node_p curr_p = head_node->next_p;
while (curr_p != head_node)
{
node_p next_p = curr_p->next_p;
free(curr_p);
curr_p = next_p;
}
free(head_node);
}