- list是可以在常數(shù)范圍內(nèi)在任意位置進(jìn)行插入和刪除的序列式容器,并且該容器可以前后雙向迭代。
- list的底層是雙向鏈表結(jié)構(gòu),雙向鏈表中每個(gè)元素存儲(chǔ)在互不相關(guān)的獨(dú)立節(jié)點(diǎn)中,在節(jié)點(diǎn)中通過指針指向其前一個(gè)元素和后一個(gè)元素。
- list與forward_list非常相似:最主要的不同在于forward_list是單鏈表,只能朝前迭代,已讓其更簡單高效。
- 與其他的序列式容器相比(array,vector,deque),list通常在任意位置進(jìn)行插入、移除元素的執(zhí)行效率更好。
- 與其他序列式容器相比,list和forward_list大的缺陷是不支持任意位置的隨機(jī)訪問,比如:要訪問list的第6個(gè)元素,必須從已知的位置(比如頭部或者尾部)迭代到該位置,在這段位置上迭代需要線性的時(shí)間開銷;list還需要一些額外的空間,以保存每個(gè)節(jié)點(diǎn)的相關(guān)聯(lián)信息(對(duì)于存儲(chǔ)類型較小元素的大list來說這可能是一個(gè)重要因素
構(gòu)造函數(shù) 接口說明 list() 構(gòu)造空的list list (size_type n, const value_type& val = value_type()) 構(gòu)造的list中包含n個(gè)值為val的元素 list (const list& x) 拷貝構(gòu)造函數(shù) list (InputIterator first, InputIterator last) 用[first, last)區(qū)間中的元素構(gòu)造list
- list()
list
lt1;
- list (size_type n, value_type& val = value_type())
list
lt2(4, 1);//構(gòu)造4個(gè)值為1的元素
- list (const list& x)
list
lt3(lt2);//用lt2拷貝構(gòu)造lt3
- list (InputIterator first, InputIterator last)
//1、用l2的[begin(), end())左閉右開的區(qū)間構(gòu)造lt4 list
lt4(lt2.begin(), lt2.end()); //2、以數(shù)組為迭代器區(qū)間構(gòu)造lt5 int array[] = {1,2,3,4 }; list lt5(array, array + sizeof(array) / sizeof(int));
2.1.begin和end
函數(shù)聲明 接口說明 begin 返回第一個(gè)元素的迭代器 end 返回最后一個(gè)元素下一個(gè)位置的迭代器 rbegin 返回第一個(gè)元素的reverse_iterator,即end位置 rend 返回最后一個(gè)元素下一個(gè)位置的reverse_iterator,即begin位置
2.2.rbegin和rendbegin是返回第一個(gè)元素的迭代器,end是返回最后一個(gè)元素下一個(gè)位置的迭代器。可以通過迭代器進(jìn)行元素訪問:
void list_test1() {list
lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); list ::iterator it = lt.begin(); while (it != lt.end()) //不能用it< lt.end() {cout<< *it<< " "; it++; } cout<< endl; }
- 注意:begin與end為正向迭代器,對(duì)迭代器執(zhí)行++操作,迭代器向后移動(dòng)。
2.3.范圍for和先前學(xué)到的string類似,rbegin的第一個(gè)元素為尾部end位置,rend返回的是begin的位置。
void list_test1() {list
lt(4, 1); list ::reverse_iterator rit = lt.rbegin(); //或者用auto自動(dòng)識(shí)別類型:auto rit = lt.rbegin(); while (rit != lt.rend()) {cout<< *it<< " "; // 1 1 1 1 it++; } }
- 注意:rbegin(end)與rend(begin)為反向迭代器,對(duì)迭代器執(zhí)行++操作,迭代器向前移動(dòng)。
2.4.迭代器的分類范圍for的底層就是迭代器實(shí)現(xiàn)的,利用其也可進(jìn)行元素訪問:
void list_test1() {list
lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); for(auto e : lt) {cout<< e<< " "; } cout<< endl; }
- 單向迭代器:只能++,不能–。比如單鏈表、哈希表等。
- 雙向迭代器:既能++也能–。比如雙向鏈表。
- 隨機(jī)訪問迭代器:既能++、–;又能+、-。比如vector、string。
- 迭代器是內(nèi)嵌類型(內(nèi)部類或定義在類里)
3.1.front和back
函數(shù)聲明 接口聲明 front 返回list第一個(gè)節(jié)點(diǎn)中值的引用 back 返回list最后一個(gè)節(jié)點(diǎn)中值的引用
front返回第一個(gè)元素,back返回最后一個(gè)元素
void list_test2() {list
lt; for (int i = 1; i<= 4; i++) {lt.push_back(i);//1 2 3 4 } cout<< lt.front()<< endl;//1 cout<< lt.back()<< endl; //4 }
4.1.empty
函數(shù)聲明 接口說明 empty 檢測list是否為空,是返回true,不是返回false size 返回list中有效節(jié)點(diǎn)的個(gè)數(shù) max_size 返回list中的大數(shù)據(jù)
4.2.size和max_sizeempty判斷l(xiāng)ist是否為空
void list_test2() {list
lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); if(lt.empty()) cout<< "list empty"<< endl; lt.pop_back(); lt.pop_back(); lt.pop_back(); lt.pop_back(); if(lt.empty()) cout<< "list empty"<< endl; }
size用來獲取list的元素個(gè)數(shù),max_size用來獲取list的大元素個(gè)數(shù)。
void list_test2() {list lt(5, 1); cout<< lt.size()<< endl;// 5 cout<< lt.max_size()<< endl; // 返回鏈表長度大值 }
5.1.push_front和pop_front
函數(shù)聲明 接口聲明 push_front 在list首元素前插入值為val的元素 pop_front 刪除list中第一個(gè)元素 push_back 在list尾部插入值為val的元素 pop_back 刪除list中最后一個(gè)元素 insert 在list position 位置中插入值為val的元素 erase 刪除list position位置的元素 swap 交換兩個(gè)list中的元素 clear 清空list中的有效數(shù)據(jù) resize 為list開辟空間同時(shí)進(jìn)行初始化
5.2.push_back和pop_backpush_front即頭插,pop_front即頭刪。
void list_test3() {list
lt; lt.push_front(1); lt.push_front(2); lt.push_front(3); lt.push_front(4); for (auto e : lt) {cout<< e<< " "; } cout<< endl; lt.pop_front(); lt.pop_front(); for (auto e : lt) {cout<< e<< " "; } cout<< endl; }
5.3.insert和erasepush_back即尾插,pop_back即尾刪。
void list_test3() {list
lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); for (auto e : lt) {cout<< e<< " "; } cout<< endl; lt.pop_back(); lt.pop_back(); lt.pop_back(); lt.pop_back(); if(lt.empty()) cout<< "list empty"<< endl; }
5.3.clear和resizelist中的insert支持下列三種插入方式:
- 在指定位置插入一個(gè)值為val的元素
- 在指定位置插入n個(gè)值為val的元素
- 在指定位置插入一段左閉右開的迭代器區(qū)間
void list_test3() {list
lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); list ::iterator pos = find(lt.begin(), lt.end(), 2); //1、在3的位置插入值20 lt.insert(pos, 20); for (auto e : lt) {cout<< e<< " ";//1 20 2 3 4 } cout<< endl; //2、在3的位置插入3個(gè)30 pos = find(lt.begin(), lt.end(), 3); lt.insert(pos, 3, 30); for (auto e : lt) {cout<< e<< " ";//1 20 2 30 30 30 3 4 } cout<< endl; //3、在7的位置插入迭代器區(qū)間 pos = find(lt.begin(), lt.end(), 20); list lt2(3, 0); lt.insert(pos, lt2.begin(), lt2.end()); for (auto e : lt) {cout<< e<< " ";//1 0 0 0 20 2 30 30 30 3 4 } cout<< endl; } erase支持下列兩種刪除方式:
刪除在指定迭代器位置的元素
刪除指定迭代器區(qū)間的元素
void list_test3() {list
lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); lt.push_back(5); lt.push_back(6); list ::iterator pos = find(lt.begin(), lt.end(), 2); //1、刪除2位置的元素 lt.erase(pos); for (auto e : lt) {cout<< e<< " ";//1 3 4 5 6 } cout<< endl; //2、刪除4到list末尾的所有元素 pos = find(lt.begin(), lt.end(), 4); lt.erase(pos, lt.end()); for (auto e : lt) {cout<< e<< " ";//1 3 } } 注意:這里的find使用的是算法庫里面的,list并未提供find算法。
5.4.swapclear用來清空list中的有效數(shù)據(jù)。
void list_test4() {list
lt(5, -1); for (auto e : lt) {cout<< e<< " ";//-1 -1 -1 -1 -1 } cout<< endl; lt.clear(); for (auto e : lt) {cout<< e<< " ";//空 } } resize擴(kuò)容并初始化分為兩種:
如果 n 小于當(dāng)前容器大小,則內(nèi)容將減少到其前n個(gè)元素,刪除超出的元素(并銷毀它們)。
如果 n 大于當(dāng)前容器大小,則通過在末尾插入所需數(shù)量的元素來擴(kuò)展內(nèi)容,以達(dá)到n的大小。如果指定了 val,則新元素將初始化為 val ,否則,它們將被值初始化為0 或者 匿名對(duì)象。
void list_test4() {list
lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); lt.push_back(5); lt.push_back(6); resize(5); for(auto e : ch) {cout<< e<< " "; // 1 2 3 4 5 } cout<< endl; resize(8, 10); for(auto e : ch) {cout<< e<< " "; // 1 2 3 4 5 10 10 10 } cout<< endl; resize(10); for(auto e : ch) {cout<< e<< " "; // 1 2 3 4 5 10 10 10 0 0 } cout<< endl; }
6.list的其他操作函數(shù)swap用于交換兩個(gè)list的內(nèi)容。
void list_test4() {list
lt1(5, 1); list lt2(3, 2); lt2.swap(lt1); for (auto e : lt1) {cout<< e<< " "; //2 2 2 } cout<< endl; for (auto d : lt2) {cout<< d<< " "; //1 1 1 1 1 } }
6.1.sort
函數(shù)聲明 接口說明 sort 對(duì)list進(jìn)行排序 unique 刪除list中的重復(fù)元素 splice 將元素從一個(gè)list剪切到另一個(gè)list move 刪除具有特定值的元素 move_if 刪除滿足條件的元素 merge 合并排序list reverse 反轉(zhuǎn)list元素的順序
6.2.splicelist中的sort函數(shù)默認(rèn)排升序。
void list_test5() {list
lt; lt.push_back(2); lt.push_back(23); lt.push_back(6); lt.push_back(14); lt.push_back(10); lt.push_back(100); lt.remove(100); for (auto e : lt) {cout<< e<< " "; } cout<< endl; // list 雙向循環(huán)鏈表提供 lt.sort(); // algorithm 算法庫提供 //sort(lt.begin(), lt.end()); 報(bào)錯(cuò) for (auto e : lt) {cout<< e<< " "; } cout<< endl; //迭代器功能分類 // 1.單向 ++ // 2.雙向 -- // 3.隨機(jī) ++ -- + - ——>vector、string } 注意:
list單獨(dú)提供排序是因?yàn)樗荒苡盟惴◣熘械呐判颉?/font>算法庫中的排序是一個(gè)快排,需要滿足三數(shù)取中以及傳遞隨機(jī)訪問迭代器,list并不能滿足,所以不適用。而list自己提供的排序的底層是歸并排序,但是它本身提供的排序比較慢,如果數(shù)據(jù)量較小,那效率還可以,但是如果數(shù)據(jù)量很大,我們寧愿把list中的數(shù)據(jù)尾插到vector中使用算法庫中的快排,再拷貝回list中,也不會(huì)使用自身的歸并排序。
測試一:vector使用算法庫中的sortVSlist自身的sort
// N個(gè)數(shù)據(jù)需要排序,vector+ 算法sort list+ sort void test_op1() {srand((unsigned int)time(0)); const int N = 1000000; vector
v; v.reserve(N); list lt1; for (int i = 0; i< N; ++i) {auto e = rand(); v.push_back(e); lt1.push_back(e); } int begin1 = clock(); sort(v.begin(), v.end()); int end1 = clock(); int begin2 = clock(); //sort(lt2.begin(), lt2.end()); lt1.sort(); int end2 = clock(); printf("vector sort:%d\n", end1 - begin1); printf("list sort:%d\n", end2 - begin2); } 測試二:list先把數(shù)據(jù)拷貝到vector,再排序,排序完成后,再將數(shù)據(jù)拷貝回list所用時(shí)間VSlist使用自身的sort所用時(shí)間
void test_op2() {srand((unsigned int)time(0)); const int N = 10000000; vector
v; v.reserve(N); list lt1; list lt2; for (int i = 0; i< N; ++i) {auto e = rand(); //v.push_back(e); lt1.push_back(e); //lt2.push_back(e); } // 拷貝到vector排序,排完以后再拷貝回來 int begin1 = clock(); for (auto e : lt1) {v.push_back(e); } sort(v.begin(), v.end()); size_t i = 0; for (auto& e : lt1) {//e = v[i++]; lt2.push_back(e); } int end1 = clock(); int begin2 = clock(); //sort(lt2.begin(), lt2.end()); lt1.sort(); int end2 = clock(); printf("vector sort:%d\n", end1 - begin1); printf("list sort:%d\n", end2 - begin2); }
6.3.move和move_ifsplice將元素從一個(gè)list剪切到另一個(gè)list,被剪切的list沒有元素了。
void list_test6() {list
lt1; lt1.push_back(10); lt1.push_back(20); lt1.push_back(30); list lt2; lt2.push_back(1); lt2.push_back(2); lt2.push_back(3); lt2.push_back(4); auto it = lt2.begin(); ++it; // 迭代器下標(biāo)為2 lt2.splice(it, lt1); // 把lt1的元素轉(zhuǎn)移到lt2迭代器下標(biāo)為2的位置 for (auto e : lt2) {cout<< e<< " "; // 1 10 20 30 2 3 4 } cout<< endl; for(auto e : lt1) {cout<< e<< " "; // 空 } }
6.4.unique和mergemove作用是從容器中刪除所有與 val 相等的元素。這將調(diào)用這些對(duì)象的析構(gòu)函數(shù),并通過刪除的元素?cái)?shù)來減小容器大小。
void list_test6() {list
lt1; lt1.push_back(1); lt1.push_back(2); lt1.push_back(3); lt1.push_back(4); lt1.push_back(2); lt1.move(2); for(auto e : lt1) {cout<< e<< " "; // 1 3 4 } cout<< endl; } move_if作用是移除滿足條件的元素。這將調(diào)用這些對(duì)象的析構(gòu)函數(shù),并通過刪除的元素?cái)?shù)來減小容器大小。
// 是否為偶數(shù) bool is_even(const int& value) {return (value % 2) == 0; } // 是否為奇數(shù) struct is_odd {bool operator() (const int& value) { return (value % 2) == 1; } }; int main () {int arr[]= {15,36,7,17,20,39,4,1}; list
lt1 (arr, arr+8); // 15 36 7 17 20 39 4 1 lt1.remove_if (is_even); for(auto e : lt1) {cout<< e<< " "; // 15 36 7 17 39 1 } cout<< endl; lt1.remove_if (is_odd()); for(auto e : lt1) {cout<< e<< " "; // 空 } cout<< endl; return 0; }
6.5.reverseunique是刪除list中的重復(fù)元素。
void list_test5() {list
lt; list lt; lt.push_back(2); lt.push_back(3); lt.push_back(6); lt.push_back(23); lt.push_back(10); lt.push_back(3); lt.push_back(10); lt.sort(); lt.unique(); for (auto e : lt) {cout<< e<< " ";//2 3 6 10 23 } }
- 注意:要想對(duì)list進(jìn)行真正的去重,必須先排序。
merge的作用是合并兩個(gè)鏈表,并且這兩個(gè)鏈表必須是有序的。
void list_test6() {list
lt1; lt1.push_back(10); lt1.push_back(30); lt1.push_back(20); list lt2; lt2.push_back(3); lt2.push_back(2); lt2.push_back(1); lt2.push_back(4); lt1.sort(); lt2.sort(); lt1.merge(lt2); for(auto e : lt1) { cout<< e<< " "; // 1 2 3 4 10 20 30 } cout<< endl;
reverse的作用是反轉(zhuǎn)list中元素的順序。
void list_test6() {list
lt1; for(int i = 1; i<= 5; i++) {lt1.push_back(i); } reverse(lt1); for(auto e : lt1) {cout<< e<< " "; // 5 4 3 2 1 } cout<< endl; }
vector list 底層結(jié)構(gòu) 動(dòng)態(tài)順序表,一段連續(xù)空間 帶頭結(jié)點(diǎn)的雙向循環(huán)鏈表 隨機(jī)訪問 支持隨機(jī)訪問,訪問某個(gè)元素效率O(1) 不支持隨機(jī)訪問,訪問某個(gè)元素效率O(N) 插入和刪除 任意位置插入和刪除效率低,需要搬移元素,時(shí)間復(fù)雜度為O(N),插入時(shí)有可能需要增容,增容:開辟新空間,拷貝元素,釋放舊空間,導(dǎo)致效率更低 任意位置插入和刪除效率高,不需要搬移元素,時(shí)間復(fù)雜度為O(1) 空間利用率 底層為連續(xù)空間,不容易造成內(nèi)存碎片,空間利用率高,緩存利用率高 底層節(jié)點(diǎn)動(dòng)態(tài)開辟,小節(jié)點(diǎn)容易造成內(nèi)存碎片,空間利用率低,緩存利用率低 迭代器 原生態(tài)指針 對(duì)原生態(tài)指針(節(jié)點(diǎn)指針)進(jìn)行封裝 迭代器失效 在插入元素時(shí),要給所有的迭代器重新賦值,因?yàn)椴迦朐赜锌赡軙?huì)導(dǎo)致重新擴(kuò)容,致使原來迭代器失效,刪除時(shí),當(dāng)前迭代器需要重新賦值否則會(huì)失效 插入元素不會(huì)導(dǎo)致迭代器失效,刪除元素時(shí),只會(huì)導(dǎo)致當(dāng)前迭代器失效,其他迭代器不受影響 使用場景 需要高效存儲(chǔ),支持隨機(jī)訪問,不關(guān)心插入刪除效率 大量插入和刪除操作,不關(guān)心隨機(jī)訪問
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧