C++: Introduction and use of container list

 Table of contents

1.Introduction and use of list

1.1 Introduction to list

1.2 Use of list

1.2.1 Construction of list

1.2.2 Use of list iterator

1.2.3 list capacity capacity

1.2.4 list element access access list elements

1.2.5 list modifiers modification

1.2.6 Iterator invalidation


1.Introduction and use of list

1.1 Introduction to list

C++ official website list introduction document

  1. list is a sequential container that can be inserted and deleted at any position within the constant range, and the container can Two-way iteration before and after is a two-way headed circular linked list.
  2. The bottom layer of list is a doubly linked list structure. Each element in the doubly linked list is stored in an independent node that is not related to each other. In the node Point to its previous element and next element through pointers.
  3. list is very similar to forward_list: the main difference is that forward_list is a singly linked list and can only iterate forward, making it simpler and more efficient.
  4. Compared with other sequential containers (array, vector, deque), list usually performs better in inserting and removing elements at any position.
  5. Compared with other sequential containers, the biggest flaw of list and forward_list is that it does not support random access at any location, for example: to access The 6th element of the list must be iterated from a known position (such as the head or tail) to this position. Iterating at this position requires linear time overhead; the list also requires some additional space to save each node. associated information (this may be an important factor for large lists storing elements of smaller types)

1.2 Use of list

There are many interfaces in the list, which are similar here. You only need to master how to use them correctly, and then study the principles behind them in depth to achieve scalability. The following are some common important interfaces in the list:

1.2.1 Construction of list

Constructor function ((constructor)) Interface Description
list (size_type n, const value_type& val = value_type()) The constructed list contains n elements with the value val
list() Construct an empty list
list (const list& x) copy constructor
list (InputIterator first, InputIterator last) Construct a list with elements in the range [first, last)
void TestList1()
{
    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 array[] = { 16,2,77,29 };
    list<int> l5(array, array + sizeof(array) / sizeof(int));

    // 列表格式初始化C++11
    list<int> l6{ 1,2,3,4,5 };

    // 用迭代器方式打印l5中的元素
    list<int>::iterator it = l5.begin();
    while (it != l5.end())
    {
        cout << *it << " ";
        ++it;
    }       
    cout << endl;

    // C++11范围for的方式遍历
    for (auto& e : l5)
        cout << e << " ";

    cout << endl;
}

1.2.2 Use of list iterator

Here, you can temporarily understand the iterator as a pointer, which points to a node in the list. It will be simulated and implemented later

function declaration Interface Description
begin() +
end()
Returns an iterator to the first element + an iterator to the next position of the last element
rbegin() +
rend()
Returns the reverse_iterator of the first element, which is the end position, and returns the next position of the last element
reverse_iterator, which is the begin position

【Notice】

  1.  begin and end are forward iterators, perform ++ operations on the iterator, and the iterator moves backward
  2.  rbegin(end) and rend(begin) are reverse iterators, perform ++ operations on the iterator, and the iterator moves forward
// 注意:遍历链表只能用迭代器和范围for
void PrintList(const list<int>& l)
{
    // 注意这里调用的是list的 begin() const,返回list的const_iterator对象
    for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it)
    {
        cout << *it << " ";
        // *it = 10; 编译不通过
    }

    cout << endl;
}

void TestList2()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array + sizeof(array) / sizeof(array[0]));
    // 使用正向迭代器正向list中的元素
    // list<int>::iterator it = l.begin();   // C++98中语法
    auto it = l.begin();                     // C++11之后推荐写法
    while (it != l.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    // 使用反向迭代器逆向打印list中的元素
    // list<int>::reverse_iterator rit = l.rbegin();
    auto rit = l.rbegin();
    while (rit != l.rend())
    {
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;
}

1.2.3 list capacity capacity

function declaration Interface Description
empty() Check whether the list is empty, return true if it is empty, otherwise return false
size() Returns the number of valid nodes in the list


1.2.4 list element access access list elements

function declaration Interface Description
front() Returns a reference to the value in the first node of the list
back() Returns a reference to the value in the last node of the list

1.2.5 list modifiers modification

function declaration Interface Description
push_front Insert an element with value val before the first element of list
pop_front Delete the first element in the list
push_back Insert an element with value val at the end of the list
pop_back Delete the last element in the list
insert Insert an element with value val in list position
erase Delete the element at list position
swap Swap elements in two lists
clear Clear valid elements in the list
// push_back/pop_back/push_front/pop_front
void TestList3()
{
    int array[] = { 1, 2, 3 };
    list<int> L(array, array + sizeof(array) / sizeof(array[0]));

    // 在list的尾部插入4,头部插入0
    L.push_back(4);
    L.push_front(0);
    PrintList(L);

    // 删除list尾部节点和头部节点
    L.pop_back();
    L.pop_front();
    PrintList(L);
}

// insert /erase 
void TestList4()
{
    int array1[] = { 1, 2, 3 };
    list<int> L(array1, array1 + sizeof(array1) / sizeof(array1[0]));

    // 获取链表中第二个节点
    auto pos = ++L.begin();
    cout << *pos << endl;

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

    // 在pos前插入5个值为5的元素
    L.insert(pos, 5, 5);
    PrintList(L);

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

    // 删除pos位置上的元素
    L.erase(pos);
    PrintList(L);

    // 删除list中[begin, end)区间中的元素,即删除list中的所有元素
    L.erase(L.begin(), L.end());
    PrintList(L);
}

void TestList5()
{
    // 用数组来构造list
    int array1[] = { 1, 2, 3 };
    list<int> l1(array1, array1 + sizeof(array1) / sizeof(array1[0]));
    PrintList(l1);

    // 交换l1和l2中的元素
    list<int> l2;
    l1.swap(l2);
    PrintList(l1);
    PrintList(l2);

    // 将l2中的元素清空
    l2.clear();
    cout << l2.size() << endl;
}

In addition, list also provides its own sort() function for sorting, but the sort function is already provided in the STL algorithm library. Why is it provided here?

BecauseThere are three categories of iterators:One-way (such as singly linked list), a>bidirectional (such as list) and random iterator (such as vector), one-way Only ++ is supported, ++/-- is supported in both directions, and +/- is also supported randomly.

void test1()
{
	list<int> l;
	l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);
	//list不支持[]
	list<int>::iterator it = l.begin();
	while (it != l.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	//iterator性质分类
	//单向++
	//双向++/--
	//随机++/--/+/-
	// list没有办法使用算法库中的sort,所以额外支持sort  因为没有办法随机存取,所以使用归并排序
	//sort(l.begin(), l.end());//支持的是自由访问迭代器,可以++/--/+/-,这里迭代器是双向的只能++ --
	
	l.sort(); //默认升序 

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

1.2.6 Iterator invalidation

As mentioned before, here you can temporarily understand iterators as similar to pointers.The failure of an iterator means that the node pointed to by the iterator is invalid, that is, the node is deleted. . Because the underlying structure of the list is a bidirectional circular linked list with the head node, inserting into the list will not cause the iterator of the list to become invalid. It will only become invalid when deleting, and Only the iterator pointing to the deleted node will be invalidated, other iterators will not be affected.

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())
    {
        it = l.erase(it); // 或者 l.erase(it++); 
    }
}

This article is over! List For more detailed introduction, please refer to: list’s document introduction

Guess you like

Origin blog.csdn.net/qq_72916130/article/details/134318088