9

C++语言STL标准容器类Vector的基本使用

 3 years ago
source link: https://blog.popkx.com/basic-use-of-vector-of-STL-in-C/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在C语言程序开发中,若是遇到了不能确定长度的数据类型结构,链表常常是一个不错的选择,但是C语言并未提供原生的链表结构,程序员不得不自己设计一套链表管理机制。虽说开源社区也提供了不少好用的通用设计,但毕竟不是C语言原生的语法,统一性有所欠缺。C++大概是察觉到了这一点,提供了一些不错的模板类,例如 STL 中的 Vector 就是一个很好用的模板类。

怎样定义 Vector?

C++语言中的 Vector 是一个动态的序列容器,随着元素的插入删除,它的 size 会自动的改变。Vector 在内存分布上有些类似于数组,其内部存储的元素是连续存储的,因此可以像数组那样通过下标访问各个元素。

Vector 属于标准命名空间 std,使用它需要包含头文件<vector>

#include <vector>

然后便可定义 vector 对象了,因为 vector 是一个模板类,因此在定义对象时,应指明数据结构,例如:

std::vector<int> myvec;

上面这行C++语言代码便定义了一个 int 类型的 vector 对象 myvec,因此 myvec 可以存储若干 int 类型的数据。

初始化 Vector

在C++11标准之后,初始化 vector 可以在定义时直接执行,例如下面这段C++语言代码:

#include <vector>

int main()
{
    std::vector<int> myvec = {1, 1, 2, 3, 5};
    return 0;
}

在上面这段代码中,我们定义了一个 vector 对象 myvec,并在其中存储了 5 个 int 型的元素,按照前面讨论的,vector 容器内部的元素在内存上是连续的,因此此时 myvec 的内存模型大致如下,请看:

myvec 的内存模型

myvec 的内存模型

此时的 myvec 看起来和数组没什么两样,但是数组的长度一旦确定下来,就不能再改变了,而 vector 却可以根据实际需要动态的改变长度,此时 vector 又有些像“链表”。。

Vector 的迭代器

前面几节讨论其他几种STL容器时,都提到了相应的迭代器,vector 容器类也不例外,它也有这些通用的设计,通过迭代器,我们能够轻易的访问容器中的各个元素。

  • begin:返回指向vector中第一个元素的迭代器指针。
  • end:返回最后一个元素接下来位置(也即结束位置)的迭代器指针。
  • rbegin 和 rend:类似于 begin 和 end,只不过是反向(reverse)的
  • cbegin 和 cend:类似于 begin 和 end,只不过返回的迭代器指针是只读的(const)。
  • crbegin 和 crend:前缀 cr 分别是 reverse 和 const。

下面是一段使用这几个迭代器的C++语言代码示例,请看:

#include <iostream>
#include <vector>
using namespace std;
int main()
{ 
    vector<int> v1;
    
    for (int i = 1; i <= 5; i++)
       v1.push_back(i+1);
    
       cout << "Output of Vector with begin and end: ";
    for (auto i = v1.begin(); i != v1.end(); ++i)
       cout << *i << " ";
    
       cout << "\nOutput of Vector with rbegin and rend: ";
    for (auto itr = v1.rbegin(); itr != v1.rend(); ++itr)
       cout << *itr << " ";
    
       cout << "\nOutput Vector of with cbegin and cend: ";
    for (auto itc = v1.cbegin(); itc != v1.cend(); ++itc)
       cout << *itc << " ";
    
       cout << "\nOutput Vector of with crbegin and crend : ";
    for (auto icr = v1.crbegin(); icr != v1.crend(); ++icr)
       cout << *icr << " ";
   
    return 0;
}

编译这段C++语言代码时记得指定-std=c++11选项,执行编译后的程序,得到如下输出:

# g++ t2.cpp -std=c++11
# ./a.out 
Output of Vector with begin and end: 2 3 4 5 6 
Output of Vector with rbegin and rend: 6 5 4 3 2 
Output Vector of with cbegin and cend: 2 3 4 5 6 
Output Vector of with crbegin and crend : 6 5 4 3 2

上述C++语言代码定义了一个 vector 对象并使用 push_back() 函数插入了若干元素,接着,我们使用了每一个迭代器函数遍历了 vector 容器中的各个元素,结合前文的解释,输出应该很好理解。

vector 元素排序

vector 容器中的元素顺序和它们被插入的顺序是一致的,不过得到一个排序后的元素序列是常有的需求,此时可使用 sort() 函数,例如下面这段C++语言代码示例:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
 {
   vector<int> myvec = {10,50,30,20,60,40};
 
   cout<<"Original Vector"<<endl;
   for(auto i=myvec.begin();i<myvec.end();++i)
      {
        cout<<*i<<" ";
      }
   cout<<endl;
 
   sort(myvec.begin(),myvec.end());
 
   cout<<"Sorted Vector"<<endl;
   for(auto i=myvec.begin();i<myvec.end();++i)
      {
        cout<<*i<<" ";
      }
   cout<<endl;

   return 0;
}

编译并执行之,得到如下输出:

# g++ t3.cpp -std=c++11
# ./a.out 
Original Vector
10 50 30 20 60 40 
Sorted Vector
10 20 30 40 50 60

sort() 函数本身是一个位于 std 命名空间的模板函数,它的部分代码如下图所示:

sort() 函数的部分代码

sort() 函数的部分代码

可见,sort() 函数接收两个迭代器指针,它会将两个迭代器之间的元素排序。并且通过注释能够看出,sort() 函数排序的基本判断是 *(i+1)<*i,程序员应自己把握这一点。

vector 的容量

成员函数 size() 可以返回当前 vector 容器内部存储的元素个数,按照前文讨论的,vector 容器类对象可以像数组那样访问元素,二者结合使用也是非常顺手的操作,例如下面这段C++语言代码示例:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int> myvec = {1, 1, 2, 3, 5, 8};
    cout << "Vector Size : " << myvec.size() << endl;
    
    for (size_t i=0; i<myvec.size(); i++)
        cout << myvec[i] << " ";
    cout << endl;

    return 0;
}

编译这段代码并执行,得到如下输出:

# g++ t4.cpp -std=c++11
# ./a.out 
Vector Size : 6
1 1 2 3 5 8

这么看来,将元素插入到 vector 容器的随机位置也是极其方便的,只需要指定下标就可以了:

myvec[random] = val;

但是这么做要确保 random 的值不超过 myvec.size(),否则就会导致错误。幸好C++语言中的 vector 提供了 resize() 函数,它可以将 vector 的容量也即 myvec.size() 改变到期望大小,下面是一段C++语言代码示例:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int> myvec;
    myvec.resize(4);
    cout << "\nVector Size after resize: " << myvec.size();
    for (size_t i=0; i<myvec.size(); i++)
        myvec[i] = i*3;

    cout << "\nVector elements are: ";
    for (auto it = myvec.begin(); it != myvec.end(); it++)
        cout << *it << " ";
    cout << endl;
    
    return 0;
}

编译并执行这段代码,得到如下输出:

# g++ t5.cpp -std=c++11
# ./a.out 

Vector Size after resize: 4
Vector elements are: 0 3 6 9

类似于其他 STL 容器类,vector 也提供了 erase() 函数用于删除指定的元素。erase() 函数接收一个迭代器指针参数,用于指定被删除元素的位置,因此期望删除第 i 个元素的C++语言代码可以是下面这样的:

myvec.erase(myvec.begin() +i);

下面是一段完整的C++语言代码示例,请看:

#include <iostream>
#include <vector>
using namespace std;
 
int main()
{
    // Initialize vector
    vector<int> myvec = {1,1,2,3,5};
    cout << "\nVector elements:";
    for (int i = 0; i < myvec.size(); i++)
        cout << myvec[i] << " ";

    // remove the first element
    myvec.erase(myvec.begin());
    cout<<"\nVector size after erase: "<<myvec.size();

    cout << "\nVector after erase operation: ";
    for (int i = 0; i < myvec.size(); i++)
        cout<<myvec[i]<<" " ;
    cout << endl;

    return 0;
}

编译并执行这段C++语言代码,可以得到如下输出,请看:

# g++ t6.cpp -std=c++11
# ./a.out 

Vector elements:1 1 2 3 5 
Vector size after erase: 4
Vector after erase operation: 1 2 3 5 

另外一个需要说明的 vector 容器类的成员是 clear() 函数,它可以将容器内部的所有元素都删除:

myvec.clear();

因此要慎重使用 clear() 函数。

C++语言中的 vector 容器类还提供了 insert() 函数用于插入元素到指定位置,下面是一段C++语言代码示例,请看:

#include <iostream>
#include <vector>
using namespace std;
 
int main()
{
    // Assign vector
    vector<int> myvec = {2,3,4};
    
    cout << "\nInitial vector: ";
    for (int i = 0; i < myvec.size(); i++)
        cout << myvec[i] << " ";
    
    // inserts 20 at the beginning, 30 after that
    myvec.insert(myvec.begin(), 20);
    myvec.insert(myvec.begin()+1,30);
    cout << "\nNew vector after insert: ";
    for (int i = 0; i < myvec.size(); i++)
        cout << myvec[i] << " ";
    cout << endl;

    return 0;
}

编译并执行这段C++语言代码,可以得到如下输出,请看:

# g++ t7.cpp -std=c++11
# ./a.out 

Initial vector: 2 3 4 
New vector after insert: 20 30 2 3 4

程序一开始定义了 vector 对象 myvec,并且给了 3 个初值,稍后使用 insert() 函数将 20 和 30 两个元素插入到容器开头,结合借助于下标的随机访问,应该能够发现 vector 是一个非常好用的容器类。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK