list总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wk_bjut_edu_cn/article/details/83540021

list的节点

list本身和list的节点是不同的结构,下面是list的节点结构

template <class T>
struct __list_node {
  typedef void* void_pointer;
  void_pointer next;
  void_pointer prev;
  T data;
};

显然这是一个双向链表

list的迭代器

list不能够像vecor一样以普通指针作为迭代器,因为其节点不保证在存储空间中连续存在。list迭代器必须有能力指向list的节点,并有能力进行正确的递增、递减、取值、成员存取等操作。

由于STL list是一个双向链表,迭代器必须具备前移、后移的能力,所以list提供的是Bidirectional Iterators。

list的重要性质:插入操作和接合操作都不会造成原有的list迭代器失效。而在vector中的插入操作有可能造成扩容,需要吧元素从一个vector移到另一个vector,这就会会导致原有的迭代器全部失效。

list的数据结构

SGI list不仅是一个双向链表,而且还是一个环状双向链表,所以它只需要一个指针,便可以完整表现整个链表。

  iterator begin() { return (link_type)((*node).next); }
  iterator end() { return node; }
  reference front() { return *begin(); }
  const_reference front() const { return *begin(); }
  reference back() { return *(--end()); }
  const_reference back() const { return *(--end()); }

刻意让node指向置于尾端的一个空白节点,node便能符合STL对于“前闭后开”区间的要求,成为last迭代器。

list的构造与内存管理

list的缺省构造函数

  list() { empty_initialize(); }

  void empty_initialize() { 
    node = get_node();
    node->next = node;
    node->prev = node;
  }

  link_type get_node() { return list_node_allocator::allocate(); }

list的insert,其实就是在双向链表中插入一个节点

  void push_front(const T& x) { insert(begin(), x); }
  void push_back(const T& x) { insert(end(), x); }

  iterator insert(iterator position, const T& x) {
    link_type tmp = create_node(x);
    tmp->next = position.node;
    tmp->prev = position.node->prev;
    (link_type(position.node->prev))->next = tmp;
    position.node->prev = tmp;
    return tmp;
  }

list源码中最关键的代码 --迁移操作

//将[first,last)内的所有元素都移到pos之前

//注:区间是左闭右开的,将first到last前一个插入pos之前
void transfer(iterator pos,iterator first,iterator last)
{
    //last等于pos,就不用移动
    if(pos != last)
    {
        //1-4从左向右断开
        //(1)将last的前一个节点后继指向pos位置
        (*((link_node*)(*last.node).prev)).next = pos.node;
        //(2)将firt到last摘出去
        (*((link_node*)(*fisrt.node).prev)).next = last.node;
        //(3)将first和position的前一个节点接起来
        (*((link_node*)(*pos.node).prev)).next = frst.nod;

        //从右向左连接
        //(4)标记pos之前的节点,因为(5)断开后找不到这个位置
        link_node* tmp = link_node*((*pos.node).prev);
        //(5)pos前驱指向last之前的节点
        (*pos.node).prev = (*last.node).prev;
        //(6)last前驱指向fist之前的节点
        (*last.node).prev = (*first.node).prev;
        //(7)将first的前驱指向tmp节点
        (*first.node).prev = tmp;

    }
}

splice,sort,merge、reverse

通过transfer就可以实现这四个函数:将某连续范围的元素迁移到某个特定位置之前,就是一个指针的移动。

C++11新特性emplace操作

在引入右值引用,转移构造函数,转移复制运算符之前,通常使用push_back()向容器中加入一个右值元素(临时对象)的时候,首先会调用构造函数构造这个临时对象,然后需要调用拷贝构造函数将这个临时对象放入容器中。原来的临时变量释放。这样造成的问题是临时变量申请的资源就浪费。 
引入了右值引用,转移构造函数后,push_back()右值时就会调用构造函数和转移构造函数。 
在这上面有进一步优化的空间就是使用emplace_back
在容器尾部添加一个元素,这个元素原地构造,不需要触发拷贝构造和转移构造。而且调用形式更加简洁,直接根据参数初始化临时对象的成员。 

#include <vector>  
#include <string>  
#include <iostream>  
using namespace std;
struct President
{
	string name;
	string country;
	int year;

	President(string p_name, string p_country, int p_year)
		: name(std::move(p_name)), country(std::move(p_country)), year(p_year)
	{
		std::cout << "I am being constructed.\n";
	}
	President(const President& other)
		: name(std::move(other.name)), country(std::move(other.country)), year(other.year)
	{
		std::cout << "I am being copy constructed.\n";
	}
	President(President&& other)
		: name(std::move(other.name)), country(std::move(other.country)), year(other.year)
	{
		std::cout << "I am being moved.\n";
	}
	President& operator=(const President& other);
};

int main()
{
	vector<President> elections;
	cout << "emplace_back:\n";
	elections.emplace_back("Nelson Mandela", "South Africa", 1994); //没有类的创建  

	vector<President> reElections;
	cout << "\npush_back:\n";
	reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));

	cout << "\nContents:\n";
	for (President const& president : elections) {
		cout << president.name << " was elected president of "
			<< president.country << " in " << president.year << ".\n";
	}
	for (President const& president : reElections) {
		cout << president.name << " was re-elected president of "
			<< president.country << " in " << president.year << ".\n";
	}
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wk_bjut_edu_cn/article/details/83540021