目录
引言
动态数组和静态数组是两种常见的数据结构,它们在内存管理、灵活性和使用场景上有显著的区别。
动态数组与静态数组的比较
1. 内存分配
静态数组
-
内存分配:在编译时分配固定大小的内存空间。
-
大小固定:数组的大小在定义时确定,无法在运行时改变。
-
示例:
int arr[10]; // 静态数组,大小为10
动态数组
-
内存分配:在运行时通过动态内存分配函数(如
malloc
、realloc
)分配内存。 -
大小可变:可以根据需要动态调整数组的大小。
-
示例:
int *arr = (int *)malloc(10 * sizeof(int)); // 动态数组,初始大小为10
2. 灵活性
静态数组
-
固定大小:一旦定义,大小不可改变。如果需要存储更多数据,必须重新定义一个新的数组。
-
适用场景:适用于数据量固定且已知的情况。
动态数组
-
动态调整:可以根据数据量的变化动态调整数组的大小(扩容或缩容)。
-
适用场景:适用于数据量不确定或可能变化的情况
3. 性能
静态数组
-
访问速度快:内存连续分配,访问元素的时间复杂度为 O(1)O(1)。
-
无内存管理开销:不需要额外的内存管理操作。
动态数组
-
访问速度与静态数组相同:内存连续分配,访问元素的时间复杂度为 O(1)O(1)。
-
内存管理开销:扩容和缩容时需要重新分配内存并复制数据,可能带来额外的性能开销。
4. 内存管理
静态数组
-
自动管理:内存由编译器自动分配和释放,无需手动管理。
-
作用域限制:数组的生命周期受限于其作用域(如函数内部)。
动态数组
-
手动管理:需要手动分配和释放内存(使用
malloc
和free
)。 -
生命周期灵活:可以在程序的任何地方分配和释放内存,生命周期由程序员控制。
5. 使用场景
静态数组
-
数据量固定:如存储一周的天数(7天)、月份(12个月)等。
-
性能要求高:适用于对性能要求极高的场景,避免动态内存分配的开销。
动态数组
-
数据量不确定:如读取用户输入、处理可变长度的数据集等。
-
灵活性要求高:适用于需要频繁调整数组大小的场景。
总结
特性 | 静态数组 | 动态数组 |
---|---|---|
内存分配 | 编译时分配 | 运行时分配 |
大小 | 固定 | 可变 |
灵活性 | 低 | 高 |
性能 | 访问速度快,无内存管理开销 | 访问速度快,有内存管理开销 |
内存管理 | 自动管理 | 手动管理 |
适用场景 | 数据量固定,性能要求高 | 数据量不确定,灵活性要求高 |
动态数组的核心思想
动态数组的核心思想是通过动态内存分配(如 malloc
、realloc
和 free
)来实现数组的自动扩容和缩容。具体来说:
-
初始化:分配一块初始内存用于存储数据。
-
扩容:当数组已满时,分配一块更大的内存,并将原有数据复制到新内存中。
-
缩容:当数组元素减少到一定程度时,释放多余的内存。
-
释放:使用完毕后,释放所有分配的内存,避免内存泄漏。
动态数组的基本结构
动态数组的核心是一个结构体 Array
,包含以下字段:
-
data
:指向动态分配的内存块,用于存储数组元素。 -
size
:当前数组中的元素个数。 -
capacity
:数组的当前容量。
typedef struct
{
int *data; // 存储数据指针
int size; // 当前已使用的元素个数
int capacity; // 数组的容量
} Array;
动态数组的基本操作
1. 初始化动态数组
createArray
函数用于初始化动态数组,分配初始内存,并设置初始容量为10。
Array *createArray()
{
Array *arr = (Array *)malloc(sizeof(Array));
if (arr == NULL)
{
printf("分配内存失败!");
exit(1);
}
arr->data = (int *)malloc(10 * sizeof(int));
if (arr->data == NULL)
{
printf("分配内存失败!");
free(arr);
exit(1);
}
arr->size = 0;
arr->capacity = 10;
return arr;
}
2. 扩容机制
ensureCapacity
函数用于检查数组是否需要扩容。如果当前元素个数达到容量上限,则将容量翻倍。
void ensureCapacity(Array *arr)
{
if (arr->size == arr->capacity)
{
arr->capacity *= 2;
arr->data = (int *)realloc(arr->data, arr->capacity * sizeof(int));
if (arr->data == NULL)
{
printf("分配内存失败!");
free(arr);
exit(1);
}
}
}
3. 添加元素
addElement
函数用于向数组末尾添加元素。如果数组已满,则先调用 ensureCapacity
扩容。
void addElement(Array *arr, int val)
{
ensureCapacity(arr);
arr->data[arr->size] = val;
arr->size++;
}
4. 在指定位置添加元素
findElement函数用于向数组的指定位置添加元素。
void insertElement(Array *arr, int index, int val)
{
if (index < 0 || index >= arr->size)
{
printf("索引超出数组限度!");
return;
}
// 确保容量足够
ensureCapacity(arr);
// 将插入位置后的元素后移
for (int i = arr->size; i > index; i--)
{
arr->data[i] = arr->data[i - 1];
}
arr->data[index] = val;
arr->size++;
}
5. 删除元素
deleteElement
函数用于删除指定位置的元素。删除后,如果数组元素个数小于容量的一半且容量大于10,则进行缩容。
void deleteElement(Array *arr, int index)
{
if (index < 0 || index >= arr->size)
{
printf("索引%d超出数组限度!", index);
return;
}
// 将指定位置后的元素全部前移
for (int i = index; i < arr->size; i++)
{
arr->data[i] = arr->data[i + 1];
}
arr->size--;
// 检查是否需要缩容
if (arr->size < arr->capacity / 2 && arr->capacity > 10)
{
arr->capacity /= 2;
arr->data = (int *)realloc(arr->data, arr->capacity * sizeof(int));
if (arr->data == NULL)
{
printf("分配内存失败!");
free(arr);
exit(1);
}
}
}
6. 获取元素
getElement
函数用于获取指定位置的元素。如果索引无效,则返回错误。
int getElement(Array *arr, int index)
{
if (index < 0 || index >= arr->size)
{
printf("索引超出数组!");
return 0;
}
return arr->data[index];
}
7. 查找元素
findElement函数用于查找目标元素的索引。
nt findElement(Array *arr, int val)
{
for (int i = 0; i < arr->size; i++)
{
if (arr->data[i] == val)
{
return i; // 返回目标元素的索引
}
}
return -1;
}
8. 打印数组
printArray
函数用于打印数组中的所有元素。
void printArray(Array *arr)
{
printf("动态数组内的元素:");
for (int i = 0; i < arr->size; i++)
{
printf("%d ", arr->data[i]);
}
printf("\n");
}
9. 释放内存
freeArray
函数用于释放动态数组占用的内存。
void freeArray(Array *arr)
{
free(arr->data);
free(arr);
}
完整代码示例
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int *data; // 存储数据指针
int size; // 当前已使用的元素个数
int capacity; // 数组的容量
} Array;
// 初始化动态数组
Array *createArray()
{
Array *arr = (Array *)malloc(sizeof(Array));
if (arr == NULL)
{
printf("分配内存失败!");
exit(1);
}
arr->data = (int *)malloc(10 * sizeof(int));
if (arr->data == NULL)
{
printf("分配内存失败!");
free(arr);
exit(1);
}
arr->size = 0;
arr->capacity = 10;
return arr;
}
// 检查是否需要扩容
void ensureCapacity(Array *arr)
{
if (arr->size == arr->capacity)
{
arr->capacity *= 2;
arr->data = (int *)realloc(arr->data, arr->capacity * sizeof(int));
if (arr->data == NULL)
{
printf("分配内存失败!");
free(arr);
exit(1);
}
}
}
// 向动态数组末尾添加元素
void addElement(Array *arr, int val)
{
ensureCapacity(arr);
arr->data[arr->size] = val;
arr->size++;
}
// 在指定位置插入一个元素
void insertElement(Array *arr, int index, int val)
{
if (index < 0 || index >= arr->size)
{
printf("索引超出数组限度!");
return;
}
// 确保容量足够
ensureCapacity(arr);
// 将插入位置后的元素后移
for (int i = arr->size; i > index; i--)
{
arr->data[i] = arr->data[i - 1];
}
arr->data[index] = val;
arr->size++;
}
// 获取指定位置的元素
int getElement(Array *arr, int index)
{
if (index < 0 || index >= arr->size)
{
printf("索引超出数组!");
return 0;
}
return arr->data[index];
}
// 查找元素
int findElement(Array *arr, int val)
{
for (int i = 0; i < arr->size; i++)
{
if (arr->data[i] == val)
{
return i; // 返回目标元素的索引
}
}
return -1;
}
// 删除指定位置的元素
void deleteElement(Array *arr, int index)
{
if (index < 0 || index >= arr->size)
{
printf("索引%d超出数组限度!", index);
return;
}
// 将指定位置后的元素全部前移
for (int i = index; i < arr->size; i++)
{
arr->data[i] = arr->data[i + 1];
}
arr->size--;
// 检查是否需要缩容
// 如果数组的大小小于数组容量的二分之一,并且当前容量大于10,就对动态数组进行缩容
if (arr->size < arr->capacity / 2 && arr->capacity > 10)
{
arr->capacity /= 2;
arr->data = (int *)realloc(arr->data, arr->capacity * sizeof(int));
if (arr->data == NULL)
{
printf("分配内存失败!");
free(arr);
exit(1);
}
}
}
// 打印数组内的元素
void printArray(Array *arr)
{
printf("动态数组内的元素:");
for (int i = 0; i < arr->size; i++)
{
printf("%d ", arr->data[i]);
}
printf("\n");
}
// 释放动态数组
void freeArray(Array *arr)
{
free(arr->data);
free(arr);
}
int main(int argc, char const *argv[])
{
Array *arr = createArray();
addElement(arr, 1);
addElement(arr, 2);
addElement(arr, 3);
addElement(arr, 4);
addElement(arr, 5);
printArray(arr);//输出:1 2 3 4 5
deleteElement(arr, 1);//删除索引为1的元素
printArray(arr);//输出:1 3 4 5
insertElement(arr,1,99);//在索引为1的位置插入元素99
printArray(arr);//输出:1 99 3 4 5
int index=findElement(arr,99);//查找元素的索引
if(index!=-1){
printf("元素99的索引为:%d\n",index);
}else{
printf("为找到元素99!\n");
}
int val = getElement(arr, 1);//查找目标索引的元素
if (val != -1)
{
printf("索引为%d的元素为:%d\n", 1, val);//输出:99
}
return 0;
}