2.5.单链表的定义


一.单链表的定义:

相比于顺序表,单链表不可随机存取,因此单链表中查找数据必须是一个一个找-->查找效率低


二.用代码定义一个单链表:

单链表每一个节点有数据元素存放该元素的指针,该指针指向下一个节点

GetElem方法解读:

把单链表L中的第i个节点取出来,并返回。

参数列表中LinkList L也可以用LNode *L。

LNode是一个结构体类型,LNode *就代表返回了一个指针,因为p为指针。(LNode * p)

LinkList是指针类型,用->关键词访问数据。

方法体解读:LNode *p=L->next;代表L是指针指向下一个节点

如果i为0,直接返回下一个节点;

不为0时如果走第二个if语句说明i为负数,边界点,如果是-1,下一个为0,但已经有了,

如果是-2,下一个是-1,就没意义了,返回空值。

两个if语句都没走时,就正常执行。

例如:


三.初始化单链表:

1.不带头结点的单链表:

注:InitList函数里的参数LinkList &L用了引用&,因为函数的结果和函数体的结果最后都还要用。没用&的话函数结束后相当于只得到了函数的结果,而函数体的结果就无法得到(比如没加&,最后得到了函数的返回值,但最终L是否被赋值为NULL就无法确定)。

2.带头结点的单链表:


四.不带头结点的单链表对比带头结点的单链表:

不带头结点的单链表那么头指针所指向的下一个节点就是实际用于存放数据的节点;

带头结点的单链表那么头指针他所指向的这个节点即头结点,是不存放实际元素的,只有这个头结点之后的下一个节点才会用于存放数据(常用带头结点的单链表)。


五.总结:


### 题目重述 实现顺序表和单链表的基本操作: 1. **顺序表**: - 建立顺序表 - 在指定位置插入元素 - 删除指定位置的元素 2. **单链表**: - 建立单链表(头插法或尾插法) - 删除指定结点(按值或按位置) --- ### 代码概述 本题属于“代码型”问题,需用C语言实现线性表的两种存储结构:**顺序表**和**单链表**的基本操作。代码包括: - 顺序表的数组实现,支持插入、删除; - 单链表的动态结点创建与删除; - 主函数中调用测试。 --- ### 代码实现(注释) ```c #include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 #define OK 1 #define ERROR 0 // 顺序表结构定义 typedef struct { int data[MAXSIZE]; int length; } SeqList; // 初始化顺序表 void InitSeqList(SeqList *L) { L->length = 0; } // 顺序表插入:在第i个位置插入x(i从1开始) int SeqListInsert(SeqList *L, int i, int x) { if (L->length >= MAXSIZE) return ERROR; // 表满 if (i < 1 || i > L->length + 1) return ERROR; // 位置非法 for (int j = L->length; j >= i; j--) { L->data[j] = L->data[j - 1]; // 后移 } L->data[i - 1] = x; L->length++; return OK; } // 顺序表删除:删除第i个元素,通过x返回其值 int SeqListDelete(SeqList *L, int i, int *x) { if (L->length == 0) return ERROR; if (i < 1 || i > L->length) return ERROR; *x = L->data[i - 1]; for (int j = i; j < L->length; j++) { L->data[j - 1] = L->data[j]; // 前移 } L->length--; return OK; } // 打印顺序表 void PrintSeqList(SeqList *L) { for (int i = 0; i < L->length; i++) { printf("%d ", L->data[i]); } printf("\n"); } // 单链表结点定义 typedef struct LNode { int data; struct LNode *next; } LNode, *LinkList; // 初始化单链表头结点) void InitLinkList(LinkList *L) { *L = (LinkList)malloc(sizeof(LNode)); (*L)->next = NULL; } // 头插法建立单链表(输入-1结束) void CreateLinkList_H(LinkList L) { int x; printf("输入数值建立链表(-1结束):"); while (1) { scanf("%d", &x); if (x == -1) break; LNode *s = (LNode *)malloc(sizeof(LNode)); s->data = x; s->next = L->next; L->next = s; } } // 删除链表中第一个值为x的结点 int DeleteLinkList(LinkList L, int x) { LNode *p = L->next, *pre = L; while (p && p->data != x) { pre = p; p = p->next; } if (!p) return ERROR; // 未找到 pre->next = p->next; free(p); return OK; } // 打印单链表 void PrintLinkList(LinkList L) { LNode *p = L->next; while (p) { printf("%d ", p->data); p = p->next; } printf("\n"); } // 释放链表内存 void DestroyLinkList(LinkList L) { LNode *p = L, *q; while (p) { q = p; p = p->next; free(q); } } // 主函数测试 int main() { // 测试顺序表 SeqList L1; InitSeqList(&L1); SeqListInsert(&L1, 1, 10); SeqListInsert(&L1, 2, 20); SeqListInsert(&L1, 3, 30); printf("顺序表内容:"); PrintSeqList(&L1); int deleted; if (SeqListDelete(&L1, 2, &deleted)) { printf("删除第2个元素:%d\n", deleted); } printf("删除后顺序表:"); PrintSeqList(&L1); // 测试单链表 LinkList L2; InitLinkList(&L2); CreateLinkList_H(L2); printf("单链表内容:"); PrintLinkList(L2); int x = 20; if (DeleteLinkList(L2, x)) { printf("删除值为 %d 的结点\n", x); } else { printf("未找到值为 %d 的结点\n", x); } printf("删除后单链表:"); PrintLinkList(L2); DestroyLinkList(L2); return 0; } ``` --- ### 代码解析 1. **顺序表部分**: - 使用静态数组实现,`length` 记录当前长度; - 插入时需从后往前移动元素,删除则从前往后覆盖; - 时间复杂度:插入/删除为 $O(n)$,空间复杂度 $O(1)$。 2. **单链表部分**: - 使用头结点的链表,便于统一操作; - 头插法建表:新结点总插入在头结点之后; - 删除操作需遍历查找目标值,并调整指针后释放内存。 3. **内存管理**: - 动态分配使用 `malloc`,删除结点用 `free` 防止泄漏; - 程序结束前调用 `DestroyLinkList` 释放全部内存。 --- ### 知识点(列出该代码中遇到的知识点) - **顺序表的插入与删除**:通过数组元素移动实现,注意边界判断和位置合法性。 - **单链表的头插法建表**:新结点插入头结点后,形成逆序链表,时间复杂度为 $O(n)$。 - **链表结点的删除**:需找到前驱结点,修改指针并释放内存,防止内存泄漏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值