程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++_系列自學課程_第_5_課_vector容器_《C++ Primer 第四版》,vector容器

C++_系列自學課程_第_5_課_vector容器_《C++ Primer 第四版》,vector容器

編輯:C++入門知識

C++_系列自學課程_第_5_課_vector容器_《C++ Primer 第四版》,vector容器


   再一次遇到 vector 這個單詞; 每一次見到這個單詞都感覺這個單詞非常的 "高大上"; 數字遇到vector馬上就可以360度旋轉;

當 "電" 遇到vector,馬上讓交流可以變得和直流一樣進行控制(德國電氣工程師的矢量控制理論,目前在工控界對電機控制應用

非常廣泛,是變頻器控制的基礎理論,可惜的是中國目前沒有這方面的真正的專家, 就是IT行業中的TI公司的TMS320LF24xx系列

DSP做的事,中國的基礎理論的研究真的是落後於西方發達國家很多年),而在C++中遇到這個單詞,同樣是高大上的感覺,馬上

讓我想起C語言中最復雜的部分指針; 別說指針的操作你無所謂, 就算你是C++、C#、Java的粉絲;沒有指針,個人感覺就像沒

有金箍棒的猴子, 幻刺模糊直接讓你子彈到處亂飛。

  不瞎扯啦,開始今天的內容。

一、vector

1、作用

  vector,從翻譯對應的詞語: 容器, 可以知道vector是用來裝東西的罐子、壇子之類的東西;聯系實際,壇壇罐罐可以用來裝各

種不同的東西, 可以用來盛酒, 也可以用來放酸菜(南北朝鮮的酸菜就算啦),當然你如果是土豪的話,也可以用來放鋼镚;如果你

是貪官的話,也可以用來藏你給情婦寫的保證書什麼的。

  從C++的角度來看,vector可以用來存放不同類型的對象,例如可以把int類型的對象存放到容器裡面,同樣也可以將char類型的

對象存儲到vector中,也可以將string對象存儲到vector裡面。

2、容器的定義

  vector類型是C++標准庫提供的一種類型,如果要在程序中引用這種類型,當然需要“報備”, 如下所示:

#include <vector>  //引用相關的頭文件
using std::vector;   //方便的使用std::命名空間/名字空間中的名字vector

  報備完成後就可以名正言順的經營啦;要使用 vector 必須指明容器裡面存放的是什麼類型的對象,就像在壇壇罐罐上面貼上標簽

告訴別人裡面存放的是什麼;通過在 vector後面加上 <> 然後將對象類型寫入到 <> 就可以啦, 如下所示:

vector<int> vInt;

  如上就定義了一個容器對象, 並且這個容器是用來存儲int類型的對象的。

   要點:尖括號裡面指出的是容器中存放的是什麼類型的對象; 同時要注意的是 vector<int>是一種數據類型,

   vector可以存儲的對象不僅可以是內置類型,還可以是用戶的自定義類型,例如string類。

vector<string>  vString;

  同樣 vector<string> 也是一種新的數據類型, 這種數據類型的對象用來存儲string對象。

 

3、容器的初始化

  標准庫提供的vector類型有多種初始化方式。

  A:  vector<T>   v1;   //容器對象v1保存類型為T的對象, 容器類型的默認構造函數初始化對象v1為空

   這樣定義的話,就是定義了一個容器,裡面沒有任何東西,就相當於一個空的壇子、罐子。

  B:  vector<T>   v2(v1);  //容器對象v2保存類型為T的對象, 對象v2初始化為與v1一樣的容器

  這樣定義的話,就表示開始的時候有一個罐子v1,然後又造了一個罐子v2,v2罐子是按照罐子v1為原型造的,如果v1裡面有東西

 那麼v2罐子裡面的東西與v1罐子一樣; 如果v1罐子裡面沒有東西,那麼v2罐子裡面也沒有東西。

  C:  vector<T>   v3(n, i);  //容器v3保存類型為T的對象, 對象初始化為保存n個類型為T、值為 i 的對象元素

  這樣定義的話,就表示下了一個明確訂單, 就是告訴你,你給我造一個罐子v3, 裡面放多少封(n)給情婦的保證書(i)。 

  D: vector<T>   v4(n);    //容器v4保存類型為T的對象, 容器對象v4中初始化裡面可以存放個數為n的T對象。 

  這樣的定義的話,就是下了一個明確的訂單, 你給某個貪官造個罐子v4, 這個罐子可以放多少(n)封給情婦的保證書, 但是你不能

放保證書,放保證書的事情讓貪官自己以後放。

Exp:

[root@localhost cpp_src]# cat test.cpp 
#include <iostream>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    vector<int> vInt1;
    vector<int> vInt2(vInt1);
    vector<int> vInt3(3,4);
    vector<int> vInt4(5);

    string str("volcanol");
    vector<string> vStr1;
    vector<string> vStr2(vStr1);
    vector<string> vStr3(4,str);
    vector<string> vStr4(5);

    return 0;
}

  這裡需要注意的是, 對於存儲string對象容器,可以用字符串字面值進行初始化, 如下所示:

vector<string>  str(4, "volcanol");

 

4、容器元素的值的初始化

  一定要分辨清楚容器的初始化和容器元素的值的初始化兩個概念, 容器的初始化可以包括兩個方面:容器本身的初始化

以及容器元素的值的初始化。

  這裡就細細的說一下這兩個的不同之處。

  A:   vector<int>  vInt;     這裡對容器對象vInt進行初始化,初始化後知道對象vInt是一個空的對象,裡面暫時不能存

放任何int對象, 就是說這個壇子是一個實心的壇子,不能往裡面塞東西。

  B:vector<int>  vInt1(2, 10);  這裡不但對容器對象vInt1進行了初始化,同時還對容器對象裡面的元素進行了初始化,

就是說容器裡面存放了兩個int類型的對象,且兩個int對象的值均為10.  用壇壇罐罐來比喻就是罐子裡面放了2個(初始化的是容器)

10元的鋼镚(初始化的是容器裡面的鋼镚的大小)。

  C:  vector<int> vInt2(10);  這裡對容器vInt2進行了初始化,而且在容器裡面目前可以放10個int對象,而且這些int對象

的值為0。  用壇壇罐罐來比喻的話就是罐子裡面放了10個面值為0元的鋼镚。

 

  要點:  

  如果容器存放的對象類型為內置類型,且沒有提供容器元素的初始化值,那麼就會初始化容器的元素值為0.

例如:

    vector<char>  vCh(1);   那麼容器vCh裡面就有一個元素之為'\0'的的char對象。

  如果容器存放的對象是類類型,且沒有提供容器元素的初始化值,那麼容器元素就會用類類型默認構造函數對容器的

元素進行初始化。

例如:

    vector<string>  vStr(2);  那麼容器vStr裡面就存放了兩個值為空""字符串的string對象。

  如果容器存放的對象是類類型,同時類類型沒有默認構造函數,且沒有提供元素的初始化值, 那麼標准庫同樣會產生

一個帶初始值的對象,這個對象的每個成員都進行了初始化。(這個地方說的有點不明不白,我也是每天搞明白,有哪位大俠了

解的話,請不吝賜教)。

 

5、vector提供的操作

  vector類提供了類似於string類的操作。

    v.empty();  檢測對象v是否為空

    v.size();  返回對象v中的元素的個數

    v.push_back(t);  往對象v中插入一個值為(t)新的元素, 這個就是動態的增加容器對象的容量,

    v[n];  訪問容器中的元素, 相當於string對象的下標操作,而且容器對象下標操作符返回的是一個左值,可以進行寫入操作。

    v1 = v2;  容器的賦值操作, 就是將容器對象v1的元素替換為v2中元素的副本,(這需要注意容器的大小)

    v1 == v2; 如果容器v1與v2相等,那麼就返回true, 這裡包括容器本身以及容器中的元素,這個必須要注意。  

     >, >=, != ,  <, <= 這些操作保持原本的意義。

Exp1:size() 和 empty()操作

[root@localhost cpp_src]# cat test.cpp 
#include <iostream>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    vector<int> vInt1;
    vector<int> vInt2(vInt1);
    vector<int> vInt3(3,4);
    vector<int> vInt4(5);

    cout<<"the size of vector<int> vInt1 is:"<<vInt1.size()<<endl;
    if(vInt1.empty())
        cout<<"vector<int> vInt1 is empty"<<endl;
    else
        cout<<"vector<int vInt1> is not empty"<<endl;

    return 0;
}

執行結果如下所示:

[root@localhost cpp_src]# g++ test.cpp 
[root@localhost cpp_src]# ./a.out 
the size of vector<int> vInt1 is:0
vector<int> vInt1 is empty

 

Exp: push_back()操作

[root@localhost cpp_src]# cat test.cpp 
#include <iostream>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    vector<int> vInt1;

    cout<<"the size of vector<int> vInt1 is:"<<vInt1.size()<<endl;
    if(vInt1.empty())
        cout<<"vector<int> vInt1 is empty"<<endl;
    else
        cout<<"vector<int vInt1> is not empty"<<endl;
    
    vInt1.push_back(1);
    cout<<"The size of vector<int> vInt1 is:"<<vInt1.size()<<endl;
    if(vInt1.empty())
        cout<<"vector<int> vInt1 is empty"<<endl;
    else
        cout<<"vector<int> vInt1 is not empty"<<endl;

    return 0;
}

執行結果如下:

[root@localhost cpp_src]# ./a.out 
the size of vector<int> vInt1 is:0
vector<int> vInt1 is empty
The size of vector<int> vInt1 is:1
vector<int> vInt1 is not empty

  可以發現執行 vInt1.push_back(1); 以後vInt的大小變成了1,而且不再是空的容器。

 

Exp:  容器的下標操作

  容器的下標操作返回的是容器裡面的元素,這個要特別的注意。

[root@localhost cpp_src]# cat test.cpp 
#include <iostream>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    vector<int> vInt1;
    
    for(vector<int>::size_type i=0;i != 10; i++)
        vInt1.push_back(i);

    for(vector<int>::size_type i=0; i != vInt1.size(); i++)
        cout<<vInt1[i]<<endl;

    return 0;
}

執行結果如下:

[root@localhost cpp_src]# g++ test.cpp 
[root@localhost cpp_src]# ./a.out 
0
1
2
3
4
5
6
7
8
9

  要點:  容器的下標是從0開始計算的,   其最大值為  v.size( ) - 1;  所以上面的第二個循環可以正常執行,

當i=9的時候, i  != vInt1.size( ),因此可以進行循環;

      而當i=10 的時候,i == vInt1.size(),  for循環的條件不成立,因此跳出循環,不會產生下標越界。

  vector<int>::size_type 類型為標准庫為vector類型定義的表示vector大小的類型, 在使用這個數據類型的

時候對象的類型 int 不能少,否則就會出錯, 這個地方經常會被遺忘。  

 

Exp: 下標操作的賦值

  

[root@localhost cpp_src]# cat test.cpp 
#include <iostream>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    vector<int> vInt1(10);

    for(vector<int>::size_type i = 0; i != vInt1.size(); i++)
        vInt1[i]=i;
    
    for(vector<int>::size_type i=0; i != vInt1.size(); i++)
        cout<<vInt1[i]<<endl;

    cout<<"the size of vInt1 is: "<<vInt1.size()<<endl;
    return 0;
}

程序執行的結果是:

[root@localhost cpp_src]# ./a.out 
0
1
2
3
4
5
6
7
8
9
the size of vInt1 is: 10

  要點:  vector下標操作返回的是容器裡面存放的對象, 是一個左值。 

 

二、 迭代器  iterator

  C++標注庫為訪問vector提供了另外的一種機制,這個機制就是迭代器。

1、作用

  迭代器的作用就是用來訪問容器中的元素。

2、迭代器的定義

  每一種類型的vector類型都定義了自己的迭代器類型,定義一個迭代器的語法如下所示:

    vector<T>::iterator  tIter;

  這樣就定義了一個用於容器類型為 vector<T>的迭代器對象   tIter; tIter的數據類型是 vector<T>::iterator,

在C++中可以通過迭代器來訪問容器裡面的元素。

  默認定義通過上面的定義 tIter 將指向容器中的第一個元素,如果容器不為空的話。

 

  迭代器的概念與C語言中的指針非常類似,都有一個指向的概念,但是要嚴格區分兩者的區別。

 

3、迭代器的begin和end操作

  每一種標准庫定義的容器都定義了兩個操作:  begin() 和 end() 操作。 begin()操作返回的迭代器指向的容器中的

第一個元素, 而end()操作則返回迭代器指向的容器中最後一個元素後面的一個位置, 通常稱為 超出末端迭代器, 表明指向了一個

不存在的元素; 如果容器為空,那麼迭代器的begin() 和end()操作將指向同一個位置---超出末端迭代器的位置。

 

4、迭代器的解引用和自增操作

  通過迭代器的解引用操作可以和下標操作符一樣操作容器中的元素。

  例如:

      vector<int> vInt(3);

      vector<int>::iterator iter=vInt.begin( );   //迭代器指向 vInt容器中的第一個元素,vInt容器中一共有3個元素。

      *iter = 10;  ====》相當於  vInt[0]  = 10;

  通過移動迭代器的指向,可以訪問容器中不同的元素。可以通過自增運算符來移動迭代器的指向。  

      vector<int> vInt(3);

      vector<int>::iterator iter=vInt.begin( );   //迭代器指向 vInt容器中的第一個元素,vInt容器中一共有3個元素。

      *iter = 10;  ====》相當於  vInt[0]  = 10;

         ++ iter ;

      *iter = 5;  =====>>相當於 vInt[1] = 5;

      ++ iter ;

      *iter = 1 ;  =====>>相當於  vInt[2] = 1;

       iter = vInt.begin();    =====》相當於將迭代器再次指向容器中的第一個元素,

       * iter = 3 ;  ======》 相當於vInt[0] = 3;

Exp:

[root@localhost cpp_src]# cat test.cpp 
#include <iostream>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    vector<string> vStr(3);

    vector<string>::iterator iter=vStr.begin();

    while(iter != vStr.end())
    {
        cin>>*iter;
        ++iter;
    }

    iter=vStr.begin();
    while(iter != vStr.end())
    {
        cout<<*iter<<endl;
        ++iter;
    }

    return 0;
}

程序執行結果如下:

[root@localhost cpp_src]# ./a.out 
abd 121 456
abd
121
456

再次執行結果如下:

[root@localhost cpp_src]# ./a.out 
volcanol hello world  hi
volcanol
hello
world

 

5、迭代器的比較操作

  可以測試兩個迭代器是否指向容器中的同一個元素,測試用的操作符為:== 和 != 。

exp:

[root@localhost cpp_src]# cat test.cpp 
#include <iostream>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    vector<string> vStr(3);

    vector<string>::iterator iter1=vStr.begin();
    vector<string>::iterator iter2=vStr.end();

    if(iter1 == iter2)
        cout<<"iter1 and iter2 point to the same element"<<endl;
    else
        cout<<"iter1 and iter2 don't point to the same element "<<endl;

    ++iter1;
    ++iter1;
    ++iter1;

    cout<<"after iter1 moved:";
    if(iter1 != iter2)
        cout<<"iter1 and iter2 don't point to the same element"<<endl;
    else
        cout<<"iter1 and iter2 point to the same element"<<endl;


    return 0;
}

程序執行結果為:

[root@localhost cpp_src]# ./a.out 
iter1 and iter2 don't point to the same element 
after iter1 moved:iter1 and iter2 point to the same element

 

6、利用迭代器循環遍歷容器中的元素

  前面我們利用下標操作符和 v.size()操作遍歷了整個容器的元素,現在我們利用迭代器遍歷容器。

[root@localhost cpp_src]# cat test.cpp 
#include <iostream>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    vector<string> vStr(3);
    vector<string>::iterator iter=vStr.begin();


    for(vector<string>::size_type i=0; i !=vStr.size();i++)
    {
        cin>>vStr[i];
    }

    while(iter != vStr.end())
    {
        cout<<*iter<<endl;
        ++iter;
    }


    return 0;
}

執行結果如如下所示:

[root@localhost cpp_src]# g++ test.cpp 
[root@localhost cpp_src]# ./a.out 
kiki gaida volcanol hi world
kiki
gaida
volcanol

 

7、const_iterator  和 const vector<T>::iterator 

     看到這個題頭,就會想起C語言中指針和const的結合。

  const_iterator的迭代器不能用來改變容器中元素的值,而 const vector<T>::iteraor則不能改變指向。

例如:

  vector<int> vInt(3, 10);

  vector<int>::const_iterator iter1= vInt.begin();

  *iter1 = 5 ;  //錯誤,不能通過const_iterator迭代器改變容器中元素的值。

  ++iter;  //正確,可以改變迭代器的指向。

 

而下面的情形是:

  vector<string>  vStr(3,"hi");

  const vector<string>::iterator  iter2=vStr.begin();

  *iter2 = "volcanol";  //正確,可以通過迭代器的解引用操作符來操作容器中的元素。

  iter2 =vStr.end() ;  //錯誤,  const 迭代器的指向不能改變。

 

而下面的情形是:

  const vector<int>  vInt(5,1);

     vector<int>::iterator  iter=vInt.begin();    //錯誤,不能這樣定義

exp:

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 
 5 using std::cin;
 6 using std::cout;
 7 using std::endl;
 8 using std::string;
 9 using std::vector;
10 
11 int main()
12 {
13     const vector<int> vInt(3); //ok,vInt[i]=0;
14     cout<<vInt[0]<<endl;
15 
16     vector<int>::iterator iter=vInt.begin();
17     *iter = 10; 
18     cout<<vInt[0]<<endl;
19 
20     return 0;
21 }

編譯的時候提示:

[root@localhost cpp_src]# g++ test.cpp 
test.cpp: In function ‘int main()’:
test.cpp:16: 錯誤:請求從 ‘__gnu_cxx::__normal_iterator<const int*, std::vector<int, std::allocator<int> > >’ 轉換到非標量類型 ‘__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >’

  提示16行錯誤。

 

而下面的情形是:

  vector<int>  vInt(10,1);

  const vector<int>::const_iterator  iter=vInt.begin();  //正確,這樣可以定義

這個地方需要注意, 第一個const指出的是 iter的指向不能改變, 第二個const_iterator 指出不能通過 *iter 改變容器中

元素的值。

 

要點:

  const修飾時迭代器和類型和容器內元素的類型要一致,如果元素不可改變,那麼就不能定義可以改變容器元素的迭代器來

訪問容器中的元素。

 

8、迭代器支持算術運算

  可以給迭代器進行 +n 和-n 的操作,就和C語言中的指針的加法、減法運算類似。

[root@localhost cpp_src]# cat test.cpp 
#include <iostream>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    vector<int> vInt(10);
    vector<int>::iterator iter=vInt.begin();

    for(;iter != vInt.end(); ++iter)
        cin>>*iter;

    iter=vInt.begin();
    iter = iter + vInt.size()/2;
    cout<<*iter<<endl;

    iter = iter - 2;
    cout<<*iter<<endl;


    return 0;
}

執行結果如下所示:

[root@localhost cpp_src]# g++ test.cpp 
[root@localhost cpp_src]# ./a.out  
1 2 3 4 5 6 7 8 9 10 11
6
4

 

 

  今天關於vector和迭代器就描述到這裡,後續內容,未完待續..........................


容器(vector)與指針(ptr)的不同

既然你選擇使用C++ 就應該熟練使用它的STL。
STL是C++非常寶貴的一部分,提供了許多對C的優化。
就像你這裡說的vector和指針。
vector就安全得多,並且提供了很多方便的操作;
使用vector不僅你會出錯更少,並且很多煩瑣的代碼你都不用編寫,它都是vector自帶的。
 

int類型的vector容器應該使用什類型的索引?C++Primer第四版 習題

vector<int> intarrary
vector<int>::iterator m_iter
要使用索引你可以使用map,索引整型,字符串都行
map<int,intarrary> map_arrary
map<string,intarrary> map_arrary
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved