在此前的文章中(链接如下),只有单向链表的代码,接下来我们来写单向循环链表,并用其实现一个简单的学生信息链表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);
}