无头结点的单向链表的实现如下:
1、linklist.h 文件
/*
* 线性表的链式存储结构(无头结点的单向链表)
*/
#ifndef LINKLIST_H__
#define LINKLIST_H__
// 宏定义
#define NAMESIZE 32
/*
* 单向链表结构
* 学生信息
*/
typedef struct stuinfo_st {
int id; // 学号
char name[NAMESIZE]; // 姓名
int chinese; // 语文
int math; // 数学
int english; // 英语
}stuinfo;
/*
* 单向链表结构
*/
typedef struct node_st {
struct stuinfo_st data; // 数据结点
struct node_st *next; // 指向下一个结点的指针
}linklist;
/*
* 从链表头部往单向链表中插入数据
*/
int linklist_insert(linklist **, stuinfo *);
/*
* 从单向链表的头部删除数据
*/
int linklist_delete(linklist **);
/*
* 在单向链表中根据 ID 查找数据
*/
stuinfo * linklist_find(linklist *, int);
/*
* 遍历单向链表
*/
void linklist_display(linklist *);
/*
* 销毁单向链表
* 释放单向链表所占内存
*/
void linklist_destroy(linklist *);
#endif
2、linklist.c 文件
#include <stdio.h>
#include <stdlib.h>
#include "linklist.h"
/*
* 从链表头部往单向链表中插入数据
*/
int linklist_insert(linklist **ptr, stuinfo *data) {
linklist *node; // 要插入数据的结点
node = malloc(sizeof(*node));
if (node == NULL) {
return -1;
}
// 给结点赋值
node->data = *data;
// 将插入的结点指向链表的头部
node->next = *ptr;
// 将链表的头部改为插入的结点
*ptr = node;
// 成功插入
return 0;
}
/*
* 从单向链表的头部删除数据
*/
int linklist_delete(linklist **ptr) {
linklist *node; // 要删除的结点
if (*ptr == NULL) {
// 空链表
return -1;
}
// 将要删除的结点指向到链表的头部
node = *ptr;
// 将链表的头部指向到链表的第二个结点
*ptr = (*ptr)->next;
// 释放要删除结点所占内存
free(node);
// 将要删除结点指向为 NULL
node = NULL;
// 删除成功
return 0;
}
/*
* 在单向链表中根据 ID 查找数据
*/
stuinfo * linklist_find(linklist *ptr, int id) {
linklist *node = ptr; // 当前结点
while (node != NULL) {
if (node->data.id == id) {
// 找到数据
return &node->data;
}
node = node->next;
}
// 找不到数据
return NULL;
}
/*
* 遍历单向链表
*/
void linklist_display(linklist *ptr) {
linklist *node = ptr; // 当前结点
while (node != NULL) {
printf("%d %s %d %d %d\n", node->data.id, node->data.name, node->data.chinese, node->data.math, node->data.english);
node = node->next;
}
return; // 无返回值
}
/*
* 销毁单向链表
* 释放单向链表所占内存
*/
void linklist_destroy(linklist *ptr) {
linklist *node; // 要释放的结点
if (ptr == NULL) {
// 空链表
return; // 无返回值
}
// 将要释放的结点指向到链表的头部
node = ptr;
while (node != NULL) {
// 将链表的头部指向到当前要释放结点的下一个结点
ptr = node->next;
// 释放当前要释放结点所占内存
free(node);
// 将要释放的结点指向到当前链表的头部
node = ptr;
}
return; // 无返回值
}
3、main.c 文件
#include <stdio.h>
#include <stdlib.h>
#include "linklist.h"
int main() {
int i; // 循环索引值
int ret; // 返回状态值
linklist *list = NULL;
stuinfo stu_st, *stu_ptr; // 操作中的学生信息
int id = 3; // 要查找的学号
/* 从链表头部往单向链表中插入 7 条随机数据 */
for (i = 0; i < 7; i++) {
stu_st.id = i; // 学号
snprintf(stu_st.name, NAMESIZE, "stu%d", i); // 姓名
stu_st.chinese = rand() % 100; // 语文
stu_st.math = rand() % 100; // 数学
stu_st.english = rand() % 100; // 英语
ret = linklist_insert(&list, &stu_st);
if (ret != 0) {
fprintf(stderr, "数据插入失败!\n");
exit(1);
}
}
/* 遍历单向链表 */
printf("链表中的学生信息:\n");
linklist_display(list);
/* 从单向链表的头部删除数据 */
linklist_delete(&list);
/* 遍历单向链表 */
printf("\n链表中的学生信息:\n");
linklist_display(list);
printf("\n");
stu_ptr = linklist_find(list, id);
if (stu_ptr == NULL) {
printf("没有找到任何数据!\n");
} else {
printf("%d %s %d %d %d\n", stu_ptr->id, stu_ptr->name, stu_ptr->chinese, stu_ptr->math, stu_ptr->english);
}
/* 销毁单向链表 */
linklist_destroy(list);
exit(0);
}
4、Makefile 文件
OBJS=main.o linklist.o
CC=gcc
CFLAGS+=-c -Wall -g
linklist:$(OBJS)
$(CC) $^ -o $@
%.o:%.c
$(CC) $^ $(CFLAGS) -o $@
clean:
$(RM) *.o linklist -r
执行效果:
gcc main.c -c -Wall -g -o main.o
gcc linklist.c -c -Wall -g -o linklist.o
gcc main.o linklist.o -o linklist
root@RicenOS:~# ./linklist
链表中的学生信息:
6 stu6 72 36 11
5 stu5 26 40 26
4 stu4 90 59 63
3 stu3 21 62 27
2 stu2 86 92 49
1 stu1 15 93 35
0 stu0 83 86 77
链表中的学生信息:
5 stu5 26 40 26
4 stu4 90 59 63
3 stu3 21 62 27
2 stu2 86 92 49
1 stu1 15 93 35
0 stu0 83 86 77
3 stu3 21 62 27
Copyright © 2005-2023 by www.ricensoftwares.com.cn All Rights Reserved.