一、思路分块解析
1. 头文件和数据结构定义
typedef struct {
int *elements; // 存储元素的数组,使用动态分配的内存存放数据
int capacity; // 数组的总容量,即当前能存储的最大元素数
int size; // 当前数组中实际存储的元素个数
} ConsequenceList;
- 数据结构
ConsequenceList
这是一个顺序表(类似动态数组)的实现:elements
:指向存放整型数据的动态内存区域。capacity
:当前内存分配的容量,用于判断是否需要扩容。size
:实际存储的元素数量,用于插入、删除和查找操作时作为有效数据的范围。
2. 顺序表的创建与销毁
2.1 创建顺序表
void Creat_ConsequenceList(ConsequenceList * list, int capacity)
{
list->elements = (int *)malloc(sizeof(int) * capacity);
list->capacity = capacity;
list->size = 0;
}
- 功能说明
- 动态分配一个大小为
capacity
的整型数组,用于存储数据。 - 将
capacity
保存到结构体中,并初始化当前元素个数size
为 0。
- 动态分配一个大小为
2.2 销毁顺序表
void Destory_ConsequenceList(ConsequenceList* list)
{
if (list->elements)
{
free(list->elements);
list->elements = NULL;
}
}
- 功能说明
- 释放动态分配的内存,并将指针置为
NULL
,避免悬空指针问题。
- 释放动态分配的内存,并将指针置为
3. 顺序表的基本操作
3.1 获取顺序表的大小
int GetSize_ConsequenceList(ConsequenceList * list)
{
return list->size;
}
- 功能说明
- 返回当前顺序表中实际存储的元素个数。
3.2 插入元素
void Add_ConsequenceList(ConsequenceList* list, int index, int element)
{
if (index < 0 || index > list->capacity) // 检查下标是否合法
{
printf("不合法的下标索求");
return;
}
if (index == list->capacity) // 如果下标等于容量,说明需要扩容
{
int *New_elements = realloc(list->elements, sizeof(int) * list->capacity * 2); // 扩容为原来的两倍
list->elements = New_elements;
list->capacity *= 2;
}
// 将下标 index 之后的元素向后移动,为新元素腾出空间
for (int i = list->size; i > index; i--)
{
list->elements[i] = list->elements[i - 1];
}
list->elements[index] = element; // 在指定位置插入新元素
list->size++;
}
- 功能说明
- 下标检查
- 判断插入位置是否合法,若
index < 0
或大于capacity
则认为不合法。
- 判断插入位置是否合法,若
- 扩容操作
- 如果插入位置等于当前容量(表明数组已满或达到预设容量边界),使用
realloc
将内存扩大为原来的两倍,并更新capacity
。
- 如果插入位置等于当前容量(表明数组已满或达到预设容量边界),使用
- 数据移动
- 从尾部开始,将元素逐个后移一位,为新元素腾出空位。
- 插入元素
- 将新元素放到指定位置,并将
size
增加 1。
- 将新元素放到指定位置,并将
- 下标检查
注意:
代码中判断扩容的条件是if (index == list->capacity)
,这要求插入的下标必须与当前容量相等才触发扩容,而通常插入操作应判断是否达到size
(已存元素个数)是否与capacity
相等。此处逻辑有一定局限性,实际使用时需注意下标的合理性和扩容的条件。
3.3 删除元素
void Delete_ConsequenceList(ConsequenceList* list, int index)
{
if (index < 0 || index >= list->size) // 判断下标是否合法
{
printf("不合法的下标索求");
return;
}
// 将 index 后面的所有元素前移覆盖删除的元素
for (int i = index; i < list->size; i++)
{
list->elements[i] = list->elements[i + 1];
}
list->size--;
}
- 功能说明
- 下标检查
- 确保待删除位置在有效范围内(
0
到size-1
)。
- 确保待删除位置在有效范围内(
- 数据移动
- 从删除位置开始,将后面的元素前移覆盖删除元素,保持数组连续性。
- 更新大小
- 删除元素后,将
size
减 1。
- 删除元素后,将
- 下标检查
3.4 修改元素
void Change_ConsequenceList(ConsequenceList* list, int index, int element)
{
if (index < 0 || index >= list->size) // 判断下标是否合法
{
printf("不合法的下标索求");
return;
}
list->elements[index] = element;
}
- 功能说明
- 根据指定下标修改元素的值,前提是下标在合法范围内。
3.5 查找元素
void Find_ConsequenceList(ConsequenceList* list, int element)
{
int index; // 用来存储找到的下标
for (int i = 0; i < list->size; i++)
{
if (element == list->elements[i]) // 如果找到了对应的元素
{
index = i;
printf("第%d的值为%d\n", index, list->elements[index]);
return;
}
}
printf("找不到对应的元素\n");
}
- 功能说明
- 依次遍历数组,若找到与目标值相同的元素则打印其下标和值,并结束函数。
- 如果遍历完成后没有找到,则输出提示信息。
4. 主函数 main
int main()
{
ConsequenceList list;
Creat_ConsequenceList(&list, 1);
for (int i = 0; i <10; i++)
{
Add_ConsequenceList(&list, i, i * 10);
printf("%d %d\n", i, list.elements[i]);
}
printf("Size:%d\n", list.size);
Find_ConsequenceList(&list, 50);
Change_ConsequenceList(&list, 4, 80);
Delete_ConsequenceList(&list, 8);
for (int i = 0; i < list.size; i++)
{
printf("%d %d\n", i, list.elements[i]);
}
system("pause");
return 0;
}
4.1 初始化与插入元素
-
初始化顺序表
- 调用
Creat_ConsequenceList
创建一个初始容量为1
的顺序表。- 初始容量设为 1,但在插入时会自动扩容。
- 调用
-
循环插入元素
- 循环 10 次,每次调用
Add_ConsequenceList(&list, i, i * 10)
- 插入位置为当前索引
i
,插入的值为i*10
(例如:0, 10, 20, …)。
- 插入位置为当前索引
- 每次插入后打印当前插入的索引和对应的值。
- 循环 10 次,每次调用
4.2 展示顺序表的大小
- 打印
list.size
,显示当前存储的元素数量。
4.3 查找、修改和删除操作
-
查找操作
- 调用
Find_ConsequenceList(&list, 50)
,在数组中查找值为 50 的元素并打印其下标和值。
- 调用
-
修改操作
- 调用
Change_ConsequenceList(&list, 4, 80)
,将下标 4 的元素修改为 80。
- 调用
-
删除操作
- 调用
Delete_ConsequenceList(&list, 8)
,删除下标 8 处的元素,随后数组中后面的元素会自动前移。
- 调用
4.4 打印最终的数组内容
- 遍历顺序表,打印每个下标及对应的元素值,展示修改与删除后的结果。
4.5 退出程序前的暂停
- 调用
system("pause")
,使程序在结束前暂停,方便在 Windows 系统上观察控制台输出。
总结
这段代码实现了一个简单的顺序表(动态数组)的基本操作,包括创建、扩容、插入、删除、修改和查找。主要特点如下:
-
动态内存分配与扩容:
利用malloc
和realloc
动态分配内存,并在需要时扩充容量。 -
数据移动:
插入和删除操作时需要将数组中数据移动,以保持元素的连续性。 -
错误处理:
通过下标合法性检查防止数组越界,但在扩容条件判断上存在一定局限(实际应用中可能需要根据size
而非capacity
判断是否扩容)。
二、完整代码实现
#include<stdio.h>
#include<stdlib.h>
typedef struct {
int *elements; //元素数组
int capacity; //总的容量大小
int size; //元素总数
}ConsequenceList;
void Creat_ConsequenceList(ConsequenceList * list,int capacity)
//创建一个容量capacity固定的顺序表
{
list->elements = (int *)malloc(sizeof(int) * capacity);
list->capacity = capacity;
list->size = 0;
}
void Destory_ConsequenceList(ConsequenceList* list)
//删除顺序表
{
if (list->elements)
{
free(list->elements);
list->elements = NULL;
}
}
int GetSize_ConsequenceList(ConsequenceList * list)
//获取元素的个数
{
return list->size;
}
//增加元素
void Add_ConsequenceList(ConsequenceList* list,int index,int element)
{
if (index < 0 || index > list->capacity) //下标不合法
{
printf("不合法的下标索求");
return;
}
if (index == list->capacity) //表明此时需要扩容
{
int *New_elements=realloc(list->elements, sizeof(int) * list->capacity * 2);//扩容一倍
list->elements = New_elements;
list->capacity *= 2;
}
for (int i = list->size; i > index; i--) //数组整体往后挪
{
list->elements[i] = list->elements[i - 1];
}
list->elements[index] = element;//修改对应下标的值
list->size++;
}
//删除元素
void Delete_ConsequenceList(ConsequenceList* list, int index)
{
if (index < 0 || index >= list->size) //下标不合法
{
printf("不合法的下标索求");
return;
}
for (int i = index; i < list->size; i++)
{
list->elements[i] = list->elements[i + 1];//整体往前覆盖
}
list->size--;
}
//修改元素
void Change_ConsequenceList(ConsequenceList* list, int index, int element)
{
if (index < 0 || index >= list->size) //下标不合法
{
printf("不合法的下标索求");
return;
}
list->elements[index] = element;
}
//查找元素
void Find_ConsequenceList(ConsequenceList* list, int element)
{
int index;//用来存储寻找元素的下标
for (int i = 0; i < list->size; i++)
{
if (element == list->elements[i])//找到了
{
index = i;
printf("第%d的值为%d\n", index, list->elements[index]);
return;
}
}
printf("找不到对应的元素\n");
}
int main()
{
ConsequenceList list;
Creat_ConsequenceList(&list, 1);
for (int i = 0; i <10; i++)
{
Add_ConsequenceList(&list, i, i * 10);
printf("%d %d\n", i, list.elements[i]);
}
printf("Size:%d\n", list.size);
Find_ConsequenceList(&list, 50);
Change_ConsequenceList(&list, 4, 80);
Delete_ConsequenceList(&list, 8);
for (int i = 0; i < list.size; i++)
{
printf("%d %d\n", i, list.elements[i]);
}
system("pause");
return 0;
}