前言
上一篇介绍了容器的接口。这篇打算一个数组来实现容器的具体接口。
vector
vector动态数组,定义如下:
typedef struct _vector
{
container_t container;
type_value_t* _data;
size_t _size;
size_t _capacity;
} vector_t;
- container 接口放第一个字段,等于是继承一个父类。
- type_value_t* 数据节点,由于vector是数组,直接放一个type_value_t 的数组指针好了。
- size 数组的大小。
- capacity 数组的容量。
vector接口的实现
根据container_t 的接口定义,需要实现一下接口:
- container_first
- container_last
- container_search
- container_insert
- container_remove
- container_sort
- container_size
除了container_t的接口外,还需要实现一下迭代器move接口的实现。
- iterator_move(iter, step)
vector 各种接口实现
- first
static iterator_t _vector_first (container_t* container)
{
vector_t* vec = container;
return _get_iter(vec->_data, vec);
}
返回一个指向第一节点的迭代器。
- last
static iterator_t _vector_last (container_t* container)
{
vector_t* vec = container;
return _get_iter((vec->_data + vec->_size -1), vec);
}
返回数组最后一元素的迭代器。
- search
static iterator_t _vector_search (container_t* container, iterator_t offset, type_value_t find, int (*compare)(type_value_t, type_value_t))
{
iterator_t first = offset;
iterator_t tail = container_tail(container);
for(; !iterator_equal(first, tail); first=iterator_next(first)) {
if (compare(iterator_dereference(first), find) == 0) return first;
}
// 返回边界的迭代器
return first;
}
因为type_value_t 是不确定的数据类型,所以需要用户自定义一种比较函数compare(type_value_t, type_value_t),用于查找目标节点。
比较函数返回值如下,两值相等,返回零。前值大于后值,返回一,后值大于前置返回负一。
- 插入
static int _vector_insert (container_t* container, iterator_t it, type_value_t data)
{
// head 的位置不能前插
if (!iterator_is_head(it)){
vector_t* vec = container;
// 检测一下是否满水?
if (vec->_size >= vec->_capacity){
// 注水
unsigned int require_size = vec->_size + VEC_ALLOC_CHUNK_SIZE;
type_value_t *new_block = allocate(container_pool(container), require_size * sizeof(type_value_t));
if (new_block == NULL){
return -1;
}
// 如果整个块要是重新malloc的,那么要重新计算it的位置。
// 隐藏的bug:地址的差值可能会超过 long 的最大值。
ptrdiff_t offset = iterator_reference(it) - iterator_reference(container_head(vec));
// copy 旧数据到新的内存
memcpy(new_block, vec->_data, vec->_size * sizeof(type_value_t));
// 释放旧的内存
deallocate(container_pool(container), vec->_data);
// 把新内存挂上去
vec->_data = new_block;
// 容量值变大。
vec->_capacity += VEC_ALLOC_CHUNK_SIZE;
// 更新it的refer。
void *new_refer = iterator_reference(container_head(vec)) + offset;
iterator_set_reference(it, new_refer);
}
// 继续做插入动作。
iterator_t last = container_last(container);
iterator_t it_prev = iterator_prev(it);
// 挪位
for (; !iterator_equal(last, it_prev); last = iterator_prev(last)){
iterator_t last_next = iterator_next(last);
iterator_assign(last_next, last);
}
// 插入
type_value_t *pt = iterator_reference(it);
*pt = data;
vec->_size++;
return 0;
}
return -1;
}
vector 的插入有个需要注意的地方。当向vector插入元素的时候,原来分配的内存可能不够,那么就需要释放原来的内存,申请更大的内存来放入原属,重新申请内存后。原来迭代器find指向的节点地址会变成无效,那么则需要根据旧的内存地址去计算新的内存地址。具体算法参考以上代码。
- 移除
static int _vector_remove (container_t* container, iterator_t it, type_value_t* rdata)
{
if (!iterator_is_boundary(it)){
vector_t *vec = container;
if (rdata){
*rdata = iterator_dereference(it);
}
// 擦除
for (;!iterator_equal(it, container_last(vec));it = iterator_next(it)){
iterator_t it_next = iterator_next(it);
iterator_assign(it, it_next);
}
vec->_size--;
return 0;
}
return -1;
}
- 排序
static int _vector_sort(container_t* container, int(*compare)(type_value_t, type_value_t))
{
return quick_sort(container_first(container), container_last(container), compare);
}
- size
static size_t _vector_size (container_t* container)
{
return ((vector_t*)container)->_size;
}
- 迭代器移动接口
static iterator_t _move (iterator_t it, int step)
{
type_value_t* pv = iterator_reference(it);
//return _get_iter((pv + step), iterator_container(it));
return iterator_set_reference(it, (pv+step));
}
接口绑定
在定义完以上接口后,便可以制作一个vector的容器了。
- 绑定迭代器的接口的函数:
static iterator_t _get_iter (void* refer, void* vec) {
return get_iterator(refer, vec, _move);
}
这个refer参数,就是当前节点的指针,参考first的函数的写法:
vector_t* vec = container;
return _get_iter(vec->_data, vec);
- 绑定容器的接口的函数:
void init_vector(vector_t* vector, pool_t* _pool) {
// 这个函数调用即是接口函数与container_t 相应的函数字段赋值。
initialize_container(vector, _vector_first, _vector_last, _vector_search, _vector_insert, _vector_remove,_vector_sort, _vector_size, _pool);
vector->_size = 0;
vector->_capacity = VEC_ALLOC_CHUNK_SIZE;
// 先给水池注点水。
vector->_data = allocate(container_pool(vector), VEC_ALLOC_CHUNK_SIZE*sizeof(type_value_t));
return;
}
完了
《第一篇,数据类型》
《第二篇,迭代器》
《第三篇,容器接口》
《第四篇,vector实现的容器》
《第五篇,list实现的容器》
《第六篇,排序》
项目地址