动态数组的实现与静态数组的区别:C语言

 

目录

 

引言

动态数组与静态数组的比较

1. 内存分配

静态数组

动态数组

2. 灵活性

静态数组

动态数组

3. 性能

静态数组

动态数组

4. 内存管理

静态数组

动态数组

5. 使用场景

静态数组

动态数组

总结

动态数组的核心思想

动态数组的基本结构

动态数组的基本操作

1. 初始化动态数组

2. 扩容机制

3. 添加元素

4. 在指定位置添加元素

5. 删除元素

6. 获取元素

7. 查找元素

8. 打印数组

9. 释放内存

完整代码示例


 

引言

动态数组和静态数组是两种常见的数据结构,它们在内存管理、灵活性和使用场景上有显著的区别。

动态数组与静态数组的比较

1. 内存分配

静态数组

  • 内存分配:在编译时分配固定大小的内存空间。

  • 大小固定:数组的大小在定义时确定,无法在运行时改变。

  • 示例

int arr[10]; // 静态数组,大小为10

动态数组

  • 内存分配:在运行时通过动态内存分配函数(如 mallocrealloc)分配内存。

  • 大小可变:可以根据需要动态调整数组的大小。

  • 示例

int *arr = (int *)malloc(10 * sizeof(int)); // 动态数组,初始大小为10

2. 灵活性

静态数组

  • 固定大小:一旦定义,大小不可改变。如果需要存储更多数据,必须重新定义一个新的数组。

  • 适用场景:适用于数据量固定且已知的情况。

动态数组

  • 动态调整:可以根据数据量的变化动态调整数组的大小(扩容或缩容)。

  • 适用场景:适用于数据量不确定或可能变化的情况

3. 性能

静态数组

  • 访问速度快:内存连续分配,访问元素的时间复杂度为 O(1)O(1)。

  • 无内存管理开销:不需要额外的内存管理操作。

动态数组

  • 访问速度与静态数组相同:内存连续分配,访问元素的时间复杂度为 O(1)O(1)。

  • 内存管理开销:扩容和缩容时需要重新分配内存并复制数据,可能带来额外的性能开销。

4. 内存管理

静态数组

  • 自动管理:内存由编译器自动分配和释放,无需手动管理。

  • 作用域限制:数组的生命周期受限于其作用域(如函数内部)。

动态数组

  • 手动管理:需要手动分配和释放内存(使用 malloc 和 free)。

  • 生命周期灵活:可以在程序的任何地方分配和释放内存,生命周期由程序员控制。

5. 使用场景

静态数组

  • 数据量固定:如存储一周的天数(7天)、月份(12个月)等。

  • 性能要求高:适用于对性能要求极高的场景,避免动态内存分配的开销。

动态数组

  • 数据量不确定:如读取用户输入、处理可变长度的数据集等。

  • 灵活性要求高:适用于需要频繁调整数组大小的场景。

总结

特性静态数组动态数组
内存分配编译时分配运行时分配
大小固定可变
灵活性
性能访问速度快,无内存管理开销访问速度快,有内存管理开销
内存管理自动管理手动管理
适用场景数据量固定,性能要求高数据量不确定,灵活性要求高

 

动态数组的核心思想

动态数组的核心思想是通过动态内存分配(如 mallocrealloc 和 free)来实现数组的自动扩容和缩容。具体来说:

  1. 初始化:分配一块初始内存用于存储数据。

  2. 扩容:当数组已满时,分配一块更大的内存,并将原有数据复制到新内存中。

  3. 缩容:当数组元素减少到一定程度时,释放多余的内存。

  4. 释放:使用完毕后,释放所有分配的内存,避免内存泄漏。

 

动态数组的基本结构

动态数组的核心是一个结构体 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;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值