C++容器(list類模板總結)---4

list是順序容器的一種。list是一個雙向鏈表。使用list需要包含頭文件list。雙向鏈表的每一個元素中都有一個指針指向後一個元素,也有一個指針指向前一個元素

在list容器中,在已經定位到要增刪元素的位置的情況下,增刪元素能在常數時間內完成,比如在ai和ai+1之間插入一個元素,值需要修改ai和ai+1中的指針即可

                                       

list的內部結構和vector不同,存在明顯的區別

1.list不支持隨機存取

2.在list的任何位置執行元素的插入和移除都非常快,可以迅速實現。插入和刪除動作不會影響指向其他元素的指針、引用、迭代器,不會造成失效

3.list不支持隨機存取,不提供下標操作符和at()函數

4.list沒有提供容量、空間重新分配等操作函數,每個元素都有自己的內存

5.list提供了特殊成員函數,專門用於移動元素

list模板類實現了標準C++11數據結構中鏈表的所有功能。list一旦定義了類對象後,就可以完成鏈表操作

STL 中的算法 sort 可以用來對 vector 和 deque 排序,它需要隨機訪問迭代器的支持。因爲 list 不支持隨機訪問迭代器,所以不能用算法 sort 對 list 容器排序。因此,list 容器引入了 sort 成員函數以完成排序

 

list的使用

#include <iostream>
#include <stdlib.h>
#include <list>

using namespace std;

int main()
{
	list<int> l1;  //構造空的l1
	list<int> l2 (4, 100); //l2中放入4個值爲100的元素
	list<int> l3(l2.begin(), l2.end()); //用l2的begin(),end()左閉右開區間構造l3
	list<int> l4(l3); //用l3拷貝構造l4

	//以數組作爲迭代器區間構造l5
	int arr[] = {32,543,23,53};
	list<int> l5(arr, arr + sizeof(arr) / sizeof(int));
	cout << "l4: data";
	//C++11打印方式
	for (auto &x : l4)
	{
		cout << x << " ";
	}
	cout << endl;
	cout << "l5:data:";
	//用迭代器方式打印l5中的元素
	for (list<int>::iterator it = l5.begin(); it != l5.end(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;

	cout << endl;
	system("pause");
	return 0;
}

list iterator的使用

1. beginend爲正向迭代器,對迭代器執行++操作,迭代器向後移動

2. rbegin(end)rend(begin)爲反向迭代器,對迭代器執行++操作,迭代器向前移動

3. cbegincendconst的正向迭代器,與beginend不同的是:該迭代器指向節點中的元素值不能修

4. crbegincrendconst的反向得帶器,與rbeginrend不同的是:該迭代器指向節點中的元素值不能修改

#include <iostream>
#include <stdlib.h>
#include <list>

using namespace std;

int main()
{
	int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	list<int> v(a, a + sizeof(a) / sizeof(int));
	//使用正向迭代器打印list中的元素
	for (list<int>::iterator it = v.begin(); it != v.end(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;
    //使用反向迭代器打印list中的元素
	for (list<int>::reverse_iterator it = v.rbegin(); it != v.rend(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;

	for (auto cit : v)
	{
		cout << cit << " ";
	}
    system("pause");
	return 0;
}

list capacity

#include <iostream>
#include <stdlib.h>
#include <list>

using namespace std;

int main()
{
	int a[] = {1,2,3,4,5,6,7,8,9,0};
	list<int> v(a, a + sizeof(a) / sizeof(a[0]));
	//打印list中有效節點的個數
	cout << v.size() << endl;
	
	//檢測list是否爲空
	if (v.empty()){
		cout << "空的list" << endl;
	}
	else
	{
		for (const auto&e : v)
		{
			cout << e << " ";
			
		}
		cout << endl;
	}
    system("pause");
	return 0;
}

 

#include <iostream>
#include <stdlib.h>
#include <list>

using namespace std;

int main()
{
	int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	list<int> v(a, a + sizeof(a) / sizeof(a[0]));

	for (auto&e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	//將list中的第一個節點與最後一個節點中的值改爲10
	v.front() = 10;
	v.back() = 10;
	
	for (auto&e : v)
	{
		cout << e << " ";
	}

	const list<int> v2(a, a + sizeof(a) / sizeof(a[0]));
	const int& ca = v2.front();
	cout << endl;
	cout << ca << " ";
system("pause");
	return 0;
}

// push_back/pop_back/push_front/pop_front



//打印函數
void PrintList(list<int>&v)
{
	for (auto&e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

//////////////////////////////////////////////////////
// push_back/pop_back/push_front/pop_front

void TestList1()
{
	int a[] = { 1, 2, 3 };
	list<int> v(a, a + sizeof(a) / sizeof(a[0]));

	//在list的尾部插入4,頭部插入0
	v.push_back(4);
	v.push_front(0);
	PrintList(v);
    //刪除尾節點和頭結點
	v.pop_back();
	v.pop_front();
	PrintList(v);
}

// emplace_back / emplace_front / emplace

// emplace_back / emplace_front / emplace
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int,int,int):" << this << endl;
	}
	Date(const Date&d)
		:_year(d._year)
		, _month(d._month)
		, _day(d._day)
	{
		cout << "Date(const Date&):" << this << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

// push_back尾插:先構造好元素,然後將元素拷貝到節點中,插入時先調構造函數,再調拷貝構造函數
// emplace_back尾插:先構造節點,然後調用構造函數在節點中直接構造對象
// emplace_back比push_back更高效,少了一次拷貝構造函數的調用

void TestList2()
{
	list<Date> l;
	Date d(2018, 10, 20);
	l.push_back(d);
	l.emplace_back(2018, 10, 21);
	l.emplace_front(2018, 10, 19);
}

// insert /erase

// insert /erase
void TestList3()
{
	int a[] = { 1, 2, 3 };
	list<int> v1(a, a + sizeof(a) / sizeof(a[0]));
	//獲取鏈表中第二個節點
	auto pos = ++v1.begin();
	cout << *pos << endl;

	//在pos前插入值爲4的元素
	v1.insert(pos, 4);
	PrintList(v1);

	//在pos前插入5個值爲5的元素
	v1.insert(pos, 5, 5);
	PrintList(v1);

	//在pos前插入[v.begin(),v.end())區間中的元素
	vector<int> v2{ 7, 8, 9 };
	v1.insert(pos, v2.begin(), v2.end());
	PrintList(v1);

	//刪除pos位置上的元素
	v1.erase(pos);
	PrintList(v1);

	//刪除list中[begin,end)區間中的元素,即刪除所有元素
	v1.erase(v1.begin(), v1.end());
	PrintList(v1);
}

// resize/swap/clear

void TestList4()
{
	int a[] = { 1, 2, 3 };
	list<int> v1(a, a + sizeof(a) / sizeof(a[0]));
	PrintList(v1);

	//將v中的元素個數增加到10個,多出的元素用默認值填充
	//list中放置的是內置類型,默認值爲0,如果list中放置自定義類型元素,調用缺省構造函數

	v1.resize(10);
	PrintList(v1);

	//將v中的元素增加到20個,多出的元素用4來填充
	v1.resize(20, 4);
	PrintList(v1);

	//將V中的元素減少到5個
	v1.resize(5);
	PrintList(v1);

	//用Vector中的元素來構造list
	vector<int> v2{ 4, 5, 6 };
	list<int> l(v2.begin(), v2.end());
	cout << "構造後l:";
	PrintList(l);

	//交換v1和l中的元素
	v1.swap(l);
	cout << "v1:";
	PrintList(v1);
	cout << "l:";
	PrintList(l);

	//將l中的元素清空
	cout << "清空後:";
	l.clear();
	cout << l.size() << endl;
}

 

list的迭代器失效

        迭代器失效即迭代器所指向的節點的無效,即該節點被刪除了。因爲list的底層結構爲帶頭結點的雙向循環鏈表,因此list中進行插入時是不會導致list的迭代 器失效的,只有在刪除時纔會失效,並且失效的只是指向被刪除節點的迭代器,其他迭代器不會受到影響

void TestListIterator1()
{
 int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array+sizeof(array)/sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
 // erase()函數執行後,it所指向的節點已被刪除,因此it無效,在下一次使用it時,必須先給其賦
值
 l.erase(it); 
 ++it;
}
}

// 改正
void TestListIterator()
{
 int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array+sizeof(array)/sizeof(array[0]));

auto it = l.begin();
while (it != l.end())
{
 l.erase(it++); // it = l.erase(it);
}
}

 

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