2.1实现简单基础的vector

2.1实现简单基础的vector

 

1.设计API

我们参考下C++ <std> 库中的vector, vector中的api很多,所以我们把里面用的频率很高的函数实现;

1.1 new&delete

new:        应该可以初始化一个我们需要的结构体指针并申请一段内存;

delete:              不仅能够把new出来的内存完整\安全的销毁,而且可以把元素中可能出现的内存指针中申请的内存销魂;

1.2 常用的api

append:      在数组的最末尾添加一个元素;

at:                    获取指定位置的元素;

getSize:    查看当前数组的长度;

resize:    重新扩大当前数组的长度;

remove:   删除指定位置的元素;

clear:               删除现有的所有的元素;

insert:              在指定位置插入指定元素;

1.3 *拓展:打印功能 & 排序功能

deleteSud:  提供释放子元素可能指向的内存的函数

show:       方便快速的显示出元素内容 例如Printf;

toString:       由于支持自定义结构体,因此需要自己编写toString函数,在show函数汇总调用;

sort:              提供一个函数能够将数组里面的元素按照某种规则排序;

compare:      提供一个准则,比较两个元素的大小,commpare(A,B)A<B return 1 else return 0; 

2.原理分析/设计实现

2.0 代码膨胀实现

代码膨胀可是参考以下使用宏定义的方式实现代码膨胀;

 

#include <stdio.h>

// 一个膨胀结构体的宏
#define V_TYPEDEF(XX,TypeName) typedef struct \
{\
    XX* data;\
    unsigned int size;\
    unsigned intrealsize;\
} VCT_##TypeName;

/*
// V_TYPEDEF(int,int_t) 等效于
typedef struct 
{
    int* data;
    unsigned int size;
    unsigned int realsize;
} VCT_int_t;
*/

V_TYPEDEF(int,int_t)

void main(void)
{
    VCT_int_t a;
    a.size = 0;
    a.realsize = 20;
    a.data = (int *) malloc(sizeof(int) *20);
}

 

 

 

2.1 数据结构选择

vector的特性是高效的随机读写,因此需要使用连续的数组;所以需要存储数据的数组 *data;

需要一个字段来管理当前数据写入的位置;同时也需要一个字段来管理申请的内存块大小;

由于C语言不支持函数重载,如果未来大规模使用vector,将会出现很多类似的at、getSize

函数,为了方便程序员找到对应的函数,我们可以在里面添加相对应的函数指针,方便快速找到

对应的操作函数;

因此结构内成员为:

 

//----------------vector 自定义结构体实现----------------//
#define V_TYPEDEF(XX,TypeName) typedef struct __##TypeName##_t \
{\
    XX* data;\
    u32 size;\
    u32 realsize;\
    u8  (* reSize)(struct __##TypeName##_t * v,u32 newsize);\
    u32  (* getSize)(struct __##TypeName##_t * v);\
    XX*  (* at) (struct __##TypeName##_t * v,u32 index);\
    u8  (* append)(struct __##TypeName##_t * v,const XX d);\
    void (* clear)(struct __##TypeName##_t * v);\
    void (* removeLast)(struct __##TypeName##_t * v);\
    void (* remove)(struct __##TypeName##_t * v,u32 starX,u32 lengh);\
    void (* insert)(struct __##TypeName##_t * v,u32 index,const XX value);\
    void (* sort)(struct __##TypeName##_t * v);\
    void (* show)(struct __##TypeName##_t * v);\
    void (* compare)(const XX * v1,const XX * v2);\
    void (* toString)(const XX * value);\
} VCT_##TypeName;

 

 

 

2.2 new函数实现

new函数实现比较简单,申请内存后给定里面所有的数据一个初始值即可;同时我们要注意的是给上

述结构体中的函数指针附上初值;并在宏处添加函数指针的赋值入口;

 

/*
 *  new函数 返回相对应的vector 指针
*/
#define V_NEW(TypeName,COMPARE,TOSTR,DELSUB) \
 VCT_##TypeName* VCT_newVCT_##TypeName()\
{\
    VCT_##TypeName* ret = malloc(sizeof(VCT_##TypeName));\
    if(ret == NULL) return NULL;\
    ret->size = 0;\
    ret->realsize = 0;\
    ret->data = NULL;\
    ret->reSize = VCT_resizeVCT_##TypeName;\
    ret->getSize = VCT_sizeVCT_##TypeName;\
    ret->at = VCT_atVCT_##TypeName;\
    ret->append = VCT_appendVCT_##TypeName;\
    ret->clear = VCT_clearVCT_##TypeName;\
    ret->removeLast = VCT_removelastVCT_##TypeName;\
    ret->remove = VCT_removeVCT_##TypeName;\
    ret->insert = VCT_insertVCT_##TypeName;\
    ret->sort = VCT_sortVCT_##TypeName;\
    ret->show = VCT_showVCT_##TypeName;\
    ret->compare = COMPARE;\
    ret->toString = TOSTR;\
    ret->deleteSub = DELSUB;\
    return ret;\
}

 

 

 

2.3 delete函数实现

delete首先要释放元素中可能指向的内存,然后在释放数组占用的内存,最后才是释放自身占用的内存;

代码如下:

 

/*
 *  delete函数,清理相关结构体使用的堆内存空间
*/
#define V_DELETE(TypeName)\
 void VCT_deleteVCT_##TypeName(VCT_##TypeName* v)\
{\
    if(v == NULL) return ;\
    if(v->data == NULL)    return ;\
    for(u32 i = 0;i< v->size && v->deleteSub != NULL;i++)\
        v->deleteSub(v->data[i]);\
    free(v->data);\
    free(v);\
}

 

 

 

2.4 append实现

append的功能为自动在数组的最末尾添加一个指定元素;需要注意的是,数组的长度并不是一直都

够用的,如果碰到申请的数组长度用完的情况(size == realsize)那么就需要使用resize扩大容量;

因此我们的逻辑是先对传参进行合法性判断,然后判断数据长度,并进行相应操作,最后追加元素;

返回插入结果(成功、失败);

*函数名称前添加‘__’下划线是因为为了防止在代码提示的时候名字高度重复带来的编写不便;

如果这里删除,那么声明和在New中赋值也需要修改,下面的库函数同理;

实现代码如下:

 

/*
 *  vector 实现 append 函数,需要 传参V不为空,自动追加在vector数组的末尾
*/
#define V_APPEND(XX,TypeName) \
    inline u8 __VCT_appendVCT_##TypeName(VCT_##TypeName* v,const XX d)\
    {\
        if(v!= NULL)\
        {\
            if(v->size >= v->realsize)\
                if(v->reSize(v,v->realsize*2+1) == FALSE)\
                    return FALSE;\
            v->data[v->size] = d;\
            v->size++;\
            return TRUE\
        }\
        return FALSE\
    }

 

 

 

2.5 at实现

at需要先判断当前位置是否越界;当然我们也可以使用v->data[i] 这样来调用我们的子项,但是这样

容易发生数组越界和其他问题;

代码如下:

 

/*
 *  vector 实现 at 函数,需要 传参V不为空且 index 小于size  从0开始计数
*/
#define V_AT(XX,TypeName) \
    inline XX* __VCT_atVCT_##TypeName(VCT_##TypeName* v,u32 index)\
    {\
        if(v!=NULL && index < v->size)  return v->data+index;\
        else return NULL;\
    }

 

 

 

2.6 getSize实现

这个没什么好说的 跟v->size作用一致,在此基础之上添加了一个防范措施;

代码如下

 

/**
 *  vector 实现 size 函数,获取当前有实际意义的大小为多少
 *
 */

#define V_SIZE(TypeName) \
    inline u32 __VCT_sizeVCT_##TypeName(VCT_##TypeName* v)\
    {\
        if(v!=NULL) return v->size;\
        else return -1u;\
    }

 

 

 

2.7 resize实现

resize需要注意几点;1.如果申请内存失败了怎么办;2.当原先的resize大小为0时如何变大;

代码如下:

 

/*
 *  vector 实现resize函数,当新的size大于原来的size时,此函数生效,否则则不生效.
*/
#define V_RESIZE(XX,TypeName) \
    u8 __VCT_resizeVCT_##TypeName(VCT_##TypeName* v,u32 newsize)\
 {\
    if(v->realsize < newsize && v->size < newsize )\
    {\
        XX* temp = malloc(sizeof(*v->data)*newsize);\
        if(temp == NULL) return FALSE;\
        memcpy(temp,v->data,sizeof(*v->data)*v->size);\
        memset(temp+v->size,0,sizeof(*v->data)*(newsize-v->size));\
        free(v->data);\
        v->data = temp;\
        v->realsize = newsize;\
        return TRUE;\
    }\
    return FALSE;\
 }

 

 

 

2.8 remove实现

remove函数需要移动指定位置的数据向前,同时判断指定的位置和remove的长度是否

合法,并且释放指定元素肯能指向的内存;

代码如下:

 

/*
 *  vector 实现 remove 函数,需要 传参V不为空,将vector 中从指定位置开始删除 指定长度的数据,如果长度过大则自动判断删除后面所有,
 * 真正的删除,其末尾一定会追加 一个全为 0 的数据字节
 * .
*/
#define V_REMOVE(TypeName) \
    inline void __VCT_removeVCT_##TypeName(VCT_##TypeName* v,u32 starX,u32 lengh) \
{\
    if(v!= NULL) \
    {\
        if(lengh == 0)  return ;\
        else if(v->size > starX) \
        {\
            lengh = (v->size >(starX+lengh))?(lengh):(v->size - starX); \
            for(u32 i = starX;i<v->size;i++) \
            {\
                if(i+lengh < v->size)\
                {\
                    if(v->deleteSub!= NULL)\
                        v->deleteSub(v->data[i]);\
                    memcpy(v->data+i,v->data+i+lengh,sizeof(*v->data)); \
                }\
                else \
                    {memset(v->data+i,0,sizeof(*v->data));  break;}\
            }\
            v->size-=lengh;\
        }\
    }\
}

 

 

 

2.9 clear实现

等同于调用v->remvoe(v, 0,size);

代码如下:

 

/*
 *  vector 实现 clear 函数,需要 传参V不为空,清空vector中所有有效的数据,都初始化为 0,并将size重置,
 * 但是其真正占用的内存并没有被释放.
*/
#define V_CLEAR(TypeName) \
    inline void __VCT_clearVCT_##TypeName(VCT_##TypeName* v)\
 {\
    if(v != NULL) \
    {\
        for(u32 i = 0;i<v->size && v->deleteSub!= NULL;i++)\
            v->deleteSub(v->data[i]);\
        memset(v->data,0,sizeof(*v->data)*v->realsize);\
        v->size = 0;\
    }\
 }

 

 

 

2.10 insert实现

insert的思想有点不一样,insert的思想是先移动开一个空的位置,然后才会放入指定元素;

代码如下:

 

/*
 *  vector 实现 insert 函数,需要 传参V不为空,将vector 中从指定位置开始插入 指定数据,如果指定位置溢出则自动添加到最后,
 * .
*/
#define V_INSERT(T,TypeName) \
    inline void __VCT_insertVCT_##TypeName(VCT_##TypeName* v,u32 index,const T value) \
{\
    if(v!= NULL) \
    {\
        if(index > v->size)\
            index = v->size;\
        if(v->size >= v->realsize)\
            v->reSize(v,v->realsize*2+1);\
        for(u32 i = v->size;i>index;i--)\
            memcpy(v->data+i,v->data+i-1,sizeof(*v->data));\
        memcpy(v->data+index,&value,sizeof(*v->data));    \
        v->size++;\
    }\
}

 

 

 

3.优化/编写注释

因为上述代码是我在之前就已经写好了的库,主要的文件就是.h文件中的这些宏定义;

后续系列我会将所有要写的代码和可能优化的点都在这里添加哦~~

 

最后这里项目的git网址:https://github.com/KimAlittleStar/cstd

不定期更新,请佛系关注~

下一版预告:

Vector中实现insertVector,实现replaceSubVector(想想看 字符串处理 replace(“A”,“a”);)

Vector中实现快速排序~!!

 

 

目录

1.引言

2.1 C语言_实现简单基础的vector

2.2 C语言_实现数据容器vector(排序功能)

3.1 C语言_实现AVL平衡二叉树

3.2 C语言_实现数据容器set(基础版)

4 C语言_实现简单基础的map

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以向您展示如何实现一个简单vector类。 首先,我们需要定义一个类: ```c++ template <typename T> class Vector { private: T* arr; int size; int capacity; public: Vector(); ~Vector(); void push_back(T val); void pop_back(); T& operator[](int index); int getSize(); int getCapacity(); }; ``` 其中,arr是指向存储元素的数组的指针,size表示当前元素的数量,capacity表示当前数组的容量。 接下来,我们需要实现每个函数: ```c++ template <typename T> Vector<T>::Vector() { arr = new T[1]; size = 0; capacity = 1; } template <typename T> Vector<T>::~Vector() { delete[] arr; } template <typename T> void Vector<T>::push_back(T val) { if (size == capacity) { T* temp = new T[capacity * 2]; for (int i = 0; i < size; i++) { temp[i] = arr[i]; } delete[] arr; arr = temp; capacity *= 2; } arr[size] = val; size++; } template <typename T> void Vector<T>::pop_back() { if (size > 0) { size--; } } template <typename T> T& Vector<T>::operator[](int index) { return arr[index]; } template <typename T> int Vector<T>::getSize() { return size; } template <typename T> int Vector<T>::getCapacity() { return capacity; } ``` 这些函数实现了向vector添加元素、删除元素、访问元素以及获取vector大小和容量的功能。 现在,您可以使用该类来创建一个vector对象并开始添加、删除和访问元素了! 请注意,这只是一个简单实现,实际上STL vector类包含了更多功能和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值