我造的轮子——山寨版vector

  昨天看C++里面的容器部分,发现vector的特性很独特:

  • vector对于随机访问有很好的效率,猜想可能是顺序存储
  • vector对随机插入和删除的效率不高,这种特性也是由顺序存储引起的
  • vector容器的容量是自增长的,并不是一开始申请很大一块内存然后直到撑满,而是满了后容量加倍。

这种特性跟delphi的TList特别像,在delphi里面,放一个array of pointer的指针,

这个指针所指向的空间的内存是动态增长的,容量到达后就增加一个delta,它的增删改查,分别是这么实现的:

  • 增加分为两种情况:

  (1)在末尾增加:首先判断容量满了没有,如果没有满则直接在数组后面赋值,如果满了就要增加容量后赋值

  (2)在中间插入:首先要移出空位给需要insert的元素,然后赋值,移动之前要判断容量是否充足,++size

  • 删除:删除操作就是将要删除的元素后面的内存单元向前面移动一格,--size
  • 查,非常简单,只要index在范围内,直接用数组的index就可以查到元素,非常高效

  我实现的代码基本上是仿照delphi的TList实现的,顺便加入了模板编程,插入的元素是泛型的。

这点较delphi有较大改进。delphi只支持管理pointer类型的。我插入的时候用的都是对象的副本,因为所有需要传元素

的地方都没有用引用,对于基本类型来说,空间损耗很小,但是对于对象来说有可能会空间损耗很大。

  另外这个例子也没有实现delphi里面的notify机制,delphi考虑扩展性,加入了notify,方便派生类操作。

头文件:

 

头文件
   
     
#ifndef CLASSES_H
#define CLASSES_H

const int MAXCAPACITY = 100000 ;
template
< class Type >
class my_vector{
private :
typedef Type(
* PType_Array)[MAXCAPACITY];
PType_Array data_list;
int count;
int capacity;
void grow();
public :
my_vector():count(
0 ), capacity( 0 ){}
~ my_vector(){clear();}
void set_Capacity( int cap);
int get_capacity();
void set_count( int count);
int get_count();
int add(Type t);
void clear();
void remove_by_index( int index);
void remove(Type t);
int index_of(Type t);
void insert( int index, Type t);
Type first();
Type last();
Type
operator []( int i);
};



#endif

 

源文件
   
     
#include " stdafx.h "
#include
" classes.h "
#include
< cstdlib >

template
< class Type > void my_vector < Type > ::grow(){
int delta;
if (capacity <= 8 )
delta
= 4 ;
else if (capacity <= 64 )
delta
= 16 ;
else
delta
= capacity / 4 ;
set_Capacity(capacity
+ delta);
}

template
< class Type > void my_vector < Type > ::set_Capacity( int new_capacity){
if (new_capacity < count || new_capacity > MAXCAPACITY){
std::cerr
<< " Capacity Invalid " << endl;
exit(
0 );
}
if (count == 0 ){
data_list
= (PType_Array)malloc( sizeof (Type) * new_capacity);
capacity
= new_capacity;
}
else if (new_capacity != capacity){
data_list
= (PType_Array)realloc(data_list, sizeof (Type) * new_capacity);
capacity
= new_capacity;
}
}

template
< class Type > int my_vector < Type > ::get_capacity(){

return capacity;
}

template
< class Type > void my_vector < Type > ::set_count( int new_count){

if (new_count < 0 || new_count > MAXCAPACITY){
std::cerr
<< " Capacity Invalid " << endl;
exit(
0 );
}
if (new_count > capacity)
set_Capacity(new_count);
if (new_count > count)
memset((
* data_list) + count, 0 , sizeof (Type) * (new_count - count));
else {
int i = 0 ;
for (i = count - 1 ; i >= new_count; -- i)
remove_by_index(i);
}
count
= new_count;

}

template
< class Type > int my_vector < Type > ::get_count(){

return count;
}

template
< class Type > void my_vector < Type > ::remove(Type t){

int index = index_of(t);
if (index >= 0 )
remove_by_index(index);
}

template
< class Type > void my_vector < Type > ::remove_by_index( int index){

if (index < 0 || index >= count)
{
std::cerr
<< " out of bound " << endl;
exit(
0 );
}
-- count;
memcpy(
* data_list + index, * data_list + index + 1 , (count - index) * sizeof (Type));
}

template
< class Type > int my_vector < Type > ::add(Type t){

int res;
res
= count;
if (res == capacity)
grow();
(
* data_list)[res] = t;
++ count;
return res;
}

template
< class Type > void my_vector < Type > ::insert( int index, Type t){
if (index < 0 || index > count){
std::cerr
<< " out of bound " << std::endl;
exit(
0 );
}
if (count == capacity)
grow();
memcpy((
* data_list) + index + 1 , ( * data_list) + index, count - index);
(
* data_list)[index] = t;
++ count;
}

template
< class Type > Type my_vector < Type > ::first(){
if (count > 0 )
return ( * data_list)[ 0 ];
else
{
cerr
<< " no element " << endl;
exit(
0 );
}
}

template
< class Type > Type my_vector < Type > ::last(){

if (count > 0 )
return (( * data_list)[count - 1 ]);
else
{
cerr
<< " no element " << endl;
exit(
0 );
}
}

template
< class Type > Type my_vector < Type > :: operator []( int i){
if (i >= count || i < 0 ){
cerr
<< " No element " << endl;
exit(
0 );
}
return ( * data_list)[i];
}

template
< class Type > void my_vector < Type > ::clear(){

set_count(
0 );
set_Capacity(
0 );
}

template
< class Type > int my_vector < Type > ::index_of(Type t){
int i( - 1 ), res( - 1 );
for (i = 0 ; i < count; ++ i)
{
if (( * data_list)[i] == t)
{
res
= i;
break ;
}
}
return res;
}

 

主函数
   
     
#include " stdafx.h "
#include
" classes.cpp "
#include
" classes.h "
#include
< iostream >
#include
< string >
using namespace std;

void display_vector(my_vector < char *> vec){
int i;
for (i = 0 ;i < vec.get_count(); ++ i)
cout
<< vec[i] << " " ;
cout
<< endl;
}

int _tmain( int argc, _TCHAR * argv[])
{
my_vector
< char *> vec;
/// //test add
for ( int i = 0 ; i < 50 ; ++ i){
char * str = new char [ 10 ];
sprintf(str,
" %d " , i);
vec.add(str);
}
/// /test remove;
cout << vec.get_count() << endl;
vec.remove_by_index(
5 );
cout
<< vec.get_count() << endl;
/// /test remove
cout << vec.get_count() << endl;
vec.remove(
0 );
cout
<< vec.get_count() << endl;
/// /test insert;
vec.insert( 12 , " asss " );
cout
<< vec.get_count() << endl;
vec.first();
vec.last();
display_vector(vec);
}

 

  另外关于泛型编程,要特别注意工程的链接方式,因为没有确定类型的时候,编译器不知道如何编译泛型函数,只有当确定类型后,

才会去找源文件。可以说泛型的编译是一种懒编译。

  所以在用的时候要确保能链接到header对应的源文件。c++ primer里面用的是在header文件里面#include "xxxx.cpp"的方式

我用的这种方式比较挫一点,直接在主函数的cpp文件里 #include "xxx.cpp"的方式。

你可能感兴趣的:(vector)