顺序表代码实现
一、动态分配方式实现的所有功能
dynamic_list.c
#include "dynamic_list.h"
// 初始化顺序表(考研重点操作)
bool InitList(DynamicList *L) {
// 分配初始容量内存
L->data = (int *)malloc(INIT_SIZE * sizeof(int));
if (L->data == NULL) return false; // 内存分配失败
L->length = 0; // 初始长度为0
L->capacity = INIT_SIZE; // 初始容量
return true;
}
// 插入操作(核心算法,考研常考边界条件)
bool ListInsert(DynamicList *L, int i, int e) {
// 1. 检查位序合法性(i范围:1~length+1)
if (i < 1 || i > L->length + 1) return false;
// 2. 检查是否需要扩容
if (L->length >= L->capacity) {
// 重新分配更大的内存(考研要求掌握realloc使用)
int *new_data = (int *)realloc(L->data, (L->capacity + INCREMENT) * sizeof(int));
if (new_data == NULL) return false; // 扩容失败
L->data = new_data; // 更新基址指针
L->capacity += INCREMENT; // 更新容量
}
// 3. 移动元素(从后往前移,避免覆盖)
for (int j = L->length; j >= i; j--) {
L->data[j] = L->data[j-1];
}
// 4. 插入元素,更新长度
L->data[i-1] = e; // 位序i对应数组下标i-1
L->length++;
return true;
}
// 删除操作(考研重点,需返回被删除值)
bool ListDelete(DynamicList *L, int i, int *e) {
// 1. 检查位序合法性(i范围:1~length)
if (i < 1 || i > L->length) return false;
// 2. 保存被删除元素
*e = L->data[i-1];
// 3. 移动元素(从前往后移)
for (int j = i; j < L->length; j++) {
L->data[j-1] = L->data[j];
}
// 4. 更新长度
L->length--;
return true;
}
// 按位查找(随机访问,时间复杂度O(1),顺序表优势)
int GetElem(DynamicList L, int i) {
if (i < 1 || i > L->length) return -1; // 位序非法(假设元素为正整数)
return L->data[i-1]; // 位序i对应下标i-1
}
// 按值查找(顺序查找,时间复杂度O(n))
int LocateElem(DynamicList L, int e) {
for (int i = 0; i < L->length; i++) {
if (L->data[i] == e) {
return i + 1; // 数组下标转位序(+1)
}
}
return 0; // 未找到
}
// 遍历输出所有元素
void PrintList(DynamicList L) {
for (int i = 0; i < L->length; i++) {
printf("%d ", L->data[i]);
}
printf("\n");
}
// 销毁顺序表(释放动态内存)
void DestroyList(DynamicList *L) {
free(L->data); // 释放存储区
L->data = NULL; // 防止野指针
L->length = 0;
L->capacity = 0;
}
dynamic_list.h
#ifndef DYNAMIC_LIST_H
#define DYNAMIC_LIST_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> // 使用bool类型需要包含此头文件
#define INIT_SIZE 10 // 初始容量
#define INCREMENT 5 // 扩容增量(考研常用倍增或固定增量,此处用固定增量示例)
// 动态顺序表结构体定义(考研标准写法)
typedef struct {
int *data; // 动态分配的存储基址
int length; // 当前长度(已用元素个数)
int capacity; // 总容量(最大可存储元素个数)
} DynamicList;
// 初始化顺序表
bool InitList(DynamicList *L);
// 插入元素(位序i,从1开始)
bool ListInsert(DynamicList *L, int i, int e);
// 删除元素(位序i,返回被删除元素)
bool ListDelete(DynamicList *L, int i, int *e);
// 按位查找(返回第i个元素)
int GetElem(DynamicList *L, int i);
// 按值查找(返回第一个等于e的位序,不存在返回0)
int LocateElem(DynamicList *L, int e);
// 遍历输出所有元素
void PrintList(DynamicList L);
// 销毁顺序表
void DestroyList(DynamicList *L);
#endif
relloc函数
realloc
是 C 语言标准库中用于重新调整已分配内存块大小的函数,主要用于动态内存管理(头文件 <stdlib.h>
)。
void* realloc(void* ptr, size_t new_size);
ptr
:指向待调整大小的原内存块的指针(若为 NULL
,效果等价于 malloc(new_size)
)。
new_size
:调整后的新内存块大小(单位:字节)。若 new_size
为 0,效果等价于 free(ptr)
(此时返回值通常为 NULL
)。
#include <stdio.h>
#include <stdlib.h>
int main() {
// 初始分配 4 字节(存 int)
int* arr = malloc(4 * sizeof(int));
if (!arr) { /* 处理分配失败 */ }
// 重新分配为 8 字节(扩展存 8 个 int)
int* new_arr = realloc(arr, 8 * sizeof(int));
if (!new_arr) {
free(arr); // realloc 失败时,原 arr 仍有效,需手动释放
return -1;
}
// 此时 arr 可能已被释放,使用 new_arr
arr = new_arr;
// 使用扩展后的内存...
free(arr); // 最终释放调整后的内存
return 0;
}
main.c
#include "dynamic_list.h"
int main() {
DynamicList L;
// 初始化测试
if (InitList(&L)) {
printf("顺序表初始化成功!初始容量:%d\n", L.capacity);
} else {
printf("顺序表初始化失败!\n");
return 1;
}
// 插入测试(插入10个元素触发扩容)
printf("\n=== 插入测试 ===\n");
for (int i = 1; i <= INIT_SIZE + 2; i++) { // 插入12个元素(超过初始容量10)
if (ListInsert(&L, i, i*10)) {
printf("插入位序%d,值%d成功!当前长度:%d\n", i, i*10, L.length);
} else {
printf("插入位序%d失败!\n", i);
}
}
printf("插入后顺序表内容:");
PrintList(L);
printf("当前容量:%d\n", L.capacity); // 应输出15(初始10+增量5)
// 按位查找测试
printf("\n=== 按位查找测试 ===\n");
int pos = 5;
int elem = GetElem(L, pos);
printf("第%d个元素的值是:%d\n", pos, elem);
// 按值查找测试
printf("\n=== 按值查找测试 ===\n");
int target = 70;
int found_pos = LocateElem(L, target);
if (found_pos) {
printf("值%d出现在位序%d\n", target, found_pos);
} else {
printf("值%d未找到\n", target);
}
// 删除测试
printf("\n=== 删除测试 ===\n");
int del_pos = 3;
int del_elem;
if (ListDelete(&L, del_pos, &del_elem)) {
printf("删除位序%d成功!被删除值:%d\n", del_pos, del_elem);
printf("删除后顺序表内容:");
PrintList(L);
printf("当前长度:%d\n", L.length);
} else {
printf("删除位序%d失败!\n", del_pos);
}
// 销毁测试
DestroyList(&L);
printf("\n顺序表已销毁!\n");
return 0;
}
代码说明(关键点):
- 结构体定义:使用
data
指针、length
(当前长度)、capacity
(总容量)三要素,与教材完全一致。 - 初始化操作:显式分配初始内存,处理内存分配失败的情况(考研要求考虑鲁棒性)。
- 插入操作:
- 检查位序合法性(
1 ≤ i ≤ length+1
) - 动态扩容使用
realloc
(考研重点函数),扩容策略为固定增量(符合教材示例) - 元素后移方向正确(从后往前避免覆盖)
- 检查位序合法性(
- 删除操作:
- 检查位序合法性(
1 ≤ i ≤ length
) - 保存被删除元素值(符合考研 “返回被删元素” 的要求)
- 元素前移方向正确(从前往后避免覆盖)
- 检查位序合法性(
- 查找操作:
- 按位查找时间复杂度 O (1)(体现顺序表随机访问优势)
- 按值查找时间复杂度 O (n)(顺序查找的标准实现)
- 内存管理:包含
DestroyList
函数释放动态内存,防止内存泄漏(考研隐含要求)。
测试代码验证场景:
- 初始容量测试(插入超过初始容量时触发扩容)
- 边界插入(头部 / 尾部插入)
- 非法位序处理(自动过滤无效位置)
- 动态扩容验证(容量从 10 变为 15)
- 删除后元素前移验证
- 内存释放验证(避免野指针)
二、静态分配方式实现的所有功能
static_list.c
#include "static_list.h"
// 初始化顺序表(静态分配无需动态内存,直接置长度为0)
bool InitList(StaticList *L) {
L->length = 0; // 初始长度为0(数组空间已静态分配)
return true; // 静态分配不会失败(区别于动态分配)
}
// 插入操作(核心算法,需处理容量已满的情况)
bool ListInsert(StaticList *L, int i, int e) {
// 1. 检查位序合法性(i范围:1~length+1)
if (i < 1 || i > L->length + 1) return false;
// 2. 检查是否已满(静态分配核心限制)
if (L->length >= MAX_SIZE) {
printf("错误:顺序表已满,无法插入!\n");
return false;
}
// 3. 移动元素(从后往前移,避免覆盖)
for (int j = L->length; j >= i; j--) {
L->data[j] = L->data[j-1];
}
// 4. 插入元素,更新长度
L->data[i-1] = e; // 位序i对应数组下标i-1
L->length++;
return true;
}
// 删除操作(考研重点,需返回被删除值)
bool ListDelete(StaticList *L, int i, int *e) {
// 1. 检查位序合法性(i范围:1~length)
if (i < 1 || i > L->length) return false;
// 2. 保存被删除元素
*e = L->data[i-1];
// 3. 移动元素(从前往后移)
for (int j = i; j < L->length; j++) {
L->data[j-1] = L->data[j];
}
// 4. 更新长度
L->length--;
return true;
}
// 按位查找(随机访问,时间复杂度O(1),顺序表优势)
int GetElem(StaticList L, int i) {
if (i < 1 || i > L->length) return -1; // 位序非法(假设元素为正整数)
return L->data[i-1]; // 位序i对应下标i-1
}
// 按值查找(顺序查找,时间复杂度O(n))
int LocateElem(StaticList L, int e) {
for (int j = 0; j < L->length; j++) {
if (L->data[j] == e) {
return j + 1; // 数组下标转位序(+1)
}
}
return 0; // 未找到
}
// 遍历输出所有元素
void PrintList(StaticList L) {
for (int j = 0; j < L->length; j++) {
printf("%d ", L->data[j]);
}
printf("\n");
}
static_list.h
#ifndef STATIC_LIST_H
#define STATIC_LIST_H
#include <stdio.h>
#include <stdbool.h> // 使用bool类型需要包含此头文件
#define MAX_SIZE 10 // 静态分配的最大容量(考研常用宏定义方式)
// 静态顺序表结构体定义(考研标准写法)
typedef struct {
int data[MAX_SIZE]; // 静态分配的存储数组(固定大小)
int length; // 当前长度(已用元素个数)
} StaticList;
// 初始化顺序表
bool InitList(StaticList *L);
// 插入元素(位序i,从1开始)
bool ListInsert(StaticList *L, int i, int e);
// 删除元素(位序i,返回被删除元素)
bool ListDelete(StaticList *L, int i, int *e);
// 按位查找(返回第i个元素)
int GetElem(StaticList L, int i);
// 按值查找(返回第一个等于e的位序,不存在返回0)
int LocateElem(StaticList L, int e);
// 遍历输出所有元素
void PrintList(StaticList L);
#endif
main.c
#include "static_list.h"
int main() {
StaticList L;
// 初始化测试
if (InitList(&L)) {
printf("顺序表初始化成功!最大容量:%d\n", MAX_SIZE);
} else {
printf("顺序表初始化失败!\n");
return 1;
}
// 插入测试(插入到最大容量验证)
printf("\n=== 插入测试 ===\n");
for (int i = 1; i <= MAX_SIZE + 2; i++) { // 尝试插入12个元素(超过最大容量10)
if (ListInsert(&L, i, i*10)) {
printf("插入位序%d,值%d成功!当前长度:%d\n", i, i*10, L.length);
} else {
printf("插入位序%d失败!\n", i);
}
}
printf("最终顺序表内容:");
PrintList(L);
// 按位查找测试
printf("\n=== 按位查找测试 ===\n");
int pos = 5;
int elem = GetElem(L, pos);
printf("第%d个元素的值是:%d\n", pos, elem);
// 按值查找测试
printf("\n=== 按值查找测试 ===\n");
int target = 70;
int found_pos = LocateElem(L, target);
if (found_pos) {
printf("值%d出现在位序%d\n", target, found_pos);
} else {
printf("值%d未找到\n", target);
}
// 删除测试(删除中间元素验证)
printf("\n=== 删除测试 ===\n");
int del_pos = 3;
int del_elem;
if (ListDelete(&L, del_pos, &del_elem)) {
printf("删除位序%d成功!被删除值:%d\n", del_pos, del_elem);
printf("删除后顺序表内容:");
PrintList(L);
printf("当前长度:%d\n", L->length);
} else {
printf("删除位序%d失败!\n", del_pos);
}
// 测试满删除(删除最后一个元素)
printf("\n=== 满删除测试 ===\n");
while (L.length > 0) {
int temp;
ListDelete(&L, L.length, &temp);
printf("删除最后一个元素%d,当前长度:%d\n", temp, L.length);
}
return 0;
}
代码说明(关键点):
- 结构体定义:使用
data[MAX_SIZE]
静态数组和length
(当前长度)两要素,与教材《数据结构》(严蔚敏版)完全一致。 - 初始化操作:无需动态内存分配,直接将
length
置 0,体现静态分配 “空间预分配” 的特点。 - 插入操作:
- 检查位序合法性(
1 ≤ i ≤ length+1
) - 核心限制:当
length == MAX_SIZE
时无法插入(静态分配的根本约束,考研常考此边界条件) - 元素后移方向正确(从后往前避免覆盖)
- 检查位序合法性(
- 删除操作:
- 检查位序合法性(
1 ≤ i ≤ length
) - 保存被删除元素值(符合考研 “返回被删元素” 的要求)
- 元素前移方向正确(从前往后避免覆盖)
- 检查位序合法性(
- 查找操作:
- 按位查找时间复杂度 O (1)(体现顺序表随机访问优势)
- 按值查找时间复杂度 O (n)(顺序查找的标准实现)
- 内存特性:无需显式销毁(静态数组由系统自动回收),区别于动态分配版本。
测试代码验证场景:
- 容量限制测试(插入超过
MAX_SIZE
时失败) - 边界插入(头部 / 尾部插入)
- 非法位序处理(自动过滤无效位置)
- 满容量插入失败验证(第 11、12 次插入失败)
- 删除后元素前移验证(删除中间元素后后续元素前移)
- 空表 / 满表边界操作(删除至空表的过程验证)
本网站原创文章版权归何大锤的狂飙日记所有。发布者:何大锤,转转请注明出处:何大锤的博客