臨時記錄_C++容器相關

-  <span class="timestamp-wrapper"><span class="timestamp">[2020-01-10 五 11:53] </span></span> 第9章 順序容器

   

        vector,隨機訪問、大小可變、尾部之外插入刪除慢、額外空間開銷小

        deque, 隨機訪問、大小可變、頭尾之外插入刪除慢、額外空間開銷小

        list, 順序雙向訪問、大小可變、插入很快、額外空間開銷大

        forward_list,順序單向訪問、大小可變、插入很快、額外空間開銷大

        array, 隨機訪問、固定大小、不能增刪、額外空間開銷小

        string, 類似vector、專爲字符、額外空間開銷小

-  <span class="timestamp-wrapper"><span class="timestamp"><2020-01-12 日 10:56> </span></span> 9.2 容器庫概覽

   

        描述容器接口的思路:

        1、所有容器通用接口

        2、順序與非順序容器的特定接口

        3、其它特殊容器特殊接口(如string)

       

        類型別名

        iterator

        const_iterator

        size_type

       

        difference_type

        value_type

        reference

        const_reference

       

        構造函數

        C c;

        C c1(c2);

        C c(b,e);

        C c{a,b,c...};

       

        賦值與swap

        c1=c2;

        c1={a,b,c...};

        a.swap(b);

        swap(a,b);

       

        大小

        c.size();

        c.max_size();

        c.empty();

       

        增刪(不適用於array)

        c.insert(args);

        c.emplace(inits);

        c.erase(args)

        c.clear();

       

        關係

        ==,!=,<,<=,>,>=

       

        迭代器

        c.begin(),c.end();

        c.cbegin(),c.cend();

       

        反向額外成員

        reverse_iterator

        const_reverse_iterator

        c.rbegin(),c.rend():

        c.crbegin(),c.crend();

   

        vector<NoDefault> v1(10,init)//對於一個沒有默認構造函數的類型NoDefault通過元素初始化器。

       

        容器是模板類,容器元素可以任何甚至可以是另外一個容器類,但是舊版編譯器需要在兩個尖括號之間加入空格,例如:

        vector<vector<string> >;

   

        兩個迭代器構成的迭代器範圍是左閉右開的,即:[begin,end), end可以與begin是同一個位置(範圍爲空),但是不能在begin之前。

        兩個迭代器可以指向同一個容器中的元素或者最後一個元素之後的位置。

   

        迭代器函數

        begin/end這類返回迭代器的函數是被重載的,如果對象是普通變量,返回的是正常的iterator,如果是常量返回的則是const_iterator。

        以c開頭的函數是C++新引入的,以支持auto,與begin/end一起使用。

       

        帶r版本的迭代器是反向的。

-  <span class="timestamp-wrapper"><span class="timestamp">[2019-11-30 六 13:35] </span></span> 將一個容器初始化爲另一個容器的拷貝

   

    容器定義和初始化

   

        //默認構造函數

        C c;

       

        //用一個容器創建另一個做爲它的拷貝的容器,必須兩個容器的類型、以及容器元素類型都一樣,array的大小還必須一樣。

        C c1(c2);

        C c1=c2;

       

        //c初始化爲初始化列表元素的拷貝,列表元素與容器元素類型必須相同;array時,列表必須不能超過array大小

        C c{a,b,c...};

        C c={a,b,c...};

       

        //初始化爲範圍中的元素,範圍中元素類型必須與C中元素類型相同(不能是array)

        C c(b,e);

       

        //只適合順序容器

        C seq(n);//n個元素進行值初始化,構造函數是explicit的(即阻止自動隱式轉換)(不能是string)

        C seq(n,t);//n個元素,初始化爲值t

   

        用一個容器創建另一個做爲它的拷貝的容器,必須兩個容器的類型、以及容器元素類型都一樣,array的大小還必須一樣。

        list<string> list2(authors);

       

        用迭代器範圍來初始化容器類型和容器元素的類型都可以不同,因爲直接替換了容器原來的元素。

        deque<string> authList(authors.begin(),it);//包括[begin(),it)迭代器範圍

       

        用列表初始化,列表隱含了被初始化容器的大小。

        list<string> authors = {"one", "two", "three"};

        除array外,初始化列表賦值之後,元素大小變爲初始化列表大小(數組則要求初始化列表大小小於數組)。

       

        順序容器相關,如果沒有默認構造函數,必須用兩個參數的,第二個參數提供默認值;如果有默認構造函數,則只需要傳遞元素數目也行。

        vector<int> ivec(10,-1);//10個元素,每個值-1

        forward<int> ivec(10);//10個元素,每個值0

       

        注:上面的例子中,authors是list。

-  9.2.5 賦值和swap

   

        c1=c2;

        c={a,b,c...};

        swap(c1,c2);

        c1.swap(c2);

       

        seq.assign(b,e);

        seq.assign(il);

        seq.assign(n,t);

   

        大小是array類型的一個部分:

        array<int,10> size_type i;

        所以array構造函數是不應當有大小參數的。

       

        與內置數組不同,array可以賦值和初始化,不過使用其它數組賦值的時候,要求數組類型匹配(大小、元素類型)

        array<int,10> ia2={0,1,2,3,4,5,6,7,8,9};

        array<int,10> ia3={42};

       

        array<int,10> ia4=ia3;

        如果列表初始化,則列表大小需要小於數組,並且剩餘的元素要有相應的默認構造函數來進行默認初始化。

        注:花括號初始化列表只能初始化賦值,不能初始化之後,再用花括號對數組進行賦值。非數組可以用花括號賦值。

   

        assign只用於除了array之外的順序容器。允許從不同但相容類型賦值

        由於是舊元素被替換,傳遞給assign的迭代器不能指向調用assign的容器。

   

    <span class="timestamp-wrapper"><span class="timestamp"><2020-01-13 一 13:21> </span></span> 使用swap

   

        除array之外,swap不會導致元素拷貝、刪除、插入。swap後,string的迭代器會失效,數組的迭代器會指向原來的位置(但是元素已經被置換了),而其它的迭代器也會被置換(各自仍指向原來被換的元素)。

   

    <span class="timestamp-wrapper"><span class="timestamp"><2020-01-14 二 10:59> </span></span> 比較

   

        容器比較必須保證元素類型和容器類型是相同的,並且只有元素也定義了比較運算才能使用運算符號對容器進行比較。

   

    -  9.3 容器操作

        插入相關

       

            //尾部追加,forwardlist不支持

            c.push_back(t);//值爲t的元素

            c.emplace_back(args);//args創建的元素

           

            //頭部創建,vector與string不支持

            c.push_front(t);

            c.emplace_front(args);

           

            //指定位置之前的插入,forwardlist不支持下面的而是有自己專用的insert和emplace

            c.insert(p,t);//在p迭代器對應元素之前插入值爲t的元素

            c.emplace(p,args);

            c.insert(p,n,t);//n個值爲t的元素

            c.insert(p,b,e);//迭代器範圍[b,e)

            c.insert(p,il);//花括號元素列表il

       

            對象插入或初始化容器後,容器中的對應元素與對象並無關係,對象只是拷貝,類似傳值調用。

       

            emplace直接在容器管理的空間中創建對象而不拷貝對象,emplace參數必須與元素類型構造函數參數匹配,

       

        訪問相關

       

            訪問成員函數返回的是引用

            front()是首元素(begin()),back是尾元素(end()-1),forwardlist不支持back();

            c.front(),c.back();

           

            下標操作和at()可以隨機訪問,下標需要程序員自己注意越界情況,而at()會在越界的時候自動拋出相關的out_of_range錯誤

            c[n],c.at(n);

       

        刪除相關

       

            //forwardlist不支持erase,它有自己專用的刪除函數

            //下面操作改變容器大小所以不支持array

            c.pop_back();//刪除尾元素,forwardlist不支持

            c.pop_front();//刪除首元素,vector和string不支持

           

            c.erase(p);//刪除p所指向的元素(p是迭代器)

            c.erase(b,e);//刪除[b,e)範圍內的元素

            c.clear();//刪除所有元素

       

        forwardlist特殊的函數

       

            //特殊的迭代器

            lst.before_begin();//首元素之前不存在的元素迭代器

            lst.cbefore_begin();

           

            //特殊的插入

            lst.insert_after(p,t);

            lst.insert_after(p,n,t);

            lst.insert_after(p,b,e);

            lst.insert_after(p,il);

           

            emplace_after(p,args);

           

            //特殊的刪除

            lst.erase_after(p);

            lst.erase_after(b,e);

   

    -  <span class="timestamp-wrapper"><span class="timestamp"><2020-01-14 二 11:50> </span></span> 9.3.5改變容器大小

       

            c.resize(n);

            c.resize(n,t);

   

    -  9.3.6 容器操作可能會使迭代器失效

       

            插入、刪除都可能導致容器迭代器失效,不同容器情況不同(比如vector、list等)具體參考相關位置。

           

            大致情況如下:

            對於插入,

            指向list/forwardlist的引用、指針、迭代器都不會失效;

            vector/string若重新分配則指針、引用、迭代器全失效,若未重新分配則插入之前的引用、指針、迭代器不會失效;

            deque插入首尾之外則指針、引用、迭代器全失效,插入首尾則迭代器失效但是指向存在的指針、引用不會失效。

           

            對於刪除,

            指向被刪元素的迭代器、指針、引用全都失效;

            指向list/forwardlist其它位置的引用、指針、迭代器都不會失效;

            deque刪除首尾之外則其它元素指針、引用、迭代器全失效,刪除尾部則尾後迭代器失效其它不失效,刪除首部則其它都不會被影響。

            指向vector/string被刪除元素之前的指針、引用、迭代器都有效。

            只要刪除元素,尾後迭代器都失效。

       

            對於vector/string/deque,爲防止失效,循環中操作容器後需要更新迭代器、引用、指針。

            insert()/erase()均會返回新迭代器,用它更新迭代器即可。

            類似如下這樣進行:

            inter= vi.insert(...);

            inter= vi.erase(....);

           

            不要在循環外保存c.end()返回的尾迭代器做爲判斷,而直接每次使用新的返回值

            類似如下這樣進行:

            while(begin != v.end())

            {...}

   

    -  9.4 vector對象是如何增長的

       

            vector元素連續,增加元素會導致重新分配空間,移動所有元素,所以通過一定策略預先給它分配多餘的預留空間,防止頻繁移動所有元素。

            capacity()告訴我們不重新分配內存(擴張)的情況下可以容納多少個元素;reserve告訴我們它應當預留準備保存的元素數目。

            c.shrink_to_fit();//將capacity減少到與size(即實際的元素數)同樣大小。

            c.capacity();//最大能保存的元素數目,超過則重新分配內存。

            c.reserve(n);//預留n的空間,不改變容器元素數量,僅影響vector預先分配多大的空間。

           

            當需求大於當前容量,reserve纔會改變vector容量,至少會分配與需求一樣大的空間;當需求小於等於當前容量,reservse什麼都不做並且小於時也並不會退回多餘的空間。當調用reserve之後,capacity空間大小會大於等於傳給reserve的參數。

           

            總之,reserve不會減少容器佔用的空間。類似地,resize只減少容器元素數目而不是容器容量,也不能用它減少預留空間。

           

            shrink_to_fit()會要求退回多餘空間,但是實際也不保證一定退回。

       

        <span class="timestamp-wrapper"><span class="timestamp"><2020-01-19 日 12:15> </span></span> capacity和size

   

    -  <span class="timestamp-wrapper"><span class="timestamp">[2020-03-17 二 11:48] </span></span> 9.5額外的string操作

       

            創建函數:使用const char*創建string對象時,如果未指定創建的大小或者指定的大小大於const char*字符數目,那麼const char*必須以NULL空字符結束,否則不用。

            string(s), string(s,pos), string(s,pos,n)

            substr(pos), substr(pos,n)

           

            修改字符串的操作:insert(),erase(),assign(),append(),replace()

           

            搜索函數:返回string:size_typ類型,是下標,沒有匹配則返回最大值npos的static成員。

            find(),rfind(),find_first_of(),find_last_of(),find_first_not_of(),find_last_not_of()

           

            比較函數: compare()

           

            數值轉換:to_string(val),stoi(),stol(),stoul(),stoll(),stoull(),stof(),stod(),stold()-  <span class="timestamp-wrapper"><span class="timestamp">[2020-01-10 五 11:53] </span></span> 第9章 順序容器

   

        vector,隨機訪問、大小可變、尾部之外插入刪除慢、額外空間開銷小

        deque, 隨機訪問、大小可變、頭尾之外插入刪除慢、額外空間開銷小

        list, 順序雙向訪問、大小可變、插入很快、額外空間開銷大

        forward_list,順序單向訪問、大小可變、插入很快、額外空間開銷大

        array, 隨機訪問、固定大小、不能增刪、額外空間開銷小

        string, 類似vector、專爲字符、額外空間開銷小

-  <span class="timestamp-wrapper"><span class="timestamp"><2020-01-12 日 10:56> </span></span> 9.2 容器庫概覽

   

        描述容器接口的思路:

        1、所有容器通用接口

        2、順序與非順序容器的特定接口

        3、其它特殊容器特殊接口(如string)

       

        類型別名

        iterator

        const_iterator

        size_type

       

        difference_type

        value_type

        reference

        const_reference

       

        構造函數

        C c;

        C c1(c2);

        C c(b,e);

        C c{a,b,c...};

       

        賦值與swap

        c1=c2;

        c1={a,b,c...};

        a.swap(b);

        swap(a,b);

       

        大小

        c.size();

        c.max_size();

        c.empty();

       

        增刪(不適用於array)

        c.insert(args);

        c.emplace(inits);

        c.erase(args)

        c.clear();

       

        關係

        ==,!=,<,<=,>,>=

       

        迭代器

        c.begin(),c.end();

        c.cbegin(),c.cend();

       

        反向額外成員

        reverse_iterator

        const_reverse_iterator

        c.rbegin(),c.rend():

        c.crbegin(),c.crend();

   

        vector<NoDefault> v1(10,init)//對於一個沒有默認構造函數的類型NoDefault通過元素初始化器。

       

        容器是模板類,容器元素可以任何甚至可以是另外一個容器類,但是舊版編譯器需要在兩個尖括號之間加入空格,例如:

        vector<vector<string> >;

   

        兩個迭代器構成的迭代器範圍是左閉右開的,即:[begin,end), end可以與begin是同一個位置(範圍爲空),但是不能在begin之前。

        兩個迭代器可以指向同一個容器中的元素或者最後一個元素之後的位置。

   

        迭代器函數

        begin/end這類返回迭代器的函數是被重載的,如果對象是普通變量,返回的是正常的iterator,如果是常量返回的則是const_iterator。

        以c開頭的函數是C++新引入的,以支持auto,與begin/end一起使用。

       

        帶r版本的迭代器是反向的。

-  <span class="timestamp-wrapper"><span class="timestamp">[2019-11-30 六 13:35] </span></span> 將一個容器初始化爲另一個容器的拷貝

   

    容器定義和初始化

   

        //默認構造函數

        C c;

       

        //用一個容器創建另一個做爲它的拷貝的容器,必須兩個容器的類型、以及容器元素類型都一樣,array的大小還必須一樣。

        C c1(c2);

        C c1=c2;

       

        //c初始化爲初始化列表元素的拷貝,列表元素與容器元素類型必須相同;array時,列表必須不能超過array大小

        C c{a,b,c...};

        C c={a,b,c...};

       

        //初始化爲範圍中的元素,範圍中元素類型必須與C中元素類型相同(不能是array)

        C c(b,e);

       

        //只適合順序容器

        C seq(n);//n個元素進行值初始化,構造函數是explicit的(即阻止自動隱式轉換)(不能是string)

        C seq(n,t);//n個元素,初始化爲值t

   

        用一個容器創建另一個做爲它的拷貝的容器,必須兩個容器的類型、以及容器元素類型都一樣,array的大小還必須一樣。

        list<string> list2(authors);

       

        用迭代器範圍來初始化容器類型和容器元素的類型都可以不同,因爲直接替換了容器原來的元素。

        deque<string> authList(authors.begin(),it);//包括[begin(),it)迭代器範圍

       

        用列表初始化,列表隱含了被初始化容器的大小。

        list<string> authors = {"one", "two", "three"};

        除array外,初始化列表賦值之後,元素大小變爲初始化列表大小(數組則要求初始化列表大小小於數組)。

       

        順序容器相關,如果沒有默認構造函數,必須用兩個參數的,第二個參數提供默認值;如果有默認構造函數,則只需要傳遞元素數目也行。

        vector<int> ivec(10,-1);//10個元素,每個值-1

        forward<int> ivec(10);//10個元素,每個值0

       

        注:上面的例子中,authors是list。

-  9.2.5 賦值和swap

   

        c1=c2;

        c={a,b,c...};

        swap(c1,c2);

        c1.swap(c2);

       

        seq.assign(b,e);

        seq.assign(il);

        seq.assign(n,t);

   

        大小是array類型的一個部分:

        array<int,10> size_type i;

        所以array構造函數是不應當有大小參數的。

       

        與內置數組不同,array可以賦值和初始化,不過使用其它數組賦值的時候,要求數組類型匹配(大小、元素類型)

        array<int,10> ia2={0,1,2,3,4,5,6,7,8,9};

        array<int,10> ia3={42};

       

        array<int,10> ia4=ia3;

        如果列表初始化,則列表大小需要小於數組,並且剩餘的元素要有相應的默認構造函數來進行默認初始化。

        注:花括號初始化列表只能初始化賦值,不能初始化之後,再用花括號對數組進行賦值。非數組可以用花括號賦值。

   

        assign只用於除了array之外的順序容器。允許從不同但相容類型賦值

        由於是舊元素被替換,傳遞給assign的迭代器不能指向調用assign的容器。

   

    <span class="timestamp-wrapper"><span class="timestamp"><2020-01-13 一 13:21> </span></span> 使用swap

   

        除array之外,swap不會導致元素拷貝、刪除、插入。swap後,string的迭代器會失效,數組的迭代器會指向原來的位置(但是元素已經被置換了),而其它的迭代器也會被置換(各自仍指向原來被換的元素)。

   

    <span class="timestamp-wrapper"><span class="timestamp"><2020-01-14 二 10:59> </span></span> 比較

   

        容器比較必須保證元素類型和容器類型是相同的,並且只有元素也定義了比較運算才能使用運算符號對容器進行比較。

   

    -  9.3 容器操作

        插入相關

       

            //尾部追加,forwardlist不支持

            c.push_back(t);//值爲t的元素

            c.emplace_back(args);//args創建的元素

           

            //頭部創建,vector與string不支持

            c.push_front(t);

            c.emplace_front(args);

           

            //指定位置之前的插入,forwardlist不支持下面的而是有自己專用的insert和emplace

            c.insert(p,t);//在p迭代器對應元素之前插入值爲t的元素

            c.emplace(p,args);

            c.insert(p,n,t);//n個值爲t的元素

            c.insert(p,b,e);//迭代器範圍[b,e)

            c.insert(p,il);//花括號元素列表il

       

            對象插入或初始化容器後,容器中的對應元素與對象並無關係,對象只是拷貝,類似傳值調用。

       

            emplace直接在容器管理的空間中創建對象而不拷貝對象,emplace參數必須與元素類型構造函數參數匹配,

       

        訪問相關

       

            訪問成員函數返回的是引用

            front()是首元素(begin()),back是尾元素(end()-1),forwardlist不支持back();

            c.front(),c.back();

           

            下標操作和at()可以隨機訪問,下標需要程序員自己注意越界情況,而at()會在越界的時候自動拋出相關的out_of_range錯誤

            c[n],c.at(n);

       

        刪除相關

       

            //forwardlist不支持erase,它有自己專用的刪除函數

            //下面操作改變容器大小所以不支持array

            c.pop_back();//刪除尾元素,forwardlist不支持

            c.pop_front();//刪除首元素,vector和string不支持

           

            c.erase(p);//刪除p所指向的元素(p是迭代器)

            c.erase(b,e);//刪除[b,e)範圍內的元素

            c.clear();//刪除所有元素

       

        forwardlist特殊的函數

       

            //特殊的迭代器

            lst.before_begin();//首元素之前不存在的元素迭代器

            lst.cbefore_begin();

           

            //特殊的插入

            lst.insert_after(p,t);

            lst.insert_after(p,n,t);

            lst.insert_after(p,b,e);

            lst.insert_after(p,il);

           

            emplace_after(p,args);

           

            //特殊的刪除

            lst.erase_after(p);

            lst.erase_after(b,e);

   

    -  <span class="timestamp-wrapper"><span class="timestamp"><2020-01-14 二 11:50> </span></span> 9.3.5改變容器大小

       

            c.resize(n);

            c.resize(n,t);

   

    -  9.3.6 容器操作可能會使迭代器失效

       

            插入、刪除都可能導致容器迭代器失效,不同容器情況不同(比如vector、list等)具體參考相關位置。

           

            大致情況如下:

            對於插入,

            指向list/forwardlist的引用、指針、迭代器都不會失效;

            vector/string若重新分配則指針、引用、迭代器全失效,若未重新分配則插入之前的引用、指針、迭代器不會失效;

            deque插入首尾之外則指針、引用、迭代器全失效,插入首尾則迭代器失效但是指向存在的指針、引用不會失效。

           

            對於刪除,

            指向被刪元素的迭代器、指針、引用全都失效;

            指向list/forwardlist其它位置的引用、指針、迭代器都不會失效;

            deque刪除首尾之外則其它元素指針、引用、迭代器全失效,刪除尾部則尾後迭代器失效其它不失效,刪除首部則其它都不會被影響。

            指向vector/string被刪除元素之前的指針、引用、迭代器都有效。

            只要刪除元素,尾後迭代器都失效。

       

            對於vector/string/deque,爲防止失效,循環中操作容器後需要更新迭代器、引用、指針。

            insert()/erase()均會返回新迭代器,用它更新迭代器即可。

            類似如下這樣進行:

            inter= vi.insert(...);

            inter= vi.erase(....);

           

            不要在循環外保存c.end()返回的尾迭代器做爲判斷,而直接每次使用新的返回值

            類似如下這樣進行:

            while(begin != v.end())

            {...}

   

    -  9.4 vector對象是如何增長的

       

            vector元素連續,增加元素會導致重新分配空間,移動所有元素,所以通過一定策略預先給它分配多餘的預留空間,防止頻繁移動所有元素。

            capacity()告訴我們不重新分配內存(擴張)的情況下可以容納多少個元素;reserve告訴我們它應當預留準備保存的元素數目。

            c.shrink_to_fit();//將capacity減少到與size(即實際的元素數)同樣大小。

            c.capacity();//最大能保存的元素數目,超過則重新分配內存。

            c.reserve(n);//預留n的空間,不改變容器元素數量,僅影響vector預先分配多大的空間。

           

            當需求大於當前容量,reserve纔會改變vector容量,至少會分配與需求一樣大的空間;當需求小於等於當前容量,reservse什麼都不做並且小於時也並不會退回多餘的空間。當調用reserve之後,capacity空間大小會大於等於傳給reserve的參數。

           

            總之,reserve不會減少容器佔用的空間。類似地,resize只減少容器元素數目而不是容器容量,也不能用它減少預留空間。

           

            shrink_to_fit()會要求退回多餘空間,但是實際也不保證一定退回。

       

        <span class="timestamp-wrapper"><span class="timestamp"><2020-01-19 日 12:15> </span></span> capacity和size

   

    -  <span class="timestamp-wrapper"><span class="timestamp">[2020-03-17 二 11:48] </span></span> 9.5額外的string操作

       

            創建函數:使用const char*創建string對象時,如果未指定創建的大小或者指定的大小大於const char*字符數目,那麼const char*必須以NULL空字符結束,否則不用。

            string(s), string(s,pos), string(s,pos,n)

            substr(pos), substr(pos,n)

           

            修改字符串的操作:insert(),erase(),assign(),append(),replace()

           

            搜索函數:返回string:size_typ類型,是下標,沒有匹配則返回最大值npos的static成員。

            find(),rfind(),find_first_of(),find_last_of(),find_first_not_of(),find_last_not_of()

           

            比較函數: compare()

           

            數值轉換:to_string(val),stoi(),stol(),stoul(),stoll(),stoull(),stof(),stod(),stold()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章