使用C语言实现动态数组Vector

 更新时间:2024年01月10日 09:48:14   作者:厨子老林  
这篇文章主要为大家详细介绍了使用C语言实现动态数组Vector的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

代码仓库地址

1. 动态数组原理

定义一个结构体类型,在结构体中用指针指向一个在堆空间开辟的一块内存。

2. 编写头文件

在头文件里定义Vector的数据结构和相关操作,可以通过修改 “typedef char* Element;” 来修改存储的数据的类型;

#ifndef VECTOR_H
#define VECTOR_H

// 数组默认容量设置为10
#define DEFAULT_CAPACITY 10 
// 数组长度低于 HIGHT_SIZE 时,每次按照原长度翻倍扩容
// 数组长度高于 HIGHT_SIZE 时,扩充原容量的1/2
#define HIGHT_SIZE 1000 

// 定义存储的数据类型
typedef char* Element;

// 定义Vector的数据结构
typedef struct vector_s {
    Element *data; // 用于存储数据的动态数组的指针
    int size; // 数组长度
    int capacity; // 容量
} Vector;

// 创建一个空的Vector
Vector* vector_create();

// 销毁释放Vector
void vector_destroy(Vector *v);

// 向动态数组的末尾新增一个元素
void vector_push_back(Vector *v, Element val);

// 向数组的前面插入一个元素
void vector_push_front(Vector *v, Element val);

// 将元素val添加到索引为idx的位置,idx后面的元素依次后移
void vector_insert(Vector *v, int idx, Element val);

// 给Vector的动态数组扩容
static void vector_rsize(Vector *v);

// 将数组的元素从指定下标位置依次向后挪动
static void move_data(Vector *v, int idx);


#endif

3. 具体实现

1. 创建一个空的Vector

Vector* vector_create() {
    Vector *v = (Vector*)calloc(1, sizeof(Vector));
    if (v == NULL) {
        puts("error:创建一个空的Vector时分配内存失败");
        exit(-1);
    }
    // 给Vector的成员变量赋值
    v->data = c1alloc(DEFAULT_CAPACITY, sizeof(Element));
    if (v->data == NULL) {
        puts("error:创建一个空的Vector时分配内存失败");
        free(v); // 因为下面一行是直接退出程序,free(v)意义不大,但最好还是写上,养成习惯
        exit(-1);
    }
    v->capacity = DEFAULT_CAPACITY;
    return v;
}

2. 销毁释放Vector

void vector_destroy(Vector *v) {
    if (v == NULL) { // Vector不能是NULL
        return;
    }
    free(v->data);
    free(v);
}

3. 向动态数组的末尾新增一个元素

void vector_push_back(Vector *v, Element val) {
    if (v == NULL) { // Vector不能是NULL
        return;
    }
    if (v->size == v->capacity) { // 容量不足,扩容
        vector_rsize(v);
    }
    v->data[v->size] = val;
    v->size++;
}

4. 向数组的前面插入一个元素

void vector_push_front(Vector *v, Element val) {
    if (v == NULL) { // Vector不能是NULL
        return;
    }
    if (v->size == v->capacity) { // 容量不足,扩容
        vector_rsize(v);
    }
    // 从下标0向后移动并在0下标位置赋值
    move_data(v, 0);
    v->data[0] = val;
    v->size++;
}

5. 将元素val添加到索引为idx的位置,idx后面的元素依次后移

void vector_insert(Vector *v, int idx, Element val) {
    if (v == NULL || idx < 0 || idx > v->size) { // Vector不能是NULL,索引位置不能为负且不能越界
        return;
    }
    if (v->size == v->capacity) { // 容量不足,扩容
        vector_rsize(v);
    }
    move_data(v, idx);
    v->data[idx] = val;
    v->size++;
}

6. 给Vector的动态数组扩容

tips:此函数以下几点需要注意

  • 算术运算‘+’的优先级比位运算符‘>>’高,要用括号括起来;
  • 用realloc扩容,不能用calloc和malloc来扩大容量,数据会丢失;
  • 扩容的时候要注意是给Vector的data数组扩容,即v->data;
  • 只有calloc会默认自动赋初值,malloc和realloc都不会默认赋初值,记得给扩容部分附上初始值;
static void vector_rsize(Vector *v) {
    int old_capacity = v->capacity;
    // tips:算术运算‘+'的优先级比位运算符‘>>'高,要用括号括起来
    int new_capacity = v->size < HIGHT_SIZE ? old_capacity << 1 : old_capacity + (old_capacity >> 1);
    // tips:用realloc扩容,不能用calloc和malloc,数据会丢失!
    // tips:扩容的是v->data,而不是v
    Element *temp = realloc(v->data, new_capacity * sizeof(Element));
    if (temp == NULL) {
        puts("error:给Vector的动态数组扩容失败");
        exit(-1);
    }
    // tips:v->data扩容部分附上初值
    memset(v->data + v->size, 0, (v->capacity - v->size) * sizeof(Element));
    v->data = temp;
    v->capacity = new_capacity;
}

7. 将数组的元素从指定下标 idx 位置依次向后挪动1个位置

static void move_data(Vector *v, int idx) {
    for (int i = v->size - 1; i >= idx; i--) {
        v->data[i+1] = v->data[i];
    }
    v->data[idx] = 0;
}

到此这篇关于使用C语言实现动态数组Vector的文章就介绍到这了,更多相关C语言动态数组内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解C语言中常用的失败退出和成功返回

    详解C语言中常用的失败退出和成功返回

    在 C 语言中,封装函数时,我们通常需要判断函数调用是否成功,并据此采取不同的操作,例如,在调用系统函数或库函数时,我们通常会使用一些错误处理机制,来输出错误信息、退出程序或返回不同的状态,以下是如何参考使用这些错误处理机制的示例,需要的朋友可以参考下
    2024-12-12
  • 详谈C++何时需要定义赋值/复制构造函数

    详谈C++何时需要定义赋值/复制构造函数

    下面小编就为大家带来一篇详谈C++何时需要定义赋值/复制构造函数。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • Objective-C不带加减号的方法实例

    Objective-C不带加减号的方法实例

    显而易见的事实是,Objective-C 中,+ 表示类方法,- 表示实例方法,这篇文章主要给大家介绍了关于Objective-C不带加减号的相关资料,需要的朋友可以参考下
    2021-06-06
  • C语言之free函数以及野指针介绍

    C语言之free函数以及野指针介绍

    以下是对C语言中的free函数与野指针进行了详细的分析介绍,需要的朋友可以参考下
    2013-07-07
  • C语言中条件编译详解

    C语言中条件编译详解

    预处理程序提供了条件编译的功能。可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件。这对于程序的移植和调试是很有用的。条件编译有三种形式,下面分别介绍。
    2017-05-05
  • C++11 强类型枚举相关总结

    C++11 强类型枚举相关总结

    这篇文章主要介绍了C++11 强类型枚举的相关资料,帮助大家更好的理解和学习使用c++11,感兴趣的朋友可以了解下
    2021-02-02
  • C++生成和解析XML文件的讲解

    C++生成和解析XML文件的讲解

    今天小编就为大家分享一篇关于C++生成和解析XML文件的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • C++利用递归实现走迷宫

    C++利用递归实现走迷宫

    这篇文章主要为大家详细介绍了C++利用递归实现走迷宫,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • C++如何切割String对象的方法

    C++如何切割String对象的方法

    C++相较于Java,Python 并没有提供的字符串分割的函数split,因此需要自己进行编写,本文主要介绍了C++如何切割String对象的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • C语言动态顺序表实例代码

    C语言动态顺序表实例代码

    大家好,本篇文章主要讲的是C语言动态顺序表实例代码,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12

最新评论