9.vector的使用介绍和模拟实现

1.vector的介绍及使用

1.1 vector的介绍

vector的文档介绍

  1. vector是表示可变大小数组的序列容器。

  2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。

  3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。

  4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。

  5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。

  6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。

1.2 vector的使用

push_back的用法

#include <iostream>
#include <vector>
using namespace std;

void test_vector1()
{
    // 使用int实例化一个vector对象
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	for (size_t i = 0; i < v.size(); ++i)
	{
		cout << v[i] << " ";
	}
	cout << endl;

    // 使用迭代器打印容器中的数据
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

    // 使用for循环打印容器中的数据
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

    // 打印容器的最大存储容量
	cout << v.max_size() << endl;

	//vector<char> vstr;    // vector并不可以替代string
	//string str;
}

reserve的用法

void test_vector2()
{
	vector<int> v;
    // 向容器中尾插数据
    // void push_back (const value_type& val);
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	cout << v.capacity() << endl;  // 打印结果为6

    // 调整容器的大小
	v.reserve(10);
	cout << v.capacity() << endl;  // 打印结果为10

	// 比当前容量小时,不缩容
	v.reserve(4);
	cout << v.capacity() << endl;  // 打印结果为10

    // 调整容器size的大小
	v.resize(8);
	v.resize(15, 1);
	v.resize(3);
}
// vector的扩容机制
void TestVectorExpand()
{
	size_t sz;
	vector<int> v;
    // 提前预留空间(在已知将要插入多少数据量)
	v.reserve(100);
	sz = v.capacity();
    cout << sz << endl;
	cout << "making v grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

size和[]重载

// size只有一个接口,为const接口(size只需要提供读的功能)
// size_type size() const;

// operator[]提供了两个接口(operator[]要有读和写的功能)
// reference operator[] (size_type n);
// const_reference operator[] (size_type n) const;
void Func(const vector<int>& v)
{
	v.size();
	v[0];
    
    // 错误演示, v被const修饰,因此调用的接口为const_reference operator[] (size_type n) const;
    // 因此v[0]是不可以被修改的
	// v[0]++; 
    
	// Returns a reference to the element at position n in the vector.
    // 返回vector中n下标位置的元素的引用
    // reference 就是类型, value_type&
    // reference at (size_type n);
	// const_reference at (size_type n) const;
	v.at(0);
}
// 总结
// 1.只读接口函数。const;   如size()
// 2.只写接口函数。非const;  如push_back()
// 3.可读可写的接口函数。const+非const;     如operator[]


void test_vector3()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.size();
	v[0];
	v[0]++;
	v.at(0);

	Func(v);
}

operator[]和at()越界的区别

// operator[]和at()越界的区别就是:一个是assert,一个是抛异常
void test_vector4()
{
	vector<int> v;
    
	//v.reserve(10);
	v.resize(10);
	for (size_t i = 0; i < 10; ++i)
	{
		v[i] = i;       // assert 
		// v.at(i) = i;  // 抛异常
		// v.push_back(i);
	}
}

assign的用法

// assign()
// template <class InputIterator>  
// void assign (InputIterator first, InputIterator last);
// 新内容是由范围内的每个元素构建的元素,顺序相同,从第一个元素到最后一个元素。

// void assign (size_type n, const value_type& val);
// 这个版本的 assign() 函数接受一个整数参数 count 和一个值 value,它会用 count 个 value 值来替换容器中的元素
void test_vector5()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);

	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

    // 对应 void assign (size_type n, const value_type& val);
	v.assign(10, 1); 
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v1; 
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);

    
    // 对应template <class InputIterator>  
    // void assign (InputIterator first, InputIterator last);
    // 将v容器中的元素替换为,v1容器中(begin指针到end指针之间的元素)
	v.assign(v1.begin(), v1.end());
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	
    string str("hello world");
	v.assign(str.begin(), str.end());  //有迭代器就可以使用
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	v.assign(++str.begin(), --str.end());
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

find、insert、swap的用法

// std::find的源码
/*
 template <class InputIterator, class T>
    InputIterator find (InputIterator first, InputIterator last, const T& val);

The behavior of this function template is equivalent to:
template<class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val)
{
   while (first!=last) 
   {
     if (*first==val) 
     	return first;
     ++first;
   }
   return last;
}
*/

void test_vector6()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);

	v.insert(v.begin(), 4);
	v.insert(v.begin()+2, 4);

	
	//vector<int>::iterator it = v.find(3);

	vector<int>::iterator it = find(v.begin(), v.end(), 3);
	if (it != v.end())
	{
		v.insert(it, 30);
	}

	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v1;
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);

//    专门为vector写的非成员函数,就是为了防止调用算法库中的swap(),哪个需要将交换的对象实例化,代价太大
//    std::swap (vector)   // 使用这个swap就相当于调用  v1.swap(v);
    
//    template <class T, class Alloc>
//    void swap (vector<T,Alloc>& x, vector<T,Alloc>& y);
    
	v1.swap(v);   
	swap(v1, v);  // std::swap (vector),对swap的重载
}
void test_vector7()
{
	vector<int> v;
	v.reserve(10);
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);

	cout << v.size() << endl;
	cout << v.capacity() << endl;

	// 设计理念:不动空间,不去缩容   空间换时间
	v.reserve(5);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.resize(3);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.clear();
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	// 设计理念:时间换空间,一般缩容都是异地,代价不小,一般不要轻易使用
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
    // 这个函数的功能就是
	v.shrink_to_fit();
    
	cout << v.size() << endl;
	cout << v.capacity() << endl;
}


int main()
{
	try
	{
		test_vector4();
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}

	//TestVectorExpand();
    
    return 0;
}



// 增:push_back 不直接头插(需要挪动数据,效率低,建议少用)  偶尔头插,使用insert(v.begin(),val) 
// 删:pop_back 不直接头删(需要挪动数据,效率低,建议少用) 偶尔头删,使用erase(v.begin())
// 查:算法库的find
// 改:迭代器 + []

习题

只出现一次的数字

image-20240410220908131

  • 分析
// &(按位与)    都为1则按位与为1,有0,则按位与为0
  // & (按位与)
//00000000000000000000000000000011 - 3的补码(正数的原码,补码,反码相同)
//	//10000000000000000000000000000101 -  -5的原码
//	//11111111111111111111111111111010 -  -5的反码(符号位不变,其他位按位取反)
//	
//  //11111111111111111111111111111011 - -5的补码
//	//00000000000000000000000000000011 - 3的补码
//	//00000000000000000000000000000011 - &后的补码(放到内存中的都是补码);


// |(按位或) 有1则按位或为1,都为0则按位或为0
//	00000000000000000000000000000011 - 3的补码(正数的原码,补码,反码相同)
//	10000000000000000000000000000101 -  -5的原码
//	11111111111111111111111111111010 -  -5的反码(符号位不变,其他位按位取反)
//	
//  11111111111111111111111111111011 - -5的补码
//	00000000000000000000000000000011 - 3的补码
//	11111111111111111111111111111011 - |(按位或) 后的补码(放到内存中的都是补码);


// ^(按位异或) 相同,则按位异或为0,相反则按位异或为1
//	00000000000000000000000000000011 - 3的补码(正数的原码,补码,反码相同)
//	10000000000000000000000000000101 -  -5的原码
//	11111111111111111111111111111010 -  -5的反码(符号位不变,其他位按位取反)
//	
//  11111111111111111111111111111011 - -5的补码
//	00000000000000000000000000000011 - 3的补码
//	11111111111111111111111111111000 - ^(按位异或)后的补码(放到内存中的都是补码);

// 任何数按位异或0,都等于它本身;  如 a^0 = a
// 任何数按位异或其本身,都等于0,  如 a^a = 0
// 3^3^5 = 5  
// 3^5^3 = 5   
//由以上可得异或操作符支持交换律
class Solution {
public:
    int singleNumber(vector<int>& nums) 
    {
        int ret = 0;

        // 范围for
        for(auto e : nums)
        {
            // 数组中只有一个数据是单个,其余数据都是两两一组,且相等
            // 又因为a^0 == a
            // a^a == 0
            // a^b^c == a^c^b  按位异或 的复合交换律
            ret ^= e;
        }

        return ret;

    }
};

杨辉三角

image-20240410221214145

image-20221217193938067

class Solution {
public:
    vector<vector<int>> generate(int numRows)
    {
        // 先创建一个二维数组的vector对象(存放的数据为int)
        vector<vector<int>> vv;

        // 确定vector的大小;
        // 使用resize可以对其初始化,如果不传参,会使用缺省参数
        vv.resize(numRows);

        // 像遍历二维数组一样,将相应的数值进行存储
        // vv.size()代表的就是二维数组的行数
        // 因为在vv中,一个元素的大小就是vector<int>的大小
        for(size_t i = 0; i < vv.size(); ++i)
        {
            // 确定vector<int>的大小,并初始化
            // void resize (size_type n, value_type val = value_type());
            // 调整容器的大小,使其包含 n 个元素。 
            // 如果新的大小大于当前大小,则容器将增加到 n 个元素,并用可选的第二个参数 value 的值进行填充。
            vv[i].resize(i+1,0);
            
            // 边界的数值填充
            // 左边界就是vv[i][0];  右边界是vv[i][vv[i].size() - 1]
            vv[i][0] = vv[i][vv[i].size() - 1] = 1;
        }

        // 杨辉三角一共有vv.size()行,每一行有vv[i].size()列
        for(size_t i = 0; i < vv.size(); ++i)
        {
            for(size_t j = 0; j < vv[i].size(); ++j)
            {
                // 如果值为1,为边界的值,不用处理
                // 如果值为0,这个值的大小等于左上方的值加上右上方的值
                if(vv[i][j] == 0)
                {
                    
                    vv[i][j] = vv[i-1][j] + vv[i-1][j-1];
                }
            }
        }

        return vv;

    }
};

电话号码的字母组合

image-20240410223032763

image-20221221191502837

// 解题思路
class Solution {
    // 2~9所有数字对应的字符
    string _numStr[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};

public:
    void Combine(const string& digits, int i, vector<string>& vCombine, string combinestr) 
    {
        // 当i等于digits.size()时,迭代完成
        // 将已经组合好的字符串combinestr尾插到vCombine中
        if(i == digits.size())   
        {
            vCombine.push_back(combinestr);
            return;
        }

        // 第一次迭代
        // digits[i]是字符的ASCLL值,因此需要减去字符'0'才可以拿到相应的数
        // num就是电话号码的第一个数字
        int num = digits[i] - '0';   

        // 将电话号码第一个数字对应的字符串存储到str中
        string str = _numStr[num];  

        // 遍历str
        for(auto ch : str) 
        {
            // 开始迭代
            // 经过for循环,会将str存储的所有字符串,都执行一次 Combine,层层递归,直到i == digits.size()为真结束
            Combine(digits, i+1, vCombine, combinestr + ch); 
        }      
    }  
    
    
    // 题目给出的接口
    vector<string> letterCombinations(string digits){
        // 用来存储组合好的字符串
        vector<string> vCombine;

        // 如果没有输入字符,则返回一个空的vector<string>; 
        // 特殊的,作单独处理
        if(digits.empty())
        {
            return vCombine;
        }

        // i为string digits的下标
        size_t i = 0;
        
        // str是用来存储组合起来的字符串的
        // 对应这个构造函数string();   这个构造的对象为空串
        string str;   

        // digit是题目给我们的数字,这些数字存放在字符串当中
        // i是字符串中,字符对应的下标
        Combine(digits, i, vCombine, str);

        return vCombine;
    }
};

2.vector深度剖析及模拟实现

image-20221218214249874

vector的私有成员变量

iterator _start;          // 指向数组的起始位置
iterator _finish;         // _finish == _start + size();    指向数组的末尾(指向末尾元素的下一个元素)
iterator _endofstorage;   // _endofstorage == _start + capacity();  数组的容量,指向数组容量的末尾(末尾的下一个元素)

image-20240411213241008

迭代器

typedef T* iterator;             
typedef const T* const_iterator; 

// 普通迭代器
iterator begin()
{
    return _start;
}

iterator end()
{
    return _finish;
}

// const迭代器
const_iterator begin() const
{
    return _start;
}

const_iterator end() const
{
    return _finish;
}

operator[]重载

// 普通重载operator[]
T& operator[](size_t pos)
{
    assert(pos < size());
    return _start[pos];
}

// const重载operator[]
const T& operator[](size_t pos) const
{
    assert(pos < size());
    return _start[pos];
}

默认构造函数

// 默认构造函数
vector()
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{}

// n可以为负数(这种方法不建议)
// vector<int> v1(10, 1);     // 10为int类型,1为int类型
// vector<int> v1(10, 1) 匹配 vector(int n, const T& val = T())

// size_t 不会有负数(建议使用这种构造方法)
// vector<char> v1(10, 'A');  // 10为int类型,'A'为char类型
// vector<char> v1(10, 'A') 匹配 vector(size_t n, const T& val = T())
// int会发生整型提升,提升为size_t类型
// 用n个val值来填充容器

vector(int n, const T& val = T())
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
    reserve(n);
    for (int i = 0; i < n; ++i)
    {
        push_back(val);
    }
}

vector(size_t n, const T& val = T())
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
    reserve(n);
    for (size_t i = 0; i < n; ++i)
    {
        push_back(val);
    }
}

拷贝构造函数

// 传统的拷贝构造的写法
// v2(v1)
/*
vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
    reserve(v.capacity());
    for (const auto& e : v)
    {
        push_back(e);
    }
}*/


// 现代写法的拷贝构造
// v1(v2)
template <class InputIterator>
vector(InputIterator first, InputIterator last)
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
    // 用迭代器的方法将v2的数据,一个一个插入到v1中
    while (first != last)
    {
        push_back(*first);
        ++first;
    }
}

// v1(v2)
vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
    // 使用上述的现代写法的拷贝构造函数将v2的数据拷贝给tmp
    vector<T> tmp(v.begin(), v.end());   // 将v的数据拷贝到tmp
    
    // 交换tmp和v1的成员变量
    swap(tmp);
}

void swap(vector<T>& v)
{
    std::swap(_start, v._start);
    std::swap(_finish, v._finish);
    std::swap(_endofstorage, v._endofstorage);
}

operator=

// v1 = v2
// 这里的vector<T> v 是v2的拷贝
vector<T>& operator=(vector<T> v)
{
    // v出了作用域就会被销毁
    // 交换v和v1
    swap(v);
    return *this;
}

reserve, 扩容

// 扩容
void reserve(size_t n)
{
    // 如果将要扩容的容量n大于原有的容量capacity(),那么就要进行扩容;但是如果将要扩容的容量n小于原有的容量capacity(),那么不进行处理(不会进行缩容)
    if (n > capacity())
    {
        // 此处必须将size()的返回值进行存储
        // 如果_start被改变,则size()的返回值也会被改变;(size()的返回值就是_start与_finsh两个指针之间元素的个数)
        size_t oldSize = size();
        
        // tmp是扩容后,新空间的地址
        T* tmp = new T[n];

        if (_start)
        {
            // 将旧空间的数据按字节拷贝到新空间
            memcpy(tmp, _start, sizeof(T)*oldSize); // 将原空间的数据拷贝到新空间
            delete[] _start;                        // 将原空间释放
        }

        // 更新成员变量
        _start = tmp;                 
        _finish = tmp + oldSize;    // 指针+整型 = 指针 (指针+1 就会跳过 T* 个字节的地址)
        _endofstorage = _start + n;
    }
}

resize();调整数组的大小

// 设置数据个数的大小,并对扩容空间进行初始化初始化(使用val进行初始化)
void resize(size_t n, T val = T())
{
    // 如果n > capacity(),则需要先进行扩容
    if (n > capacity())    
    {
        reserve(n);
    }

    if (n > size())
    {
        // size()位置到n位置的数据进行初始化;也就是对n-size()个数据初始化
        // 即n-(_finish - _start) > 0
        while (_finish < _start + n)    
        {
            *_finish = val;
            ++_finish;
        }
    }
    else
    {
        // 当n <= size()时,令 n == size()即可,也就是 n == _finish - _start
        _finish = _start + n;
    }
}

尾插,尾删

void push_back(const T& x)
{
    // 如果数组的大小与数组的容量相等,那么要插入,就需要进行扩容
    if (_finish == _endofstorage)
    {
        size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
        reserve(newCapacity);
    }

    *_finish = x;
    ++_finish;
}

void pop_back()
{
    assert(!empty());

    --_finish;
}

insert;任意位置插入

// 迭代器失效 : 扩容引起,野指针问题
iterator insert(iterator pos, const T& val)
{
    // pos只是形参; this->_start; this->_finish
    assert(pos >= _start);
    assert(pos < _finish);

    // 扩容(容量满了,需要进行扩容)
    if (_finish == _endofstorage)
    {
        // 记录起始位置和pos位置之间的长度
        size_t len = pos - _start;
        
        size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
        reserve(newCapacity);

        // 这里如果不更新pos就会导致野指针
        // 扩容之后,编译器可能会重新分配新的空间,pos还指向原来的空间(也就是野指针)
        // 扩容会导致pos迭代器失效,需要更新处理一下
        pos = _start + len;
    }

    // 挪动数据(将pos以及pos位置后的数据向后挪动一个位置)
    // _finish 指向数组最后一个元素的下一个位置
    // _finish - 1 指向数组的最后一个元素
    iterator end = _finish - 1;
    while (end >= pos)   
    {
        *(end + 1) = *end;
        --end;
    }

    *pos = val;
    ++_finish;

    // 返回更新之后的pos指针,这里的pos指针是主函数的形参,必须返回更新主函数的pos实参
    return pos;
}

erase任意位置删除

iterator erase(iterator pos)
{
    assert(pos >= _start);
    assert(pos < _finish);

    // 将pos位置后的所有数据向前挪动
    iterator begin = pos+1;
    while (begin < _finish)
    {
        *(begin-1) = *(begin);
        ++begin;
    }

    --_finish;

    // 返回更新之后的pos指针,这里的pos指针是主函数的形参,必须返回更新主函数的pos实参
    return pos;
}

3.vector的完整实现

// vector.h
#pragma once
namespace qwy
{
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;             
        typedef const T* const_iterator; 

        // 普通迭代器
        iterator begin()
        {
            return _start;
        }

        iterator end()
        {
            return _finish;
        }

        // const迭代器
        const_iterator begin() const
        {
            return _start;
        }

        const_iterator end() const
        {
            return _finish;
        }

        // 普通重载operator[]
        T& operator[](size_t pos)
        {
            assert(pos < size());
            return _start[pos];
        }

        // const重载operator[]
        const T& operator[](size_t pos) const
        {
            assert(pos < size());
            return _start[pos];
        }

        // 默认构造函数
        vector()
        :_start(nullptr)
        , _finish(nullptr)
        , _endofstorage(nullptr)
        {}
        
        // n可以为负数(这种方法不建议)
        // vector<int> v1(10, 1);     // 10为int类型,1为int类型
        // vector<int> v1(10, 1) 匹配 vector(int n, const T& val = T())

        // size_t 不会有负数(建议使用这种构造方法)
        // vector<char> v1(10, 'A');  // 10为int类型,'A'为char类型
        // vector<char> v1(10, 'A') 匹配 vector(size_t n, const T& val = T())
        // int会发生整型提升,提升为size_t类型
        // 用n个val值来填充容器

        vector(int n, const T& val = T())
        :_start(nullptr)
        , _finish(nullptr)
        , _endofstorage(nullptr)
        {
            reserve(n);
            for (int i = 0; i < n; ++i)
            {
                push_back(val);
            }
        }

        vector(size_t n, const T& val = T())
        :_start(nullptr)
        , _finish(nullptr)
        , _endofstorage(nullptr)
        {
            reserve(n);
            for (size_t i = 0; i < n; ++i)
            {
                push_back(val);
            }
        }


        
        // 传统的拷贝构造的写法
        // v2(v1)
        /*
        vector(const vector<T>& v)
		:_start(nullptr)
		, _finish(nullptr)
		, _endofstorage(nullptr)
		{
			reserve(v.capacity());
			for (const auto& e : v)
			{
				push_back(e);
			}
		}*/


        // 现代写法的拷贝构造
        // v1(v2)
        template <class InputIterator>
        vector(InputIterator first, InputIterator last)
        :_start(nullptr)
        , _finish(nullptr)
        , _endofstorage(nullptr)
        {
            // 用迭代器的方法将v2的数据,一个一个插入到v1中
            while (first != last)
            {
                push_back(*first);
                ++first;
            }
        }

        vector(const vector<T>& v)
        :_start(nullptr)
        , _finish(nullptr)
        , _endofstorage(nullptr)
        {
            vector<T> tmp(v.begin(), v.end());   // 将v的数据拷贝到tmp
            swap(tmp);
        }



        // v1 = v2
        // v1 = v1;  // 极少数情况,能保证正确性,所以这里就这样写没什么问题
        vector<T>& operator=(vector<T> v)
        {
            swap(v);
            return *this;
        }


        // 析构函数
        ~vector()
        {
            delete[] _start;
            _start = _finish = _endofstorage = nullptr;
        }


        // 扩容
        void reserve(size_t n)
        {
            if (n > capacity())
            {
                // 此处必须将size()的返回值进行存储
                // 如果_start被改变,则size()的返回值也会被改变;(size()的返回值为_start与_finsh的差值)
                size_t oldSize = size();
                T* tmp = new T[n];

                if (_start)
                {
                    memcpy(tmp, _start, sizeof(T)*oldSize); // 将原空间的数据拷贝到新空间
                    delete[] _start;                        // 将原空间释放
                }

                _start = tmp;                 
                _finish = tmp + oldSize;
                _endofstorage = _start + n;
            }
        }

        // 设置数据个数的大小,并对其初始化
        void resize(size_t n, T val = T())
        {
            if (n > capacity())    // 如果n > capacity(),则需要先进行扩容
            {
                reserve(n);
            }

            if (n > size())
            {
                // size()位置到n位置的数据进行初始化;也就是对n-size()个数据初始化
                // 即n-(_finish - _start) > 0
                while (_finish < _start + n)    
                {
                    *_finish = val;
                    ++_finish;
                }
            }
            else
            {
                // 当n <= size()时,令 n == size()即可,也就是 n == _finish - _start
                _finish = _start + n;
            }
        }


        bool empty() const
        {
            return _finish == _start;
        }

        size_t size() const
        {
            return _finish - _start;
        }

        size_t capacity() const
        {
            // 指针-指针 = 两个指针之间元素的个数
            return _endofstorage - _start;
        }


        void push_back(const T& x)
        {
            if (_finish == _endofstorage)
            {
                size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
                reserve(newCapacity);
            }

            *_finish = x;
            ++_finish;
        }

        void pop_back()
        {
            assert(!empty());

            --_finish;
        }



        // 迭代器失效 : 扩容引起,野指针问题
        iterator insert(iterator pos, const T& val)
        {
            // pos只是形参; this->_start; this->_finish
            assert(pos >= _start);
            assert(pos < _finish);

            // 扩容
            if (_finish == _endofstorage)
            {
                size_t len = pos - _start;
                size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
                reserve(newCapacity);

                // 扩容之后,编译器可能会重新分配新的空间,pos还指向原来的空间(也就是野指针)
                // 扩容会导致pos迭代器失效,需要更新处理一下
                pos = _start + len;
            }

            // 挪动数据
            iterator end = _finish - 1;
            while (end >= pos)   
            {
                *(end + 1) = *end;
                --end;
            }

            *pos = val;
            ++_finish;

            return pos;
        }



        iterator erase(iterator pos)
        {
            assert(pos >= _start);
            assert(pos < _finish);


            iterator begin = pos+1;
            while (begin < _finish)
            {
                *(begin-1) = *(begin);
                ++begin;
            }

            --_finish;

            return pos;
        }



        void swap(vector<T>& v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endofstorage, v._endofstorage);
        }



        void clear()
        {
            _finish = _start;
        }



        private:
        iterator _start;        
        iterator _finish;         // _finish == _start + size()
        iterator _endofstorage;   // _endofstorage == _start + capacity()
    };
    
    

	void test_vector1()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);

		for (size_t i = 0; i < v.size(); ++i)
		{
			cout << v[i] << " ";
		}
		cout << endl;

		vector<int>::iterator it = v.begin();
		while (it != v.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;

		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		v.pop_back();
		v.pop_back();
		v.pop_back();
		v.pop_back();
		v.pop_back();

		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}
    
    

	void test_vector2()
	{
		vector<int> v;
		v.resize(10, -1);
        
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		v.resize(5);
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}
    
    

	void test_vector3()
	{
		vector<int> v;
		//v.reserve(10);
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);

		for (size_t i = 0; i < v.size(); ++i)
		{
			cout << v[i] << " ";
		}
		cout << endl;

		v.insert(v.begin(), 0);
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

        // 算法库中的find
        // template <class InputIterator, class T>
   		// InputIterator find (InputIterator first, InputIterator last, const T& val);
		vector<int>::iterator it = find(v.begin(), v.end(), 3);
		if (it != v.end())
		{
			v.insert(it, 30);
		}
        
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}
    
    

	void test_vector4()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);

        // 算法库中的find
		vector<int>::iterator it = find(v.begin(), v.end(), 3);
		if (it != v.end())
		{
			v.insert(it, 30);
		}

		// insert以后 it还能否继续使用 -- 不能,可能迭代器失效(野指针)
        // insert以后,实参it并不会发生改变,但是形参pos会发生改变;(形参改变并不会影响实参)
		// (*it)++;
		// *it *= 100;

		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}





    // 算法库实现的测试--> 最后发现程序崩溃了
    // 这是由于v.erase(it)调用之后, it就失效了;因此我们需要去更新it(即it = v.erase(it))
    void test_vector5()
    {
        std::vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);

        // it失效还是不失效?(这里一定会失效,具体原因详细看erase的模拟实现)
        std::vector<int>::iterator it = find(v.begin(), v.end(), 3);
        if (it != v.end())
        {
            v.erase(it);
        }

        // 读 (在vs下会失效)
        cout << *it << endl;
        // 写 (在vs下会失效)
        (*it)++;

        for (auto e : v)
        {
            cout << e << " ";
        }
        cout << endl;
    }



	// 算法库中实现的erase()的测试 
	//void test_vector6()
	//{
	//	// 要求删除所有偶数
	//	std::vector<int> v;
	//	v.push_back(1);
	//	v.push_back(2);
	//	v.push_back(2);
	//	v.push_back(3);
	//	v.push_back(4);

	//	std::vector<int>::iterator it = v.begin();
	//	while (it != v.end())
	//	{
	//		if (*it % 2 == 0)
	//		{
	//			it = v.erase(it);
	//		}
	//		else
	//		{
	//			++it;
	//		}
	//	}

	//	for (auto e : v)
	//	{
	//		cout << e << " ";
	//	}
	//	cout << endl;
	//}

	

    // 我们自己实现的erase()的测试
    void test_vector6()
    {
        // 要求删除所有偶数
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
        //v.push_back(5);


        vector<int>::iterator it = v.begin();
        while (it != v.end())
        {
            if (*it % 2 == 0)
            {
                // 这里更新it指针,那么pos就不会失效
                // erase(iterator pos)
                it = v.erase(it);
            }
            else
            {
                ++it;
            }		
        }

        for (auto e : v)
        {
            cout << e << " ";
        }
        cout << endl;
    }

	

	// 测试拷贝构造
	void test_vector7()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);

		vector<int> v1(v);

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		vector<int> v2;
		v2.push_back(10);
		v2.push_back(20);
		v1 = v2;
        
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

        
		v1 = v1;
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}



	
	void test_vector8()
	{
		std::string str("hello");

		vector<int> v(str.begin(), str.end());
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		//vector<int> v1(v.begin(), v.end());
		vector<int> v1(10, 1);
		//vector<char> v1(10, 'A');

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}


	
	// 测试杨辉三角
	// 杨辉三角的实现程序
	class Solution 
    {
	public:
		vector<vector<int>> generate(int numRows) 
        {
			vector<vector<int>> vv;
			vv.resize(numRows);
			for (size_t i = 0; i < vv.size(); ++i)
			{
				vv[i].resize(i + 1, 0);
				vv[i][0] = vv[i][vv[i].size() - 1] = 1;
			}

			for (size_t i = 0; i < vv.size(); ++i)
			{
				for (size_t j = 0; j < vv[i].size(); ++j)
				{
					if (vv[i][j] == 0)
					{
						vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
					}
				}
			}

			return vv;
		}
	};


	// 需要注意的问题如:void test_vector9()
	void test_vector10()
    {
        vector<string>	v;
        v.push_back("1111111111111111111111111111");
		v.push_back("1111111111111111111111111111");
		v.push_back("1111111111111111111111111111");
		v.push_back("1111111111111111111111111111");
		v.push_back("1111111111111111111111111111");
        
        
        for (auto& e : v)
		{
			cout << e << " ";
		}
		cout << endl;
          
    }

// 测试杨辉三角
	void test_vector9()
	{
        // 内部运行原理
        // vv的类型是vector<vector<int>>   给vv中插入5个v,v的类型是vector<int>
        // v中开辟5个空间,每个空间初始化为1
        // 根据我们写的底层原理,插入第5个数据的时候,程序会进行扩容
        // 扩容时会调用reserve()函数,如果reserve()函数中使用memcopy()来拷贝原空间的数据到扩容的新空间,但是这个新空间是vv的新空间,vv中的v指向的还是原来的空间,并没有给v开辟新空间,并将v的数据拷贝到新空间(v的指针:_start,_finish,_endofstorage是在vv中)
        // 拷贝数据之后,就会将v指向的原空间释放,但是没有给v开辟新空间,并将将数据拷贝
        // 解决方案:
        // 将memcopy()函数拷贝,替换为
        // for (size_t i = 0; i < oldSize; ++i)
		// {
		//  	tmp[i] = _start[i]; // 对应 vector<T>& operator=(vector<T> v)
		// }
        // 这样就可以将v的数据拷贝到新空间,原空间被释放,并不会对现在的v指向的空间有影响
		vector<vector<int>> vv;
		vector<int> v(5, 1);
		vv.push_back(v);
		vv.push_back(v);
		vv.push_back(v);
		vv.push_back(v);
		vv.push_back(v);

		for (size_t i = 0; i < vv.size(); ++i)
		{
			for (size_t j = 0; j < vv[i].size(); ++j)
			{
				cout << vv[i][j] << " ";
			}
			cout << endl;
		}
		cout << endl;
	}
}



// test.cpp
int main()
{
	try
	{
		bit::test_vector9();
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}

	return 0;
}

测试杨辉三角(使用自己的vector)

// 测试杨辉三角(下面的代码,使用我自己的vector容器会报错,具体原因如下,改进方式如下)
	void test_vector9()
	{
        // 内部运行原理
        // vv的类型是vector<vector<int>>   给vv中插入5个v,v的类型是vector<int>
        // v中开辟5个空间,每个空间初始化为1
        // 根据我们写的底层原理,插入第5个数据的时候,程序会进行扩容
        // 扩容时会调用reserve()函数,如果reserve()函数中使用memcopy()来拷贝原空间的数据到扩容的新空间,但是这个新空间是vv的新空间,vv中的v指向的还是原来的空间,并没有给v开辟新空间,并将v的数据拷贝到新空间(v的指针:_start,_finish,_endofstorage是在vv中)
        // 拷贝数据之后,就会将v指向的原空间释放,但是没有给v开辟新空间,并将将数据拷贝
        // 解决方案:
        // 将memcopy()函数拷贝,替换为
        // for (size_t i = 0; i < oldSize; ++i)
		// {
		//  	tmp[i] = _start[i]; // 对应 vector<T>& operator=(vector<T> v)
		// }
        // 这样就可以将v的数据拷贝到新空间,原空间被释放,并不会对现在的v指向的空间有影响
		vector<vector<int>> vv;
		vector<int> v(5, 1);
		vv.push_back(v);
		vv.push_back(v);
		vv.push_back(v);
		vv.push_back(v);
		vv.push_back(v);

		for (size_t i = 0; i < vv.size(); ++i)
		{
			for (size_t j = 0; j < vv[i].size(); ++j)
			{
				cout << vv[i][j] << " ";
			}
			cout << endl;
		}
		cout << endl;
	}
  • 33
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用和提供了关于实现vector的两种方法。其中,引用展示了一个使用reserve和push_back方法的示例,而引用展示了一个使用new和memcpy函数的示例。这两种方法都是常见的实现vector的方式。 在第一种方法中,通过reserve函数可以预留足够的内存空间,然后使用push_back函数逐个将元素添加到vector中。这种方法的好处是可以避免不必要的内存重分配,提高了效率。 而第二种方法使用new操作符在堆上分配内存空间,并使用memcpy函数将已有的vector对象的数据复制到新的内存空间中。通过这种方式,可以实现深拷贝,即两个vector对象拥有独立的内存空间。这种方法的好处是可以在不修改原始vector对象的情况下创建一个新的vector对象。 除了以上两种方法,还可以使用其他方式实现vector类。例如,可以使用动态数组来实现vector的底层数据结构,然后通过成员函数实现vector的各种操作,如增加、删除、查找等。 总结来说,c语言模拟实现vector的关键是动态内存管理和对元素的增删改查操作。可以使用预留空间和逐个添加元素的方式,也可以使用动态数组和复制数据的方式来实现vector类。具体的实现方式可以根据需求和实际情况选择。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++——vector模拟实现](https://blog.csdn.net/weixin_49449676/article/details/126813526)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值