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特有的取出方式.枚举和迭代器很像.其实枚举和迭代是一样的. 因为枚举的名称 ...
随机推荐
- 关于Java网络编程
一,网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可 ...
- App 冷启动与热启动及启动白屏优化
介绍一下 app 冷启动和热启动方式来实现 app 秒开的效果.那么,先来看看什么叫冷启动和热启动. 冷启动:指 app 被后台杀死后,在这个状态打开 app,这种启动方式叫做冷启动. 热启动:指 a ...
- UGUI_游戏界面开发Demo001
1.Alt+Stretch:快速拉伸匹配至画布,与父类大小保持一致. 2.Anchors锚点:实现屏幕自适应 图片也可以实现自适应.Target Graphic (目标图),点击的时候,控件的效果用在 ...
- Unity3D_08_XML文件创建,读取,修改,添加
今天在工作之余学习了一下关于Unity中关于XML的部分. 在这里要注意添加两个命名空间,如下: 一.xml的解析 首先新建一个xml,可以命名为item.xml,拖进assets里面,内容如下: & ...
- 用代码触发testng实现并发测试
有时候希望测试用例能用代码触发,发现testng支持这种操作,于是记录一下: 首先添加testng依赖: <dependency> <groupId>org.testng< ...
- 渐进深入理解Nginx
文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. 之前其实写过一篇文章具体介绍过:最基础的Nginx教学,当时有提到过Nginx有一个重要的功能:负载均衡.所以 ...
- 20 (OC)* GCD、NSOperation、NSThread。多线程
多线程编程技术的优缺点比较 NSThread (抽象层次:低) 优点:轻量级,简单易用,可以直接操作线程对象 缺点: 需要自己管理线程的生命周期,线程同步.线程同步对数据的加锁会有一定的系统开销. C ...
- C++类的this指针详解
这篇文章主要讲解隐式this指针的概念,以及如何使用,包含const 先直接给出一个C++Primer里的类,你可能还不能完全看懂,但是不着急,我们一点点解释 class Sales_data { s ...
- 第一次登陆jenkins页面空白解决方案
之前搭建了几次jenkins环境都没问题,最近换了工作,再次搭建jenkins用的是docker部署: https://www.cnblogs.com/yy-cola/p/10457484.html ...
- Maven 梳理 -scope属性
在POM 4中,<dependency>中还引入了<scope>,它主要管理依赖的部署.目前<scope>可以使用5个值: * compile,缺省值,适用于所有阶 ...