STL—list容器
list容器
1 list基本概念
功能:將資料進行鏈式儲存
連結串列(list)是一種物理儲存單元上非連續的儲存結構,資料元素的邏輯順序是通過連結串列中的指標連結實現的
連結串列的組成:連結串列由一系列結點組成
結點的組成:一個是儲存資料元素的資料域,另一個是儲存下一個結點地址的指標域
STL中的連結串列是一個雙向迴圈連結串列
由於連結串列的儲存方式並不是連續的記憶體空間,因此連結串列list中的迭代器只支援前移和後移,屬於雙向迭代器
list的優點:
- 採用動態儲存分配,不會造成記憶體浪費和溢位
- 連結串列執行插入和刪除操作十分方便,修改指標即可,不需要移動大量元素
list的缺點:
- 連結串列靈活,但是空間(指標域) 和 時間(遍歷)額外耗費較大
List有一個重要的性質,插入操作和刪除操作都不會造成原有list迭代器的失效,這在vector是不成立的。
總結:STL中List和vector是兩個最常被使用的容器,各有優缺點
2 list建構函式
功能描述:
- 建立list容器
函式原型:
list<T> lst;
//list採用採用模板類實現,物件的預設構造形式:list(beg,end);
//建構函式將[beg, end)區間中的元素拷貝給本身。list(n,elem);
//建構函式將n個elem拷貝給本身。list(const list &lst);
//拷貝建構函式。
示例:
#include <list> void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } void test01() { list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); printList(L1); list<int>L2(L1.begin(),L1.end()); printList(L2); list<int>L3(L2); printList(L3); list<int>L4(10, 1000); printList(L4); } int main() { test01(); system("pause"); return 0; }
總結:list構造方式同其他幾個STL常用容器,熟練掌握即可
3 list 賦值和交換
功能描述:
- 給list容器進行賦值,以及交換list容器
函式原型:
assign(beg, end);
//將[beg, end)區間中的資料拷貝賦值給本身。assign(n, elem);
//將n個elem拷貝賦值給本身。list& operator=(const list &lst);
//過載等號操作符swap(lst);
//將lst與本身的元素互換。
示例:
#include <list>
void printList(const list<int>& L) {
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
//賦值和交換
void test01()
{
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
printList(L1);
//賦值
list<int>L2;
L2 = L1;
printList(L2);
list<int>L3;
L3.assign(L2.begin(), L2.end());
printList(L3);
list<int>L4;
L4.assign(10, 100);
printList(L4);
}
//交換
void test02()
{
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
list<int>L2;
L2.assign(10, 100);
cout << "交換前: " << endl;
printList(L1);
printList(L2);
cout << endl;
L1.swap(L2);
cout << "交換後: " << endl;
printList(L1);
printList(L2);
}
int main() {
//test01();
test02();
system("pause");
return 0;
}
總結:list賦值和交換操作能夠靈活運用即可
4 list 大小操作
功能描述:
- 對list容器的大小進行操作
函式原型:
-
size();
//返回容器中元素的個數 -
empty();
//判斷容器是否為空 -
resize(num);
//重新指定容器的長度為num,若容器變長,則以預設值填充新位置。 //如果容器變短,則末尾超出容器長度的元素被刪除。
-
resize(num, elem);
//重新指定容器的長度為num,若容器變長,則以elem值填充新位置。 //如果容器變短,則末尾超出容器長度的元素被刪除。
示例:
#include <list>
void printList(const list<int>& L) {
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
//大小操作
void test01()
{
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
if (L1.empty())
{
cout << "L1為空" << endl;
}
else
{
cout << "L1不為空" << endl;
cout << "L1的大小為: " << L1.size() << endl;
}
//重新指定大小
L1.resize(10);
printList(L1);
L1.resize(2);
printList(L1);
}
int main() {
test01();
system("pause");
return 0;
}
總結:
- 判斷是否為空 --- empty
- 返回元素個數 --- size
- 重新指定個數 --- resize
5 list 插入和刪除
功能描述:
- 對list容器進行資料的插入和刪除
函式原型:
- push_back(elem);//在容器尾部加入一個元素
- pop_back();//刪除容器中最後一個元素
- push_front(elem);//在容器開頭插入一個元素
- pop_front();//從容器開頭移除第一個元素
- insert(pos,elem);//在pos位置插elem元素的拷貝,返回新資料的位置。
- insert(pos,n,elem);//在pos位置插入n個elem資料,無返回值。
- insert(pos,beg,end);//在pos位置插入[beg,end)區間的資料,無返回值。
- clear();//移除容器的所有資料
- erase(beg,end);//刪除[beg,end)區間的資料,返回下一個資料的位置。
- erase(pos);//刪除pos位置的資料,返回下一個資料的位置。
- remove(elem);//刪除容器中所有與elem值匹配的元素。
示例:
#include <list>
void printList(const list<int>& L) {
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
//插入和刪除
void test01()
{
list<int> L;
//尾插
L.push_back(10);
L.push_back(20);
L.push_back(30);
//頭插
L.push_front(100);
L.push_front(200);
L.push_front(300);
printList(L);
//尾刪
L.pop_back();
printList(L);
//頭刪
L.pop_front();
printList(L);
//插入
list<int>::iterator it = L.begin();
L.insert(++it, 1000);
printList(L);
//刪除
it = L.begin();
L.erase(++it);
printList(L);
//移除
L.push_back(10000);
L.push_back(10000);
L.push_back(10000);
printList(L);
L.remove(10000);
printList(L);
//清空
L.clear();
printList(L);
}
int main() {
test01();
system("pause");
return 0;
}
總結:
- 尾插 --- push_back
- 尾刪 --- pop_back
- 頭插 --- push_front
- 頭刪 --- pop_front
- 插入 --- insert
- 刪除 --- erase
- 移除 --- remove
- 清空 --- clear
6 list 資料存取
功能描述:
- 對list容器中資料進行存取
函式原型:
front();
//返回第一個元素。back();
//返回最後一個元素。
示例:
#include <list>
//資料存取
void test01()
{
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
//cout << L1.at(0) << endl;//錯誤 不支援at訪問資料
//cout << L1[0] << endl; //錯誤 不支援[]方式訪問資料
cout << "第一個元素為: " << L1.front() << endl;
cout << "最後一個元素為: " << L1.back() << endl;
//list容器的迭代器是雙向迭代器,不支援隨機訪問
list<int>::iterator it = L1.begin();
//it = it + 1;//錯誤,不可以跳躍訪問,即使是+1
}
int main() {
test01();
system("pause");
return 0;
}
總結:
- list容器中不可以通過[]或者at方式訪問資料
- 返回第一個元素 --- front
- 返回最後一個元素 --- back
7 list 反轉和排序
功能描述:
- 將容器中的元素反轉,以及將容器中的資料進行排序
函式原型:
reverse();
//反轉連結串列sort();
//連結串列排序
示例:
void printList(const list<int>& L) {
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
bool myCompare(int val1 , int val2)
{
return val1 > val2;
}
//反轉和排序
void test01()
{
list<int> L;
L.push_back(90);
L.push_back(30);
L.push_back(20);
L.push_back(70);
printList(L);
//反轉容器的元素
L.reverse();
printList(L);
//排序
//所有不支援隨機訪問迭代器的容器,不可以使用標準演算法
//不支援隨機訪問迭代器的容器,內部會提供一些演算法
/*sort(L1.begin(), L1.end());
cout << "排序之後: " << endl;
printList(L1);*/
L.sort(); //預設的排序規則 從小到大
printList(L);
L.sort(myCompare); //指定規則,從大到小
printList(L);
}
int main() {
test01();
system("pause");
return 0;
}
總結:
- 反轉 --- reverse
- 排序 --- sort (成員函式)
8 排序案例
案例描述:將Person自定義資料型別進行排序,Person中屬性有姓名、年齡、身高
排序規則:按照年齡進行升序,如果年齡相同按照身高進行降序
示例:
#include <list>
#include <string>
class Person {
public:
Person(string name, int age , int height) {
m_Name = name;
m_Age = age;
m_Height = height;
}
public:
string m_Name; //姓名
int m_Age; //年齡
int m_Height; //身高
};
//指定排序規則
bool ComparePerson(Person& p1, Person& p2) {
if (p1.m_Age == p2.m_Age) {//如果年齡相同,按照身高降序
return p1.m_Height > p2.m_Height;
}
else
{
//按照年齡升序
return p1.m_Age < p2.m_Age;
}
}
void test01() {
list<Person> L;
Person p1("劉備", 35 , 175);
Person p2("曹操", 45 , 180);
Person p3("孫權", 40 , 170);
Person p4("趙雲", 25 , 190);
Person p5("張飛", 35 , 160);
Person p6("關羽", 35 , 200);
L.push_back(p1);
L.push_back(p2);
L.push_back(p3);
L.push_back(p4);
L.push_back(p5);
L.push_back(p6);
for (list<Person>::iterator it = L.begin(); it != L.end(); it++) {
cout << "姓名: " << it->m_Name << " 年齡: " << it->m_Age
<< " 身高: " << it->m_Height << endl;
}
cout << "---------------------------------" << endl;
L.sort(ComparePerson); //排序
for (list<Person>::iterator it = L.begin(); it != L.end(); it++) {
cout << "姓名: " << it->m_Name << " 年齡: " << it->m_Age
<< " 身高: " << it->m_Height << endl;
}
}
int main() {
test01();
system("pause");
return 0;
}
總結:
-
對於自定義資料型別,必須要指定排序規則,否則編譯器不知道如何進行排序
-
高階排序只是在排序規則上再進行一次邏輯規則制定,並不複雜