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 = ;
a.realsize = ;
a.data = (int *) malloc(sizeof(int) *);
}
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 = ;\
ret->realsize = ;\
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 = ;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*+) == 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,,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 == ) 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,,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 = ;i<v->size && v->deleteSub!= NULL;i++)\
v->deleteSub(v->data[i]);\
memset(v->data,,sizeof(*v->data)*v->realsize);\
v->size = ;\
}\
}
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*+);\
for(u32 i = v->size;i>index;i--)\
memcpy(v->data+i,v->data+i-,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.引言
3.2 C语言_实现数据容器set(基础版)
4 C语言_实现简单基础的map
2.1实现简单基础的vector的更多相关文章
- java:Spring框架1(基本配置,简单基础代码模拟实现,spring注入(DI))
1.基本配置: 步骤一:新建项目并添加spring依赖的jar文件和commons-logging.xx.jar: 步骤二:编写实体类,DAO及其实现类,Service及其实现类; 步骤三:在src下 ...
- cocos2dx的模板容器简单使用(Vector,Map,Value)
在cocos2dxv3.0beta之前存在顺序性容器cocos2d::CCArray,和cocos2d::CCDictionary.可是在新版本号之后这两个容器都将被cocos2d::Vector&l ...
- java学习之路--简单基础的面试题
1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: 1)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪些属性和行为,并不关注 ...
- C++学习3--编程基础(vector、string、三种传参)
知识点学习 Vector容器 vector是C++标准程序库中的一个类,其定义于头文件中,与其他STL组件一样,ventor属于STD名称空间: ventor是C++标准程序库里最基本的容器,设计之初 ...
- 你所要掌握的最简单基础的React渲染优化
一.React的渲染机制 要掌握一两项React-render优化的方法不难,但是非常重要.无论是在实际项目中的一个小细节,还是迎合'面试官'的口味 1.1 触发Render 我们知道React要更新 ...
- C/C++基础----string, vector, array
1 using声明 方便使用命名空间中的成员,不用每次xxx::yyy 头文件不应该包含using声明(不经意间包含了一些名字) 2 string 表3.1:初始化string对象的方式 string ...
- java 学习第一篇简单基础
Java基础 Java Java 和C#有着极为相似的语法. 和C#都是面向对象的高级程序语言. JAVA是一个开源,公开的语言,有着极其丰富的开源库和其他资源. JAVA分类 JAVA分SE EE ...
- ADB简单基础命令
1.查看设备 adb devices 这个命令是查看当前连接的设备, 连接到计算机的android设备或者模拟器将会列出显示 2.安装软件 adb install adb install :这个命令将 ...
- 黑马程序员——JAVA基础之Vector集合
------- android培训.java培训.期待与您交流! ---------- 基本已被淘汰 枚举就是Vector特有的取出方式.枚举和迭代器很像.其实枚举和迭代是一样的. 因为枚举的名称 ...
随机推荐
- Android-WebView支持input file启用相机/选取照片
webview要调起input-file拍照或者选取文件功能,可以在webview.setWebChromeClient方法中重写指定的方法,来拦截webview的input事件,并做我们相应的操作. ...
- a417: 螺旋矩陣
题目: 每行有一正整数T,代表有几组测试数据 接下来有T行,每行有N.M两正整数 N为矩阵长宽,就是会有N*N矩阵 M为方向,M=1为顺时钟,M=2为逆时钟 N范围为1~100之间 思路: 所以,代码 ...
- IntelliJ IDEA远程连接tomcat,实现单步调试
web项目部署到tomcat上之后,有时需要打断点单步调试,如果用的是Intellij idea,可以通过如下方法实现: 开启debug端口,启动tomcat 以tomcat7.0.75为例,打开bi ...
- 网关高可用之keepavlived全流程(安装/配置/验证/解析)
1.场景描述 因为要做网关的高可用,用到了keepalived+nginx,来保证nginx的高可用.(微服务时代之网关及注册中心高可用架构设计),如下图: 安装了keepavlived,走了一些弯路 ...
- FlagCounter被封杀?自己实现一个简单的多国访客计数器
起因 前段时间发现博客右边的FlagCounter计数器突然没了,又看到了博客园封杀了FlagCounter的消息,有点摸不着头脑.于是上FlagCounter的网站上看了一眼,发现最近出现的来自新国 ...
- JavaScript学习记录
js整理笔记 1.数据类型 2.基本语法 3.js运算符 4.条件语句 5.类型转换 6.函数 7.预编译 8.作用域 9.闭包 10.对象创建方法 11.this 12.dom操作 13.事件 14 ...
- 机器学习之SVM调参实例
一.任务 这次我们将了解在机器学习中支持向量机的使用方法以及一些参数的调整.支持向量机的基本原理就是将低维不可分问题转换为高维可分问题,在前面的博客具体介绍过了,这里就不再介绍了. 首先导入相关标准库 ...
- 对象实例Vue
var vm = new Vue({ el:'#app', data:{}, //数据 methods:{}, //方法调用 filters:{}, //私有过滤器 directives:{}, // ...
- PyCharm中创建项目时,在所创建的python虚拟环境下的pip失效
在这篇博文里,我简单地叙述了我在使用PyCharm创建一个flask项目时遇到的问题,以及我解决这个问题的过程.其中比较值得注意的点有:①PyCharm创建新项目时的解释器配置②Python虚拟环境的 ...
- 树上数据结构——LCT
目录 树上数据结构--LCT 概述 基本概念 核心操作 其他操作 完整模板 树上数据结构--LCT 概述 LCT是一种强力的树上数据结构,支持以下操作: 链上求和 链上求最值 链上修改 子树修改 子树 ...