C语言实现动态数组[数据结构]

一.代码实现功能说明

        在C语言中,数组长度一旦被定义,就不能再改变,使得对于数组元素的增删变的十分麻烦,本文将使用一些C语言常见的函数来实现数组的动态扩容,增删功能

        这段代码一共设计了九个函数,分别实现初始化动态数组.扩容动态数组.销毁数组空间.获取数组长度.数组往指定索引位置添加元素.数组往尾部插入元素.数组删除指定索引位置的元素.数组删除指定索引位置的元素.遍历数组元素九个功能.

// 动态数组案例 -> 手敲数据结构代码
#include <stdlib.h>
#include <stdio.h>
// 定义动态数组结构体
typedef struct
{
    // 属性
    int *data;       // 指向连续空间的第一个地址
    size_t length;   // 动态数组中真实数据的个数
    size_t capacity; // 动态数组中数组空间大小
} DynamicArray;

// 初始化动态数组,参数(结构体,初始化数组大小)
void initDynamicArray(DynamicArray *array, size_t init_capacity)
{
    // 动态分配内存
    array->data = (int *)calloc(init_capacity, sizeof(int));
    // 判断是否开辟成功
    if (array->data == NULL)
    {
        printf("空间开辟失败");
        return;
    }
    // 开辟成功,需要对结构体实例的长度和容量属性赋值[初始值]
    array->length = 0;
    // 将初始化数组大小 赋给 结构体的数组大小
    array->capacity = init_capacity;
}
// 扩容动态数组
void resizeDynamicArray(DynamicArray *array, size_t newCapacity)
{
    // 用realloc函数对动态分配的空间扩大
    // 将扩大后的地址仍然赋给原指针
    array->data = realloc(array->data, newCapacity * sizeof(int));
    // 将新的容量也要重新赋值
    array->capacity = newCapacity;
}
// 销毁内存空间
void destroyDynamicArray(DynamicArray *array)
{
    // 直接用free函数销毁原来开辟的内存
    free(array->data);
    // 虽然内存释放了,但数组依然存在,所以要将数组置为NULL
    array = NULL;
}
// 获取长度
int getLength(DynamicArray *array)
{
    return array->length;
}
// 往指定索引位置添加元素
void insertElement(DynamicArray *array, int index, int element)
{
    // 先判断是否数组已满,或者数组为空
    if (index > array->capacity)
    {
        // 索引越界
        return;
    }
    // 考虑扩容问题
    if (array->length == array->capacity)
    {
        // 数组已满 扩容
        int oldcapacity = array->capacity;
        int newcapacity = oldcapacity + oldcapacity >> 1;
        resizeDynamicArray(array, 1.5 * array->capacity);
    }
    for (int i = array->length; i > index; i--)
    {
        array->data[i] = array->data[i - 1];
    }
    // 插入元素
    array->data[index] = element;
    array->length++;
}
// 往尾部插入元素
void addElement(DynamicArray *array, int element)
{
    insertElement(array, array->length, element);
}

// 删除指定索引位置的元素
void deleteAtElement(DynamicArray *array, int index)
{
    // 判断删除的索引位置是否合理
    if (index >= array->capacity)
    {
        return;
    }
    for (int i = index; i < array->length - 1; i++)
    {
        array->data[i] = array->data[i + 1];
    }
    array->length--;
}

// 删除数组尾部的元素
void deleteElement(DynamicArray *array)
{
    // array->length--(可以);
    deleteAtElement(array, array->length - 1);
}

// 遍历数组元素
void printElements(DynamicArray *array)
{
    // 非空校验
    if (array == NULL)
    {
        return;
    }

    // 无元素
    if (array->length == 0)
    {
        return;
    }

    for (int i = 0; i < array->length; i++)
    {
        // printf("%d\t",*(array + i));
        printf("%d\t", (array->data)[i]);
    }
    printf("\n");
}

int main()
{
    DynamicArray array;
    // 初始化长度为3测试
    initDynamicArray(&array, 3);
    // 插入元素
    addElement(&array, 1);
    addElement(&array, 2);
    addElement(&array, 3);

    // 将原来索引为2的位置查插入4
    insertElement(&array, 2, 4);
    // 删除元素
    deleteElement(&array);

    // 删除指定索引位置
    deleteAtElement(&array, 1);

    printElements(&array);
    return 0;
}

 二.动态扩容数组逻辑

        这里我们重点解释如何实现数组扩容.由于我们的数组内存初始化是使用calloc函数实现的,当我们的开辟的内存已满,可以用realloc函数实现不改变内存地址而扩大内存的目的.

// 扩容动态数组

void resizeDynamicArray(DynamicArray *array, size_t newCapacity)

{

    // 用realloc函数对动态分配的空间扩大

    // 将扩大后的地址仍然赋给原指针

    array->data = realloc(array->data, newCapacity * sizeof(int));

    // 将新的容量也要重新赋值

    array->capacity = newCapacity;

}

三.插入和删除元素逻辑

插入逻辑

        我设计的插入逻辑,是先判断插入后,数组是否能装得下,如果装不下,则需要先调用扩容函数再插入元素.

        当开始插入时,先将插入的索引位置之后的元素全部向后平移一位,用倒着遍历循环的方式,将数组的前一个元素赋给后一个元素,代码如下段:

for (int i = array->length; i > index; i--)

    {

        array->data[i] = array->data[i - 1];

    }

        并且扩容时,按照原数组的1.5倍(扩容因子,可修改)扩容,当数组内元素已满时扩容,代码如下:

// 考虑扩容问题

    if (array->length == array->capacity)

    {

        // 数组已满 扩容

        int oldcapacity = array->capacity;

        int newcapacity = oldcapacity + oldcapacity >> 1;

        resizeDynamicArray(array, 1.5 * array->capacity);

    }

删除逻辑

        删除元素并不需要对数组扩容,所以要比插入更简单,不过也需要在删除之前判断要删除的元素索引合不合理.这里我们使用顺序遍历,用删除索引的后一个元素值覆盖前一个元素值,代码如下:

for (int i = index; i < array->length - 1; i++)

    {

        array->data[i] = array->data[i + 1];

    }

    array->length--;

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值