zoukankan      html  css  js  c++  java
  • 我造的轮子——山寨版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"的方式。

  • 相关阅读:
    Vue.js学习 Item14 – 过滤器与自定义过滤器
    Vue.js学习 Item13 – 指令系统与自定义指令
    Vue.js学习 Item12 – 内部响应式原理探究
    redis配置文件redis.conf详细说明
    PhpStorm下Laravel代码智能提示
    laravel 5.0 artisan 命令列表(中文简体)
    阿里云CENTOS服务器挂载数据盘
    NGINX关于配置PATHINFO
    LINUX下导入、导出MYSQL数据库命令
    ECSTORE2.0 定时任务配置
  • 原文地址:https://www.cnblogs.com/lovelyxia/p/1915290.html
Copyright © 2011-2022 走看看