我们以题目为切入点,深入了解链表代码实现。
题目(单项链表)
题目描述
实现一个数据结构,维护一张表(最初只有一个元素 1)。需要支持下面的操作,其中 x 和 y 都是 1 到 1000000 范围内的正整数,且保证任何时间表中所有数字均不相同,操作数量不多于 100000:
1 x y
:将元素 y 插入到 x 后面;2 x
:询问 x 后面的元素是什么。如果 x 是最后一个元素,则输出 0;3 x
:从表中删除元素 x 后面的那个元素,不改变其他元素的先后顺序。
输入格式
第一行一个整数 q 表示操作次数。
接下来 q 行,每行表示一次操作,操作具体间题目描述。
输出格式
对于每个操作 2,输出一个数字,用换行隔开。
输入输出样例
输入 #1
6
1 1 99
1 99 50
1 99 75
2 99
3 75
2 1
输出 #1
75
99
代码解析:
首先说清楚,这道题我并没有完完全全写出来,时间超限了。我觉得这道题比较经典,所以写这篇博客。主要是用来捋清楚链表代码流程。
头文件
#include <stdio.h>//c语言一般都要有
#include <stdlib.h>//链表的实现需要这个库函数的free和malloc函数
free函数
free
函数在 C 语言中用于释放之前通过 malloc
、calloc
或 realloc
函数分配的内存。当你不再需要一块动态分配的内存时,应当使用 free
来释放它,以避免内存泄漏。
函数原型:
void free(void *ptr);
其中,ptr
是一个指向之前分配的内存块的指针。这个指针必须是 malloc
、calloc
或 realloc
返回的指针,或者是这些指针的副本(即,指向相同内存地址的指针)。
//释放特定内存
int *ptr = (int *)malloc(sizeof(int));
if (ptr != NULL) {
// 使用 ptr
free(ptr); // 释放内存
ptr = NULL; // 将指针设为 NULL,防止悬挂指针
}
//释放连续内存
int *array = (int *)malloc(10 * sizeof(int));
if (array != NULL) {
// 使用 array
free(array); // 释放整个数组
array = NULL; // 将指针设为 NULL
}
malloc函数
malloc
是 C 语言标准库中的一个函数,用于在堆区分配指定大小的内存空间。
函数原型:
void* malloc(size_t size);
其中,size
是要分配的内存块的大小(以字节为单位)。malloc
函数返回一个指向新分配内存的指针,如果分配成功,该指针指向被分配的内存的首地址;如果分配失败,则返回 NULL
。
数组内存分配
int *array = (int *)malloc(10 * sizeof(int));
检查返回值:始终检查 malloc
的返回值是否为 NULL
。如果返回 NULL
,则表示内存分配失败,可能是因为内存不足。如下:
int *array = (int *)malloc(10 * sizeof(int));
if (array == NULL) {
// 处理错误,例如输出错误信息并退出程序
fprintf(stderr, "Memory allocation failed.\n");
exit(EXIT_FAILURE);
}
在使用 malloc
时,请确保在程序的适当位置释放所有分配的内存,以避免内存泄漏。此外,由于 malloc
只负责分配内存,不负责初始化内存,因此在使用分配的内存之前,请确保对其进行适当的初始化。
exit函数
exit
函数是 C 语言标准库中的一个函数,用于立即终止程序的执行。
函数原型:
void exit(int status);
其中,status
是一个整数值,通常用于向操作系统返回程序的退出状态。通常,如果程序正常退出,status
应该是 EXIT_SUCCESS
(在 <stdlib.h>
中定义,通常为 0);如果程序因为某种错误而退出,status
应该是 EXIT_FAILURE
(同样在 <stdlib.h>
中定义,通常为 1)。
使用例子:
#include <stdio.h>
#include <stdlib.h>
int main() {
// 假设发生了某种错误
if (/* 错误条件 */) {
fprintf(stderr, "An error occurred, exiting the program.\n");
exit(EXIT_FAILURE); // 退出程序,返回错误状态码
}
// 程序继续执行...
exit(EXIT_SUCCESS); // 程序正常退出
}
此外,exit
函数与 return
语句不同。return
语句用于从当前函数中返回,而 exit
则用于终止整个程序。如果你在 main
函数中使用 return
语句,它的效果与调用 exit
是相同的,都会结束程序的执行。然而,exit
可以在任何函数中被调用,而不仅仅是 main
函数。
结构体的建立
typedef struct Node {
int value;
struct Node* next;
}Node;
Node* head = NULL;//链表的表头
主函数
主函数是主干。
int main()
{
head = (Node*)malloc(sizeof(Node));
head->value = 1;//题目要求第一个为1
head->next = NULL;//初始化
int n;//操作次数
scanf("%d", &n);//输入
while (n--) {
int m, x, y;//m为操作指令,可以用switch语句来实现
scanf("%d%d", &m, &x);
switch (m)
{
case 1://元素插入
scanf("%d", &y);
charu(x, y);
break;//不要忘了
case 2://元素查找
printf("%d\n",chaxun(x));
break;//不要忘了
case 3://元素删除
shanchu(x);
break;//不要忘了
default:printf("Invalid operation.\n");//翻译过来是无效操作。
}
}
return 0;
}
函数
插入函数
void charu(int x, int y)//插入
{
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
printf("Memory allocation failed.\n");//翻译过来是内存分配失败
exit(1);
}
newNode->value = y;
Node* p = head;
while (p != NULL&&p->value !=x) {//如果不是空链表进入寻找x的位置
p = p->next;
}
if (p->value != NULL) {//如果找到了
newNode->next = p->next;
p->next = newNode;
}
else {//如果没有找到
printf("Element %d not found in the list.\n", x);//翻译过来是元素x未在列表中找到。
}
}
查询函数
int chaxun(int x)
{
Node* p = head;
while (p != NULL && p->value != x) //如果不是空链表进入寻找x的位置
p = p->next;
if (p != NULL && p->next != NULL) {//如果都没有超出链表长度的话就找到查询的数字了
return p->next->value;
}
else return 0;
}
删除函数
void shanchu(int x)
{
Node* p = head;
while (p != NULL && p->value != x) //如果不是空链表进入寻找x的位置
p = p->next;
if (p != NULL && p->next != NULL) {
Node* q = p->next;
p->next = q->next;//删除的精髓
free(q);//空间释放
}
else printf("Element %d or its successor is not found in the list.\n", x);//自己翻译吧
}
完整代码
#include<stdio.h>
#include<stdlib.h>
typedef struct Node {
int value;
struct Node* next;
}Node;
Node* head = NULL;
void charu(int x, int y)//插入
{
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
printf("Memory allocation failed.\n");//翻译过来是内存分配失败
exit(1);
}
newNode->value = y;
Node* p = head;
while (p != NULL&&p->value !=x) {//如果不是空链表进入寻找x的位置
p = p->next;
}
if (p->value != NULL) {//如果找到了
newNode->next = p->next;
p->next = newNode;
}
else {//如果没有找到
printf("Element %d not found in the list.\n", x);//翻译过来是元素x未在列表中找到。
}
}
int chaxun(int x)
{
Node* p = head;
while (p != NULL && p->value != x) //如果不是空链表进入寻找x的位置
p = p->next;
if (p != NULL && p->next != NULL) {//如果都没有超出链表长度的话就找到查询的数字了
return p->next->value;
}
else return 0;
}
void shanchu(int x)
{
Node* p = head;
while (p != NULL && p->value != x) //如果不是空链表进入寻找x的位置
p = p->next;
if (p != NULL && p->next != NULL) {
Node* q = p->next;
p->next = q->next;//删除的精髓
free(q);//空间释放
}
else printf("Element %d or its successor is not found in the list.\n", x);//自己翻译吧
}
int main()
{
head = (Node*)malloc(sizeof(Node));
head->value = 1;//题目要求第一个为1
head->next = NULL;//初始化
int n;//操作次数
scanf("%d", &n);//输入
while (n--) {
int m, x, y;//m为操作指令,可以用switch语句来实现
scanf("%d%d", &m, &x);
switch (m)
{
case 1://元素插入
scanf("%d", &y);
charu(x, y);
break;//不要忘了
case 2://元素查找
printf("%d\n", chaxun(x));
break;//不要忘了
case 3://元素删除
shanchu(x);
break;//不要忘了
default:printf("Invalid operation.\n");//翻译过来是无效操作。
}
}
return 0;
}
最后,如果有时间,我会另一种方法重新敲写一遍再发布出来。