当前位置: 首页 > news >正文

C语言数据结构:动态顺序表实现与应用

顺序表

  1. 顺序表核心逻辑
    • 顺序表是基于数组实现的线性表,通过 ArrayList 结构体存储数据(data 指针)、容量(capacity)和最后一个元素的索引(last)。核心特点是支持动态扩容(满容量时自动翻倍),并通过索引快速访问元素。
    • 数据结构
typedef struct {int capacity;  // 顺序表容量int lastIndex; // 最后一个元素的索引(-1表示为空)int* data;     // 存储数据的数组指针
} Arra
  1. 初始化(initList
    • 校验容量合法性(必须 > 0)。
    • 分配结构体和数据数组的内存,初始化 last = -1(表示空表)。
    • 若内存分配失败,释放已分配的空间以避免泄漏。
/*** @brief 初始化顺序表(创建顺序表)* @param capacity 顺序表的初始容量(必须大于0)* @return 成功返回顺序表指针;失败返回NULL*/
ArrayList* initList(int capacity) {// 容量合法性校验if (capacity <= 0) {return NULL;}// 分配顺序表结构体内存ArrayList* list = malloc(sizeof(ArrayList));if (list != NULL) {list->last = -1; // 初始状态:顺序表为空(无元素)// 分配数据存储数组的内存(初始化为0)list->data = calloc(capacity, sizeof(int));if (list->data == NULL) {// 数组内存分配失败时,释放结构体以避免内存泄漏free(list);return NULL;}list->capacity = capacity; // 设置初始容量return list;}return NULL; // 结构体内存分配失败
}
  1. 插入元素(insertList
    • 采用头部插入:先将现有元素后移一位,再将新元素放入索引0的位置。
    • 自动扩容:当表满时调用 expandList 进行二倍扩容(使用 realloc 保留原有数据)。
/*** @brief 向顺序表头部插入元素(前插法)* @param list 顺序表指针* @param data 待插入的元素值* @return 插入成功返回true;失败(如指针为空或扩容失败)返回false*/
bool insertList(ArrayList* list, int data) {// 指针合法性校验if (list == NULL) {return false;}// 若顺序表已满,尝试扩容if (isFull(list) && !expandList(list)) {return false; // 扩容失败,插入失败}// 元素后移:为头部插入腾出位置(从最后一个元素开始移)for (int i = list->last; i >= 0; i--) {list->data[i + 1] = list->data[i];}// 插入新元素到头部(索引0的位置)list->data[0] = data;list->last++; // 更新最后一个元素的索引return true;
}
  1. 查找元素(findElement)
    • 从顺序表中查找元素, 如果找到元素,则返回
/*** @brief 查找元素在顺序表中的索引* @param list 顺序表指针* @param data 待查找元素* @return 找到返回对应索引,未找到返回-1*/
int findElement(ArrayList* list, int data) {if (list == NULL || isEmpty(list)) {return -1;}for (int i = 0; i <= list->lastIndex; i++) {if (list->data[i] == data) {return i;}}return -1;
}
  1. 删除元素(removeElement
    • 先通过 findElement 查找元素索引。
    • 若存在,将索引后的元素前移一位,覆盖待删除元素,最后更新 last 索引。
/** @brief 从顺序表中删除指定元素* @param list 顺序表指针* @param data 待删除元素*/
void removeElement(ArrayList* list, int data) {if (list == NULL || isEmpty(list)) {return;}// 查找元素索引int index = findElement(list, data);printf("元素%d在顺序表中的索引为%d\n", data, index);// 若找到则删除if (index != -1) {// 元素前移覆盖待删除元素for (int i = index; i < list->lastIndex; i++) {list->data[i] = list->data[i + 1];}list->lastIndex--;  // 更新最后一个元素索引}
}
  1. 辅助函数
    • isFull/isEmpty:判断表的状态(满/空)。
    • expandList:动态扩容(核心是 realloc 函数的使用)。
    • showList:遍历打印元素,方便调试和查看表内容。
/*** @brief 判断顺序表是否已满* @param list 顺序表指针* @return 已满返回true,否则返回false*/
static bool isFull(ArrayList* list) {if (list == NULL) return true;// 最后一个元素索引等于容量-1时表示已满return list->lastIndex == list->capacity - 1;
}/*** @brief 对顺序表进行二倍扩容* @param list 顺序表指针* @return 扩容成功返回true,失败返回false*/
static bool expandArrayList(ArrayList* list) {if (list == NULL) return false;// 计算新容量(原容量的2倍)int newCapacity = list->capacity * 2;// 重新分配内存int* newData = realloc(list->data, sizeof(int) * newCapacity);if (newData == NULL) {return false;}// 更新数据指针和容量list->data = newData;// 初始化新增的内存空间memset(&list->data[list->capacity], 0, sizeof(int) * (newCapacity - list->capacity));list->capacity = newCapacity;return true;
}/*** @brief 判断顺序表是否为空* @param list 顺序表指针* @return 为空返回true,否则返回false*/
static bool isEmpty(ArrayList* list) {return list->lastIndex == -1;
}
  1. 销毁顺序表

** 内存释放步骤 **:
先释放data指向的数组内存(因为数组是动态分配的)
再释放ArrayList结构体本身的内存
最后将外部传入的指针置空(关键:防止后续误用已释放的内存)
函数说明

// 销毁顺序表
destroy_list(&list);
if (list == NULL) {printf("顺序表已成功销毁\n");
}

为什么使用双重指针

因为需要在函数内部将外部的ArrayList*指针置空(避免野指针),单指针无法修改外部指针的指向,所以必须使用ArrayList。

完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>// 顺序表结构体定义
typedef struct 
{int capacity;  // 顺序表容量int last;      // 最后一个元素的索引(-1表示空表)int *data;     // 存储数据的动态数组
} ArrayList;// 静态辅助函数声明
static bool isFull(ArrayList *list);
static bool expend_list(ArrayList *list);
static bool isEmpty(ArrayList *list);// 函数声明
ArrayList *init_list(int capacity);
bool insert_list(ArrayList *list, int data);
void show(ArrayList *list);
int find_e(ArrayList *list, int data);
void remove_element(ArrayList *list, int data);
void destroy_list(ArrayList **list);/*** @brief 判断顺序表是否已满* @param list 顺序表指针* @return 已满返回true,否则返回false*/
static bool isFull(ArrayList *list)
{if (list == NULL) return true;return list->last == list->capacity - 1;
}/*** @brief 对顺序表进行二倍扩容* @param list 顺序表指针* @return 扩容成功返回true,失败返回false*/
static bool expend_list(ArrayList *list)
{if (list == NULL) return false;int new_len = list->capacity * 2;int *new_int = realloc(list->data, sizeof(int) * new_len);if (new_int == NULL)return false;        list->data = new_int;memset(&list->data[list->capacity], 0, sizeof(int) * (new_len - list->capacity));list->capacity = new_len;return true;
}/*** @brief 判断顺序表是否为空* @param list 顺序表指针* @return 为空返回true,否则返回false*/
static bool isEmpty(ArrayList *list)
{return list->last == -1;
}/*** @brief 初始化顺序表* @param capacity 初始容量* @return 成功返回顺序表指针,失败返回NULL*/
ArrayList *init_list(int capacity)
{if (capacity <= 0)return NULL;ArrayList *list = malloc(sizeof(ArrayList));if (list != NULL){list->last = -1;list->data = calloc(capacity, sizeof(int));if (list->data == NULL){free(list);return NULL;}list->capacity = capacity;return list;}return NULL;
}/*** @brief 向前插法插入元素* @param list 顺序表指针* @param data 待插入元素* @return 插入成功返回true,失败返回false*/
bool insert_list(ArrayList *list, int data)
{if (list == NULL) return false;if (isFull(list) && !expend_list(list))return false;// 元素后移,为新元素腾出位置for (int i = list->last; i >= 0; i--){list->data[i + 1] = list->data[i];}list->data[0] = data;list->last++;return true;
}/*** @brief 遍历并打印顺序表元素* @param list 顺序表指针*/
void show(ArrayList *list)
{if (!list || isEmpty(list)){perror("顺序表为空!");return;}printf("顺序表中的元素:\n");for (int i = 0; i <= list->last; i++){printf("%-4d ", list->data[i]);}printf("\n");
}/*** @brief 查找元素位置* @param list 顺序表指针* @param data 待查找元素* @return 找到返回索引,未找到返回-1*/
int find_e(ArrayList *list, int data)
{for (int i = 0; i <= list->last; i++){if (list->data[i] == data)return i;}return -1;
}/*** @brief 删除指定元素* @param list 顺序表指针* @param data 待删除元素*/
void remove_element(ArrayList *list, int data)
{if (list == NULL)return;int index = find_e(list, data);printf("该元素%d在序列中的索引为%d\n", data, index);if (index != -1){// 元素前移覆盖待删除元素for (int i = index; i < list->last; i++){list->data[i] = list->data[i + 1];}list->last--;}
}/*** @brief 销毁顺序表,释放所有内存* @param list 顺序表指针的指针*/
void destroy_list(ArrayList **list)
{if (list == NULL || *list == NULL)return;// 先释放数据数组free((*list)->data);(*list)->data = NULL;// 再释放顺序表结构体free(*list);*list = NULL;  // 将外部指针置空,避免野指针
}/*** @brief 主函数:测试顺序表功能*/
int main(int argc, char *argv[])
{// 初始化顺序表,初始容量为6ArrayList *list = init_list(6);if (list == NULL){printf("顺序表初始化失败\n");return 1;}printf("初始化顺序表的容量为%d\n", list->capacity);// 插入9个元素(测试扩容功能)for (int i = 0; i <= 8; i++){int val = i * 2;if (insert_list(list, val)){printf("插入%d成功, 当前容量为%d\n", val, list->capacity);}else{printf("插入%d失败, 当前容量为%d\n", val, list->capacity);}}// 显示插入结果printf("遍历顺序表:\n");show(list);// 删除元素16remove_element(list, 16);// 显示删除后结果printf("删除元素后:\n");show(list);// 销毁顺序表destroy_list(&list);if (list == NULL){printf("顺序表已成功销毁\n");}return 0;
}
http://www.dtcms.com/a/342457.html

相关文章:

  • 如何使用Prometheus + Grafana + Loki构建一个现代化的云原生监控系统
  • 数字社会学是干什么的?数字社会学理论与数字社会学家唐兴通讲数字社会学书籍有哪些?AI社会学人工智能社会学理论框架
  • 4090服务器无法sudo apt update 问题解决
  • 告别服务器!Amazon Lambda无服务开发实战指南
  • CI/CD 学习之路
  • 佰钧成 社招 一面
  • Cesium 实战 27 - 自定义纹理材质 - 立体墙(渐变色)
  • 【数据结构入门】排序算法:插入排序
  • C和C++的区别?
  • 水深水温测量仪:水域监测的“智慧双眸”
  • Linux学习:信号的概念与产生方式
  • 03 安装【动手学深度学习v2】
  • CAN高速通信(含简单程序实战)
  • 解决远程桌面连接“为安全考虑,已锁定该用户帐户,原因是登录尝试或密码更改尝试过多”问题
  • idea将服务封装为一个jar包
  • RabbitMQ如何确保消息发送和消息接收
  • 无监督学习(聚类 异常检测)
  • 数据大屏全链路质量保障测试
  • Eino 框架组件协作指南 - 智能图书馆建设手册
  • java基础(十三)消息队列
  • 【Springboot进阶】Java切面编程对性能的影响深度分析
  • K8s概念之进程、容器与 Pod 的终极指南
  • 第二阶段Winform-3:常用控件介绍2
  • 算法题(187):程序自动分析
  • k8s集群限制不同用户操作
  • Windows 笔记本实现仅关屏仍工作:一种更便捷的 “伪熄屏” 方案
  • 基于Spring Cloud Gateway动态路由与灰度发布方案对比与实践指导
  • 哈希表知识总结
  • 风吸式杀虫灯在果园的作用
  • python的校园研招网系统