前言
本期看看这位熟悉又陌生的朋友——vector。
博主水平有限,不足之处望请斧正!
是什么
vecotr是序列容器,可变大小的数组。
*vector有矢量、向量的意思,用其命名可能想强调“序列”这个概念。
class template
std::vector
 
template < class T, class Alloc = allocator<T> > class vector; // generic template
*Alloc是空间配置器(内存池),后面讲。
怎么用
有了数据结构顺序表的基础加上string的接口使用,vector的接口基本一看就懂了。CPP文档
遍历
void t1()
{
    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;
}
1 2 3 4 
1 2 3 4 
1 2 3 4
按这个说法……vector<char> 和 string不是一样吗?
还是没法划等号的:
- string的结尾是\0。
- 因意义不同,接口也有差异。
迭代器构造
void t2()
{
    vector<int> v1;
    v1.resize(10, 1);
    
    for(auto e : v1) cout << e << ' ';
    cout << endl;
    
    vector<int> v2(v1.begin() + 1, v1.end() - 1);
    for(auto e : v2) cout << e << ' ';
    cout << endl;
}
1 1 1 1 1 1 1 1 1 1 
1 1 1 1 1 1 1 1
需要注意,迭代器都是左闭右开的。
reserve
 
void t3()
{
    vector<int> v;
    
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    cout << v.capacity() << endl;
    
    v.reserve(10);
    cout << v.capacity() << endl;
    
    v.reserve(4);
    cout << v.capacity() << endl;
    
}
resrve仍然是不缩容的。缩容是有代价的,没法原地缩,只能异地开辟、拷贝、释放(涉及到内存管理)。这可以理解成是一种空间换时间。
resize
 
缩容 / 扩容并初始化(需要可以填数据)
void t4()
{
    vector<int> v;
    v.resize(20, 3);
    
    for(auto e : v) cout << e << ' ';
    cout << endl;
}
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
resize 和 reserve
 
一疏忽就容易用混
void t5()
{
    vector<int> v;
    v.reserve(10); //size没变
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    for(size_t i = 0; i < 10; ++i) v[i] = i;
    
    for(size_t i = 0; i < 10; ++i) cout << v[i] << ' ';
    
    cout << endl;
    
}

断言原因:[]内根据size判断是否越界。
正常情况下resize好用些。
assert
 
assert也是有缺点的,在release版本下会失效。不过都到release这一步了,程序基本没什么触发断言的地方了。
#内置类型的构造函数
看看resize
void resize (size_type n, value_type val = value_type());
size_type = unsigned int
value_type = The first template parameter
val的缺省值给了一个匿名对象,当模版参数绑定的是int,不就等于内置类型也有构造函数了?
是的,
void t6()
{
    int a = int();
    int b = int(10);
    cout << a << endl;
    cout << b << endl;
}
0 //默认初始化为0
10
而且这是有意义的,如果缺省值给了个0,自定义类型就照顾不到了,你0不一定能赋给自定义类型,所以
内置类型也有构造函数。
#vector的扩容机制
void t7()
{
    vector<int> v;
    size_t size;
    size = v.capacity();
    cout << "vector growing...\n" << endl;
    for (int i = 0; i < 100; ++i)
    {
        v.push_back(i);
        if (size != v.capacity())
        {
            cout << "capacity changed to " << v.capacity() << endl;
            size = v.capacity();
        }
    }
}
vs2019下:1.5x
vector growing...
capacity changed to 1
capacity changed to 2
capacity changed to 3
capacity changed to 4
capacity changed to 6
capacity changed to 9
capacity changed to 13
capacity changed to 19
capacity changed to 28
capacity changed to 42
capacity changed to 63
capacity changed to 94
capacity changed to 141
g++:2x(2倍左右比较合适,往下太少导致频繁扩容;往上太多用不完浪费)
vector growing...
capacity changed to 1
capacity changed to 2
capacity changed to 4
capacity changed to 8
capacity changed to 16
capacity changed to 32
capacity changed to 64
capacity changed to 128
提前开空间,可以避免扩容
void t7()
{
    vector<int> v;
    v.reserve(100);
    size_t size;
    size = v.capacity();
    cout << "vector growing..." << endl;
    for (int i = 0; i < 100; ++i)
    {
        v.push_back(i);
        if (size != v.capacity())
        {
            cout << "capacity changed to " << v.capacity() << endl;
            size = v.capacity();
        }
    }
}
vector growing...
find
 
void t8()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    
    vector<int>::iterator it = find(v.begin(), v.end(), 3);
    if(it != v.end())
        v.insert(it, 5);
    
    for(auto e : v) cout << e << ' ';
    cout << endl;
}
1 2 5 3 4
需要注意,vector没有find。因为有迭代器,find只需要用迭代器遍历找就行,所以实现一个放进<algorithm>最方便,每个容器都能用。
swap
 
//1.成员函数
void swap (vector& x);
//2.非成员函数
template <class T, class Alloc>
  void swap (vector<T,Alloc>& x, vector<T,Alloc>& y);
大佬真是用心良苦,怕我们用错成 swap(v1, v2),还专门写了个非成员函数的swap给咱用。就算写错,也不会走算法库的深拷贝,而是走这个更匹配的。
使用方面,能讲的大概也就这些了,和string非常像。
OJ练手
1. 只出现一次的数字
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 1 :
输入:nums = [2,2,1]
输出:1
示例 2 :
输入:nums = [4,1,2,1,2]
输出:4
示例 3 :
输入:nums = [1]
输出:1
提示:
- 1 <= nums.length <= 3 * 104
- -3 * 104 <= nums[i] <= 3 * 104
- 除了某个元素只出现一次以外,其余每个元素均出现两次。
思路和算法:
将vector内的数异或起来,每个位上,相同的会抵消,不同的会留下,最终ret的32位由“不同的”组成
class Solution {
public:
    int singleNumber(vector<int>& nums) 
    {
        int ret = 0;
        for(auto e : nums) ret ^= e; //相同抵消
        return ret;
    }
};
2. 杨辉三角
给定一个非负整数 *numRows,*生成「杨辉三角」的前 numRows 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。

示例 1:
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
示例 2:
输入: numRows = 1
输出: [[1]]
提示:
- 1 <= numRows <= 30
思路和算法:
杨辉三角的第n行有n个元素,除去第一个和最后一个,每一个都是上一行的元素 + 上一行左边的元素
1
1 1
1 2 1
1 3 3 1
杨辉三角:vv[i][j] = vv[i-1][j-1] + vv[i-1][j]
class Solution {
public:
    vector<vector<int>> generate(int numRows) 
    {
        //构造二维数组
        vector<vector<int>> vv;
        vv.resize(numRows); //vv含numRows个vector<int>
        for(int i = 0; i < numRows; ++i) 
        {
            vv[i].resize(i+1); //每一行含i+1个int
            // vv[i][0] = vv[i][vv[i].size() - 1] = 1;
            vv[i].front() = vv[i].back() = 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-1] + vv[i-1][j];
            }
        }
        return vv;
    }
};
今天的分享就到这里了
这里是培根的blog,期待与你共同进步!
下期见~






![【WSL】[01] windows subsytem linux 配置和使用 - ubuntu GUI安装](https://img-blog.csdnimg.cn/d92b42e3f789407289d57d08aa2ce5a4.png)












