歡迎訪問https://blog.csdn.net/lxt_Lucia~~
宇宙第一小仙女\(^o^)/~~萌量爆表求帶飛=≡Σ((( つ^o^)つ~ dalao們點個關注唄~~
摘要
最近學了map,set,auto,decltype,pair,vector等,有點瑣碎, 現在放在一起來總結一下,方便理解和以後查找,也方便大家查閱 ~
Come on!!!
Come on!!!
Come on!!!
Map常見用法說明
C++中map提供的是一種鍵值對容器,裏面的數據都是成對出現的,如下圖:每一對中的第一個值稱之爲關鍵字(key),每個關鍵字只能在map中出現一次;第二個稱之爲該關鍵字的對應值。
——————————————————————————————————————————————
一. 聲明
#include<map>//頭文件
map<int, string> ID_Name;
// 使用{}賦值是從c++11開始的,因此編譯器版本過低時會報錯,如visual studio 2012
map<int, string> ID_Name =
{
{ 2015, "Jim" },
{ 2016, "Tom" },
{ 2017, "Bob" }
};
——————————————————————————————————————————————
二. 插入操作
2.1 使用[ ]進行單個插入
map<int, string> ID_Name;
// 如果已經存在鍵值2015,則會作賦值修改操作,如果沒有則插入
ID_Name[2015] = "Tom";
2.1 使用insert進行單個和多個插入
insert共有4個重載函數:
// 插入單個鍵值對,並返回插入位置和成功標誌,插入位置已經存在值時,插入失敗
pair<iterator,bool> insert (const value_type& val);
//在指定位置插入,在不同位置插入效率是不一樣的,因爲涉及到重排
iterator insert (const_iterator position, const value_type& val);
// 插入多個
void insert (InputIterator first, InputIterator last);
//c++11開始支持,使用列表插入多個
void insert (initializer_list<value_type> il);
下面是具體使用示例:
#include <iostream>
#include <map>
int main()
{
std::map<char, int> mymap;
// 插入單個值
mymap.insert(std::pair<char, int>('a', 100));
mymap.insert(std::pair<char, int>('z', 200));
//返回插入位置以及是否插入成功
std::pair<std::map<char, int>::iterator, bool> ret;
ret = mymap.insert(std::pair<char, int>('z', 500));
if (ret.second == false)
{
std::cout << "element 'z' already existed";
std::cout << " with a value of " << ret.first->second << '\n';
}
//指定位置插入
std::map<char, int>::iterator it = mymap.begin();
mymap.insert(it, std::pair<char, int>('b', 300)); //效率更高
mymap.insert(it, std::pair<char, int>('c', 400)); //效率非最高
//範圍多值插入
std::map<char, int> anothermap;
anothermap.insert(mymap.begin(), mymap.find('c'));
// 列表形式插入
anothermap.insert({ { 'd', 100 }, {'e', 200} });
return 0;
}
——————————————————————————————————————————————
三. 取值
Map中元素取值主要有at和[ ]兩種操作,at會作下標檢查,而[]不會。
map<int, string> ID_Name;
//ID_Name中沒有關鍵字2016,使用[]取值會導致插入
//因此,下面語句不會報錯,但打印結果爲空
cout<<ID_Name[2016].c_str()<<endl;
//使用at會進行關鍵字檢查,因此下面語句會報錯
ID_Name.at(2016) = "Bob";
——————————————————————————————————————————————
四. 容量查詢
// 查詢map是否爲空
bool empty();
// 查詢map中鍵值對的數量
size_t size();
// 查詢map所能包含的最大鍵值對數量,和系統和應用庫有關。
// 此外,這並不意味着用戶一定可以存這麼多,很可能還沒達到就已經開闢內存失敗了
size_t max_size();
// 查詢關鍵字爲key的元素的個數,在map裏結果非0即1
size_t count( const Key& key ) const; //
——————————————————————————————————————————————
五. 迭代器
共有八個獲取迭代器的函數:* begin, end, rbegin,rend* 以及對應的 * cbegin, cend, crbegin,crend*。
二者的區別在於,後者一定返回 const_iterator,而前者則根據map的類型返回iterator 或者 const_iterator。const情況下,不允許對值進行修改。如下面代碼所示:
map<int,int>::iterator it;
map<int,int> mmap;
const map<int,int> const_mmap;
it = mmap.begin(); //iterator
mmap.cbegin(); //const_iterator
const_mmap.begin(); //const_iterator
const_mmap.cbegin(); //const_iterator
返回的迭代器可以進行加減操作,此外,如果map爲空,則 begin = end。
——————————————————————————————————————————————
六. 刪除交換
6.1 刪除
// 刪除迭代器指向位置的鍵值對,並返回一個指向下一元素的迭代器
iterator erase( iterator pos )
// 刪除一定範圍內的元素,並返回一個指向下一元素的迭代器
iterator erase( const_iterator first, const_iterator last );
// 根據Key來進行刪除, 返回刪除的元素數量,在map裏結果非0即1
size_t erase( const key_type& key );
// 清空map,清空後的size爲0
void clear();
- 6.2 交換
// 就是兩個map的內容互換
void swap( map& other );
——————————————————————————————————————————————
七. 順序比較
// 比較兩個關鍵字在map中位置的先後
key_compare key_comp() const;
示例:
map<char,int> mymap;
map<char,int>::key_compare mycomp = mymap.key_comp();
mymap['a']=100;
mymap['b']=200;
mycomp('a', 'b'); // a排在b前面,因此返回結果爲true
——————————————————————————————————————————————
八. 查找
// 關鍵字查詢,找到則返回指向該關鍵字的迭代器,否則返回指向end的迭代器
// 根據map的類型,返回的迭代器爲 iterator 或者 const_iterator
iterator find (const key_type& k);
const_iterator find (const key_type& k) const;
舉例:
std::map<char,int> mymap;
std::map<char,int>::iterator it;
mymap['a']=50;
mymap['b']=100;
mymap['c']=150;
mymap['d']=200;
it = mymap.find('b');
if (it != mymap.end())
mymap.erase (it); // b被成功刪除
——————————————————————————————————————————————
九. 操作符
operator: == != < <= > >=
注意:對於==運算符, 只有鍵值對以及順序完全相等纔算成立。
Set常見用法說明
一.關於set
C++ STL 之所以得到廣泛的讚譽,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封裝了許多複雜的數據結構算法和大量常用數據結構操作。vector封裝數組,list封裝了鏈表,map和set封裝了二叉樹等,在封裝這些數據結構的時候,STL按照程序員的使用習慣,以成員函數方式提供的常用操作,如:插入、排序、刪除、查找等。讓用戶在STL使用過程中,並不會感到陌生。
關於set,必須說明的是set關聯式容器。set作爲一個容器也是用來存儲同一數據類型的數據類型,並且能從一個數據集合中取出數據,在set中每個元素的值都唯一,而且系統能根據元素的值自動進行排序。應該注意的是set中數元素的值不能直接被改變。C++ STL中標準關聯容器set, multiset, map, multimap內部採用的就是一種非常高效的平衡檢索二叉樹:紅黑樹,也成爲RB樹(Red-Black Tree)。RB樹的統計性能要好於一般平衡二叉樹,所以被STL選擇作爲了關聯容器的內部結構。
關於set有下面幾個問題:
(1)爲何map和set的插入刪除效率比用其他序列容器高?
大部分人說,很簡單,因爲對於關聯容器來說,不需要做內存拷貝和內存移動。說對了,確實如此。set容器內所有元素都是以節點的方式來存儲,其節點結構和鏈表差不多,指向父節點和子節點。結構圖可能如下:
A
/ \
B C
/ \ / \
D E F G
因此插入的時候只需要稍做變換,把節點的指針指向新的節點就可以了。刪除的時候類似,稍做變換後把指向刪除節點的指針指向其他節點也OK了。這裏的一切操作就是指針換來換去,和內存移動沒有關係。
(2)爲何每次insert之後,以前保存的iterator不會失效?
iterator這裏就相當於指向節點的指針,內存沒有變,指向內存的指針怎麼會失效呢(當然被刪除的那個元素本身已經失效了)。相對於vector來說,每一次刪除和插入,指針都有可能失效,調用push_back在尾部插入也是如此。因爲爲了保證內部數據的連續存放,iterator指向的那塊內存在刪除和插入過程中可能已經被其他內存覆蓋或者內存已經被釋放了。即使時push_back的時候,容器內部空間可能不夠,需要一塊新的更大的內存,只有把以前的內存釋放,申請新的更大的內存,複製已有的數據元素到新的內存,最後把需要插入的元素放到最後,那麼以前的內存指針自然就不可用了。特別時在和find等算法在一起使用的時候,牢記這個原則:不要使用過期的iterator。
(3)當數據元素增多時,set的插入和搜索速度變化如何?
如果你知道log2的關係你應該就徹底瞭解這個答案。在set中查找是使用二分查找,也就是說,如果有16個元素,最多需要比較4次就能找到結果,有32個元素,最多比較5次。那麼有10000個呢?最多比較的次數爲log10000,最多爲14次,如果是20000個元素呢?最多不過15次。看見了吧,當數據量增大一倍的時候,搜索次數只不過多了1次,多了1/14的搜索時間而已。你明白這個道理後,就可以安心往裏面放入元素了。
——————————————————————————————————————————————
二.set中常用的方法
begin() ,返回set容器的第一個元素
end() ,返回set容器的最後一個元素
clear() ,刪除set容器中的所有的元素
empty() ,判斷set容器是否爲空
max_size() ,返回set容器可能包含的元素最大個數
size() ,返回當前set容器中的元素個數
rbegin ,返回的值和end()相同
rend() ,返回的值和rbegin()相同
寫一個程序練一練這幾個簡單操作吧:
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> s;
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(1);
cout<<"set 的 size 值爲 :"<<s.size()<<endl;
cout<<"set 的 maxsize的值爲 :"<<s.max_size()<<endl;
cout<<"set 中的第一個元素是 :"<<*s.begin()<<endl;
cout<<"set 中的最後一個元素是:"<<*s.end()<<endl;
s.clear();
if(s.empty())
cout<<"set 爲空 !!!"<<endl;
cout<<"set 的 size 值爲 :"<<s.size()<<endl;
cout<<"set 的 maxsize的值爲 :"<<s.max_size()<<endl;
return 0;
}
小結:插入3之後雖然插入了一個1,但是我們發現set中最後一個值仍然是3哈,這就是set 。還要注意begin() 和 end()函數是不檢查set是否爲空的,使用前最好使用empty()檢驗一下set是否爲空.
1)count( ) 用來查找set中某個某個鍵值出現的次數。這個函數在set並不是很實用,因爲一個鍵值在set只可能出現0或1次,這樣就變成了判斷某一鍵值是否在set出現過了。
示例代碼:
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> s;
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(1);
cout<<"set 中 1 出現的次數是 :"<<s.count(1)<<endl;
cout<<"set 中 4 出現的次數是 :"<<s.count(4)<<endl;
return 0;
}
2)equal_range( ) ,返回一對定位器,分別表示第一個大於或等於給定關鍵值的元素和 第一個大於給定關鍵值的元素,這個返回值是一個pair類型,如果這一對定位器中哪個返回失敗,就會等於end()的值。具體這個有什麼用途我還沒遇到過~~~
示例代碼:
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> s;
set<int>::iterator iter;
for(int i = 1 ; i <= 5; ++i)
s.insert(i);
for(iter = s.begin() ; iter != s.end() ; ++iter)
cout<<*iter<<" ";
cout<<endl;
pair<set<int>::const_iterator,set<int>::const_iterator> pr;
pr = s.equal_range(3);
cout<<"第一個大於等於 3 的數是 :"<<*pr.first<<endl;
cout<<"第一個大於 3的數是 : "<<*pr.second<<endl;
return 0;
}
3)
erase(iterator) ,刪除定位器iterator指向的值
erase(first,second),刪除定位器first和second之間的值
erase(key_value),刪除鍵值key_value的值
看看程序吧:
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> s;
set<int>::const_iterator iter;
set<int>::iterator first;
set<int>::iterator second;
for(int i = 1 ; i <= 10 ; ++i)
s.insert(i);
//第一種刪除
s.erase(s.begin());
//第二種刪除
first = s.begin();
second = s.begin();
second++;
second++;
s.erase(first,second);
//第三種刪除
s.erase(8);
cout<<"刪除後 set 中元素是 :";
for(iter = s.begin() ; iter != s.end() ; ++iter)
cout<<*iter<<" ";
cout<<endl;
return 0;
}
小結:set中的刪除操作是不進行任何的錯誤檢查的,比如定位器的是否合法等等,所以用的時候自己一定要注意。
4)find( ) ,返回給定值值得定位器,如果沒找到則返回end()。
示例代碼:
#include<iostream>
#include<set>
using namespace std;
int main()
{
int a[] = {1,2,3};
set<int> s(a,a+3);
set<int>::iterator iter;
if((iter = s.find(2)) != s.end())
cout<<*iter<<endl;
return 0;
}
5)
insert(key_value); 將key_value插入到set中 ,返回值是pair<set<int>::iterator,bool>,bool標誌着插入是否成功,而iterator代表插入的位置,若key_value已經在set中,則iterator表示的key_value在set中的位置。
inset(first,second);將定位器first到second之間的元素插入到set中,返回值是void.
示例代碼:
#include<iostream>
#include<set>
using namespace std;
int main()
{
int a[] = {1,2,3};
set<int> s;
set<int>::iterator iter;
s.insert(a,a+3);
for(iter = s.begin() ; iter != s.end() ; ++iter)
cout<<*iter<<" ";
cout<<endl;
pair<set<int>::iterator,bool> pr;
pr = s.insert(5);
if(pr.second)
{
cout<<*pr.first<<endl;
}
return 0;
}
6)
lower_bound(key_value) ,返回第一個大於等於key_value的定位器
upper_bound(key_value),返回最後一個大於等於key_value的定位器
示例代碼:
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> s;
s.insert(1);
s.insert(3);
s.insert(4);
cout<<*s.lower_bound(2)<<endl;
cout<<*s.lower_bound(3)<<endl;
cout<<*s.upper_bound(3)<<endl;
return 0;
}
——————————————————————————————————————————————
三.自定義比較函數
(1)元素不是結構體:
例:
//自定義比較函數myComp,重載“()”操作符
struct myComp
{
bool operator()(const your_type &a,const your_type &b)
{
return a.data-b.data>0;
}
}
set<int,myComp>s;
......
set<int,myComp>::iterator it;
(2)元素是結構體:
可以直接將比較函數寫在結構體內。
例:
struct Info
{
string name;
float score;
//重載“<”操作符,自定義排序規則
bool operator < (const Info &a) const
{
//按score從大到小排列
return a.score<score;
}
}
set<Info> s;
......
set<Info>::iterator it;
Auto常見用法說明
一.用法理解
C++11引入了一些新的實用的類型推導能力,這意味着你可以花費更少的時間去寫那些編譯器已經知道的東西。當然有些時候你需要幫助編譯器或者你的編程夥伴。但是C++11,你可以在一些乏味的東西上花更少的時間,而多去關注邏輯本身。
在C++11中,如果編譯器在定義一個變量的時候可以推斷出變量的類型,不用寫變量的類型,你只需寫auto即可。
過去咱們往往先寫成:
int x = 4;
現在可以這樣寫:
auto x = 4;
這當然不是auto預期的用途!它會在模板和迭代器的配合使用中閃耀光芒:
vector<int> vec;
auto itr = vec.iterator();
其它時候auto也會非常有用。比如,你有一些下面格式的代碼:
template <typename BuiltType, typename Builder>
void
makeAndProcessObject (const Builder& builder)
{
BuiltType val = builder.makeObject();
// do stuff with val
}
上面的代碼,我們看到這裏需要兩個模板參數:一個是Builder對象的類型,另一個是Builder創建出的對象的類型。糟糕的是創建出的類型無法被推導出,所以每次你必須這樣調用:
MyObjBuilder builder;
makeAndProcessObject<MyObj>( builder );
但是auto立即將醜陋的代碼一掃無餘,當Builder創建對象時不用寫特殊代碼了,你可以讓C++幫你做:
template <typename Builder>
void
makeAndProcessObject (const Builder& builder)
{
auto val = builder.makeObject();
// do stuff with val
}
現在你僅需一個模板參數,而且這個參數可以在函數調用的時候輕鬆推導:
MyObjBuilder builder;
makeAndProcessObject( builder );
這樣更易調用了,並且沒丟失可讀性,卻更清晰了。
——————————————————————————————————————————————
二.引用、指針和常量
下面要確定的一個問題是auto如何處理引用:
int& foo();
auto bar = foo(); // int& or int?
答案是在C++11中,auto處理引用時默認是值類型,所以下面的代碼bar是int。不過你可以指定&作爲修飾符強制它作爲引用:
int& foo();
auto bar = foo(); // int
auto& baz = foo(); // int&
不過,假如你有一個指針auto則自動獲取指針類型:
int* foo();
auto p_bar = foo(); // int*
但是你也可以顯式指定表明變量是一個指針:
int* foo();
auto *p_baz = foo(); // int*
當處理引用時,你一樣可以標記const,如果需要的話:
int& foo();
const auto& baz = foo(); // const int&
或者指針:
int* foo();
const int* const_foo();
const auto* p_bar = foo(); // const int*
auto p_bar = const_foo(); // const int*
所有這些都很自然,並且這遵循C++模板中類型推導的規則。
decltype常見用法說明
現在你可能會說auto就這樣嗎,假如我想返回Builder創建的對象怎麼辦?我還是需要提供一個模板參數作爲返回值的類型。好!這充分證明了標準委員有一羣聰明的傢伙,對這個問題他們早想好了一個完美的解決方案。這個方案由兩部分組成:decltype和新的返回值語法。
——————————————————————————————————————————————
一.新的返回值語法
講一下新的返回值語法,該語法還能看到auto的另一個用處。在以前版本的C和C++中,返回值的類型必須寫在函數的前面:
int multiply(int x, int y);
在C++11中,你可以把返回類型放在函數聲明的後面,用auto代替前面的返回類型,像這樣:
auto multiply(int x, int y) -> int;
但是爲什麼我要這樣用?讓我們看一個證明這個語法好處的例子。一個包含枚舉的類:
class Person
{
public:
enum PersonType { ADULT, CHILD, SENIOR };
void setPersonType (PersonType person_type);
PersonType getPersonType ();
private:
PersonType _person_type;
};
我們寫了一個簡單的類,裏面有一個類型PersonType表明Person是小孩、成人和老人。不做特殊考慮,我們定義這些成員方法時會發生什麼? 第一個設置方法,很簡單,你可以使用枚舉類型PersonType而不會有錯誤:
void Person::setPersonType (PersonType person_type)
{
_person_type = person_type;
}
而第二個方法卻是一團糟。簡單的代碼卻編譯不過:
// 編譯器不知道PersonType是什麼,因爲PersonType會在Person類之外使用
PersonType Person::getPersonType ()
{
return _person_type;
}
你必須要這樣寫,才能使返回值正常工作:
Person::PersonType Person::getPersonType ()
{
return _person_type;
}
這可能不算大問題,不過會容易出錯,尤其是牽連進模板的時候。
這就是新的返回值語法引進的原因。因爲函數的返回值出現在函數的最後,而不是前面,你不需要補全類作用域。當編譯器解析到返回值的時候,它已經知道返回值屬於Person類,所以它也知道PersonType是什麼。
auto Person::getPersonType () -> PersonType
{
return _person_type;
}
好,這確實不錯,但它真的能幫助我們什麼嗎?我們還不能使用新的返回值語法去解決我們之前的問題,我們能嗎?不能,讓我們介紹新的概念:decltype。
——————————————————————————————————————————————
二.decltype
decltype是auto的反面兄弟。auto讓你聲明瞭一個指定類型的變量,decltype讓你從一個變量(或表達式)中得到類型。我說的是什麼?
int x = 3;
decltype(x) y = x; // 相當於 auto y = x;
可以對基本上任何類型使用decltype,包括函數的返回值。嗯,聽起來像個熟悉的問題,假如我們這樣寫:
decltype( builder.makeObject() )
我們將得到makeObject的返回值類型,這能讓我們指定makeAndProcessObject的返回類型。我們可以整合進新的返回值語法:
template <typename Builder>
auto
makeAndProcessObject (const Builder& builder) -> decltype( builder.makeObject() )
{
auto val = builder.makeObject();
// do stuff with val
return val;
}
這僅適用於新的返回值語法,因爲舊的語法下,我們在聲明函數返回值的時候無法引用函數參數,而新語法,所有的參數都是可訪問的。
Pair常見用法說明
一.說明:
1)類模板:template <class T1, class T2> struct pair
2)參數:class T1是第一個值的數據類型,class T2是第二個值的數據類型。
3)功能:pair將一對值(可以是不同的數據類型)組合成一個值,兩個值可以分別用pair的兩個公有函數first和second訪問。
——————————————————————————————————————————————
二.具體用法:
1.定義(構造):
pair<int, double> p1; //使用默認構造函數
pair<int, double> p2(1, 2.4); //用給定值初始化
pair<int, double> p3(p2); //拷貝構造函數
2.訪問兩個元素(通過first和second):
pair<int, double> p1; //使用默認構造函數
p1.first = 1;
p1.second = 2.5;
cout << p1.first << ' ' << p1.second << endl;
輸出結果:1 2.5
3.賦值:
(1)利用make_pair:
pair<int, double> p1;
p1 = make_pair(1, 1.2);
(2)變量間賦值:
pair<int, double> p1(1, 1.2);
pair<int, double> p2 = p1;
(3)生成新的pair對象:
可以使用make_pair對已存在的兩個數據構造一個新的pair類型:
int a = 8;
string m = "James";
pair<int, string> newone;
newone = make_pair(a, m);
注意:使用關於pair函數中的字符串時,定義字符串用string a;a時字符串的名稱。
Vector常見用法說明
一、什麼是vector
向量(Vector)是一個封裝了動態大小數組的順序容器(Sequence container)。跟任意其它類型容器一樣,它能夠存放各種類型的對象。可以簡單的認爲,向量是一個能夠存放任意類型的動態數組。
——————————————————————————————————————————————
二、容器特性
1.順序序列
順序容器中的元素按照嚴格的線性順序排序。可以通過元素在序列中的位置訪問對應的元素。
2.動態數組
支持對序列中的任意元素進行快速直接訪問,甚至可以通過指針算述進行該操作。操供了在序列末尾相對快速地添加/刪除元素的操作。
3.能夠感知內存分配器的(Allocator-aware)
容器使用一個內存分配器對象來動態地處理它的存儲需求。
——————————————————————————————————————————————
三、基本函數實現
1.構造函數
- vector():創建一個空vector
- vector(int nSize):創建一個vector,元素個數爲nSize
- vector(int nSize,const t& t):創建一個vector,元素個數爲nSize,且值均爲t
- vector(const vector&):複製構造函數
- vector(begin,end):複製[begin,end)區間內另一個數組的元素到vector中
2.增加函數
- void push_back(const T& x):向量尾部增加一個元素X
- iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一個元素x
- iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n個相同的元素x
- iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一個相同類型向量的[first,last)間的數據
3.刪除函數
- iterator erase(iterator it):刪除向量中迭代器指向元素
- iterator erase(iterator first,iterator last):刪除向量中[first,last)中元素
- void pop_back():刪除向量中最後一個元素
- void clear():清空向量中所有元素
4.遍歷函數
- reference at(int pos):返回pos位置元素的引用
- reference front():返回首元素的引用
- reference back():返回尾元素的引用
- iterator begin():返回向量頭指針,指向第一個元素
- iterator end():返回向量尾指針,指向向量最後一個元素的下一個位置
- reverse_iterator rbegin():反向迭代器,指向最後一個元素
- reverse_iterator rend():反向迭代器,指向第一個元素之前的位置
5.判斷函數
- bool empty() const:判斷向量是否爲空,若爲空,則向量中無元素
6.大小函數
- int size() const:返回向量中元素的個數
- int capacity() const:返回當前向量張紅所能容納的最大元素值
- int max_size() const:返回最大可允許的vector元素數量值
7.其他函數
- void swap(vector&):交換兩個同類型向量的數據
- void assign(int n,const T& x):設置向量中第n個元素的值爲x
- void assign(const_iterator first,const_iterator last):向量中[first,last)中元素設置成當前向量元素
8.看着清楚
01)push_back 在數組的最後添加一個數據
02)pop_back 去掉數組的最後一個數據
03)at 得到編號位置的數據
04)begin 得到數組頭的指針
05)end 得到數組的最後一個單元+1的指針
06)front 得到數組頭的引用
07)back 得到數組的最後一個單元的引用
08)max_size 得到vector最大可以是多大
09)capacity 當前vector分配的大小
10)size 當前使用數據的大小
11)resize 改變當前使用數據的大小,如果它比當前使用的大,者填充默認值
12)reserve 改變當前vecotr所分配空間的大小
13)erase 刪除指針指向的數據項
14)clear 清空當前的vector
15)rbegin 將vector反轉後的開始指針返回(其實就是原來的end-1)
16)rend 將vector反轉構的結束指針返回(其實就是原來的begin-1)
17)empty 判斷vector是否爲空
18)swap 與另一個vector交換數據
——————————————————————————————————————————————
四、頭文件
#include < vector>
using namespace std;
——————————————————————————————————————————————
五、簡單介紹
- Vector<類型>標識符
- Vector<類型>標識符(最大容量)
- Vector<類型>標識符(最大容量,初始所有值)
- Int i[5]={1,2,3,4,5}
Vector<類型>vi(I,i+2);//得到i索引值爲3以後的值 - Vector< vector< int> >v; 二維向量//這裏最外的<>要有空格。否則在比較舊的編譯器下無法通過
——————————————————————————————————————————————
六.使用總結
1.vector的初始化:
可以有五種方式,舉例說明如下:
(1) vector<int> a(10); //定義了10個整型元素的向量(尖括號中爲元素類型名,它可以是任何合法的數據類型),但沒有給出初值,其值是不確定的。
(2)vector<int>a(10,1); //定義了10個整型元素的向量,且給出每個元素的初值爲1
(3)vector<int>a(b); //用b向量來創建a向量,整體複製性賦值
(4)vector<int>a(b.begin(),b.begin+3); //定義了a值爲b中第0個到第2個(共3個)元素
(5)intb[7]={1,2,3,4,5,9,8};vector<int> a(b,b+7); //從數組中獲得初值
2.vector對象的幾個重要操作:
舉例說明如下:
(1)a.assign(b.begin(), b.begin()+3);//b爲向量,將b的0~2個元素構成的向量賦給a
(2)a.assign(4,2);//是a只含4個元素,且每個元素爲2
(3)a.back();//返回a的最後一個元素
(4)a.front();//返回a的第一個元素
(5)a[i]; //返回a的第i個元素,當且僅當a[i]存在2013-12-07
(6)a.clear();//清空a中的元素
(7)a.empty();//判斷a是否爲空,空則返回ture,不空則返回false
(8)a.pop_back();//刪除a向量的最後一個元素
(9)a.erase(a.begin()+1,a.begin()+3);//刪除a中第1個(從第0個算起)到第2個元素,也就是說刪除的元素從a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)
(10)a.push_back(5);//在a的最後一個向量後插入一個元素,其值爲5
(11)a.insert(a.begin()+1,5);//在a的第1個元素(從第0個算起)的位置插入數值5,如a爲1,2,3,4,插入元素後爲1,5,2,3,4
(12)a.insert(a.begin()+1,3,5);//在a的第1個元素(從第0個算起)的位置插入3個數,其值都爲5
(13)a.insert(a.begin()+1,b+3,b+6);//b爲數組,在a的第1個元素(從第0個算起)的位置插入b的第3個元素到第5個元素(不包括b+6),如b爲1,2,3,4,5,9,8,插入元素後爲1,4,5,9,2,3,4,5,9,8
(14)a.size();//返回a中元素的個數;
(15)a.capacity();//返回a在內存中總共可以容納的元素個數
(16)a.rezize(10);//將a的現有元素個數調至10個,多則刪,少則補,其值隨機
(17)a.rezize(10,2);//將a的現有元素個數調至10個,多則刪,少則補,其值爲2
(18)a.reserve(100);//將a的容量(capacity)擴充至100,也就是說現在測試a.capacity();的時候返回值是100.這種操作只有在需要給a添加大量數據的時候才 顯得有意義,因爲這將避免內存多次容量擴充操作(當a的容量不足時電腦會自動擴容,當然這必然降低性能)
(19)a.swap(b);//b爲向量,將a中的元素和b中的元素進行整體性交換
(20)a==b; //b爲向量,向量的比較操作還有!=,>=,<=,>,<
3.順序訪問vector的幾種方式:
舉例說明如下:
1.向向量a中添加元素:
1)直接向向量a中添加元素
vector<int> a;
for(int i=0;i<10;i++)
a.push_back(i);
2)也可以從數組中選擇元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector<int> b;
for(int i=1;i<=4;i++)
b.push_back(a[i]);
3)也可以從現有向量中選擇元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector<int> b;
vector<int> c(a,a+4);
for(vector<int>::iterator it=c.begin();it<c.end();it++)
b.push_back(*it);
4)也可以從文件中讀取元素向向量中添加
ifstream in("data.txt");
vector<int> a;
for(int i; in>>i)
a.push_back(i);
5)易犯錯誤
vector<int> a;
for(int i=0;i<10;i++)
a[i]=i;
//這種做法以及類似的做法都是錯誤的。下標只能用於獲取已存在的元素,而現在的a[i]還是空的對象
2.從向量中讀取元素:
1)通過下標方式讀取
int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);
for(int i=0;i<=b.size()-1;i++)
cout<<b[i]<<" ";
2)通過遍歷器方式讀取
int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);
for(vector<int>::iterator it=b.begin();it!=b.end();it++)
cout<<*it<<" ";
——————————————————————————————————————————————
七.實例來咯~
1.pop_back()&push_back(elem)實例在容器最後移除和插入數據:
#include <string.h>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int>obj(10,0);//最大容器爲10,都初始化爲0
for(int i=0;i<10;i++)//push_back(elem)在數組最後添加數據
{
obj.push_back(i);
cout<<obj[i]<<",";
}
for(int i=0;i<5;i++)//去掉數組最後一個數據
{
obj.pop_back();
}
cout<<"\n"<<endl;
for(int i=0;i<obj.size();i++)//size()容器中實際數據個數
{
cout<<obj[i]<<",";
}
return 0;
}
2.clear()清除容器中所以數據:
#include <string.h>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int>obj;
for(int i=0;i<10;i++)//push_back(elem)在數組最後添加數據
{
obj.push_back(i);
cout<<obj[i]<<",";
}
obj.clear();//清除容器中所以數據
for(int i=0;i<obj.size();i++)
{
cout<<obj[i]<<endl;
}
return 0;
}
3.排序:
#include <string.h>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
vector<int>obj;
obj.push_back(1);
obj.push_back(3);
obj.push_back(0);
sort(obj.begin(),obj.end());//從小到大
cout<<"從小到大:"<<endl;
for(int i=0;i<obj.size();i++)
{
cout<<obj[i]<<",";
}
cout<<"\n"<<endl;
cout<<"從大到小:"<<endl;
reverse(obj.begin(),obj.end());//從大到小
for(int i=0;i<obj.size();i++)
{
cout<<obj[i]<<",";
}
return 0;
}
1)注意sort需要頭文件#include < algorithm>
2)如果想sort來降序,可重寫sort
bool compare(int a,int b)
{
return a< b; //升序排列,如果改爲return a>b,則爲降序
}
int a[20]={2,4,1,23,5,76,0,43,24,65},i;
for(i=0;i<20;i++)
cout<< a[i]<< endl;
sort(a,a+20,compare);
4.訪問(直接數組訪問&迭代器訪問)
#include <string.h>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
//順序訪問
vector<int>obj;
for(int i=0;i<10;i++)
{
obj.push_back(i);
}
cout<<"直接利用數組:";
for(int i=0;i<10;i++)//方法一
{
cout<<obj[i]<<" ";
}
cout<<endl;
cout<<"利用迭代器:" ;
//方法二,使用迭代器將容器中數據輸出
vector<int>::iterator it;//聲明一個迭代器,來訪問vector容器,作用:遍歷或者指向vector容器的元素
for(it=obj.begin();it!=obj.end();it++)
{
cout<<*it<<" ";
}
return 0;
}
5.二維數組兩種定義方法(結果一樣)
#include <string.h>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int N=5, M=6;
vector<vector<int> > obj(N); //定義二維動態數組大小5行
for(int i =0; i< obj.size(); i++)//動態二維數組爲5行6列,值全爲0
{
obj[i].resize(M);
}
for(int i=0; i< obj.size(); i++)//輸出二維動態數組
{
for(int j=0;j<obj[i].size();j++)
{
cout<<obj[i][j]<<" ";
}
cout<<"\n";
}
return 0;
}
#include <string.h>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int N=5, M=6;
vector<vector<int> > obj(N, vector<int>(M)); //定義二維動態數組5行6列
for(int i=0; i< obj.size(); i++)//輸出二維動態數組
{
for(int j=0;j<obj[i].size();j++)
{
cout<<obj[i][j]<<" ";
}
cout<<"\n";
}
return 0;
}
string常見用法說明
#include<iostream>
#include"string"
#include"algorithm"
using namespace std;
//string的賦值
void f1()
{
string s1 ="shihao"; //string是一個類
string s2 ("bbbbbb");
string s3 = s1;
string s4(10, 'a'); //等價於string s4 ="aaaaaaaaaa";
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
}
//string的遍歷
void f2()
{
string s1 = "abcdefg";
//1:數組方式
for(int i = 0; i < s1.length(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
//2:迭代器
for(string::iterator it = s1.begin(); it != s1.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//3 異常處理
try
{
for(int i = 0; i < s1.length() + 3; i++)
{
cout << s1.at(i) << " "; //當出現錯誤時, 會向外拋出異常
}
}
catch(...)
{
cout << "發生異常" << endl;
}
try
{
for(int i = 0; i < s1.length() + 3; i++) //出現錯誤, 不向外拋出異常
{
cout << s1[i] << " ";
}
}
catch(...)
{
cout << "發生異常" << endl;
}
}
//字符指針和sting的轉換
void f4()
{
//1:
string s1 = "aaabbb";
cout << s1.c_str() << endl;
//2:
char buf[128] = {0};
s1.copy(buf, 3, 1); //拷貝3個字符,從1個字符開始(位置下標從0開始) //注:不會自動加上字符串結束標誌
cout << "buf: " << buf << endl;
}
//字符串的連接
void f5()
{
//1:
string s1 = "aaa";
string s2 = "bbb";
s1 = s1 + s2;
cout << "s1: " << s1 << endl;
//2:
string s3 = "333";
string s4 = "444";
s3.append(s4);
cout << "s3: " << s3 << endl;
}
//字符串的查找和替換
void f6()
{
string s1 = "wbm hello wbm 111 wbm 222 wbm 333";
//查找 從查找位置開始第一個出現的下標
int index = s1.find("wbm", 1); //位置下標從0開始
cout <<"index: " << index << endl << endl;
//查找每一次wbm出現的下標
int offindex = s1.find("wbm", 0);
while (offindex != string::npos) //不等於-1
{
cout << "offindex: " << offindex << endl;
offindex++;
offindex = s1.find("wbm", offindex);
}
//把所有的wbm換成大寫
offindex = s1.find("wbm", 0);
while (offindex != string::npos) //不等於-1
{
s1.replace(offindex, 3, "WBM");
offindex++;
offindex = s1.find("wbm", offindex);
}
cout << endl << "s1替換後的結果爲: " << s1 << endl;
//把aaa替換成大寫
string s2 = "aaa bbb ccc";
s2.replace(0, 3, "AAA"); //從第0個位置開始替換3個
cout << endl << "s2: " << s2 << endl;
}
//區間刪除和插入
void f7()
{
string s1 = "hello1 hello2 hello1";
string::iterator it = find(s1.begin(), s1.end(), 'l');
if (it != s1.end())
{
s1.erase(it); //刪除
}
cout << "s1刪除l以後的結果爲:" << s1 << endl;
s1.erase(s1.begin(), s1.end());
cout << "s1全部刪除:" << s1 << endl;
cout << "s1的長度爲: " << s1.length() << endl;
//插入
string s2 = "BBB";
s2.insert(0, "AAA");
cout << "s2: " << s2 << endl;
}
//大小寫轉換
void f8()
{
string s1 = "AAAbbb";
transform(s1.begin(), s1.end(), s1.begin(), ::tolower); //transform(first,last,result,op);
cout << "s1全部轉化爲小寫爲: " << s1 << endl;
transform(s1.begin(), s1.end(), s1.begin(), ::toupper); //transform(first,last,result,op);
cout << "s1全部轉化爲大寫爲: " << s1 << endl;
}
int main()
{
f8();
return 0;
}
結束語
宇宙第一小仙女\(^o^)/~~萌量爆表求帶飛=≡Σ((( つ^o^)つ~ dalao們點個關注唄~~
還比較全面叭~歡迎補充~有錯誤歡迎指出~
再次感謝各位大佬的們的分享!
本篇參考資料:
https://blog.csdn.net/w_linux/article/details/71600574
https://blog.csdn.net/shuzfan/article/details/53115922
https://blog.csdn.net/Duke10/article/details/78344226
https://blog.csdn.net/fanyun_01/article/details/56842637
https://blog.csdn.net/yas12345678/article/details/52601454
https://blog.csdn.net/wang907553141/article/details/52663223
http://towriting.com/blog/2013/08/08/improved-type-inference-in-cpp11/