list模板类的实现

 

目录

1.list的节点结构体

2.list的构造函数

3.list的增删查改

4.list的迭代器问题

5.list的排序问题


在学习STL中的list链表的过程中,对于其中主要功能的实现,我遇到了一些困难,因此在此总结一下问题所在。

1.list的节点结构体

在STL中,list的是带头双向循环链表的实现  ,其节点类型如下

      

既有上一节点的指针,也有下一节点的指针以及本节点的值。 

而在list类中存储一个头节点为开始,也是结尾,因此头节点的下一节点还是头节点是判断链表是否为空的条件。

2.list的构造函数

这里我主要介绍前两个常用构造函数, 如果想要理解其余的构造函数,可以点击

https://cplusplus.com/reference/list/list/list/

首先,第一个构造函数就是传入一个任何类型的引用变量,将其赋值给list链表,可以是数字,数组甚至字符串,如下:

list<int> L1(1);//数字
list<int> L2(1,2,3,4,5);//数组
list<string> L3("abc");//字符串

第二个构造函数也比较常用,其功能是传入一个整数和一个任何类型的数据,将整数个数据添加入链表中,如下:

list<int> L1(10,1);//添加十个数字1
list<int> L2(10,'a');//添加十个字符a
list<string> L3(10,"abc");//添加十个字符串abc

拷贝构造,赋值重载以及析构函数这里不再赘述。

3.list的增删查改

与vector不同的是,list的插入操作更加简单,头插头删,尾插尾删,任意位置插入与删除,list都能够实现。

首先是插入操作,list的插入操作不用考虑扩容,比较简单,我们大可不必全部写,而是只写一个insert (任意位置插入),而尾插与头插直接复用就行了,代码如下:

//我的代码
iterator insert(iterator pos, const T& x)                     
{
	Node* cur = pos._node;  //cur指向插入位置原来节点

	Node* prev = cur->_prev;  //prev指向插入位置的下一节点

	Node* newnode = new Node(x);  //创建新节点,值为x

    //处理指向
	prev->_next = newnode;
	newnode->_next = cur;

	cur->_prev = newnode;
	newnode->_prev = prev;

	
    //返回插入后的新pos位置
	return newnode;
}

//STL源码
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;
  }

其实源码与我写的原理相同,就是源码看起来更加高大上。。。

其次,在链表中的删除操作是很简单的,这里我们也是只要写一个任意位置删除的erase,其他删除操作进行复用就可以,学过数据结构的朋友都知道,删除操作很简单,改变指向加释放节点就能够实现,代码如下:

//我的代码
iterator erase(iterator pos)
{
	assert(pos != end());
    //改变指向信息
	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* next = cur->_next;
	prev->_next = next;
	next->_prev = prev;
    
    //释放节点
	delete cur;

	
    //返回更新后的pos位置
	return next;
}


//STL源码
iterator erase(iterator position) {
    link_type next_node = link_type(position.node->next);
    link_type prev_node = link_type(position.node->prev);
    prev_node->next = next_node;
    next_node->prev = prev_node;
    destroy_node(position.node);
    return iterator(next_node);
  }

4.list的迭代器问题

在学习STL的过程中,我们学习了vector的迭代器,但是vector的迭代器其实可以直接用指针进行替代,正是由于vector是一块连续的空间,但是在list之中,空间不是连续的,我们无法直接通过自增自减实现节点之间的跳跃,因此在list中,对于其迭代器的行为我们需要进行一些特殊处理。

这里提取list源码中的迭代器定义如下:

//同一个类模板实例化出的两个类型,便于实现const版本和非const版本
//STL源代码中的写法,通过利用多个模板参数来避免副本造成的代码冗余问题
template<class T, class Ref, class Ptr>
struct __list_iterator {

  typedef __list_iterator<T, T&, T*>             iterator;
  typedef __list_iterator<T, const T&, const T*> const_iterator;
  typedef __list_iterator<T, Ref, Ptr>           self;

  typedef bidirectional_iterator_tag iterator_category;
  typedef T value_type;
  typedef Ptr pointer;
  typedef Ref reference;
  typedef __list_node<T>* link_type;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;

  link_type node;

  __list_iterator(link_type x) : node(x) {}//使用x构造list迭代器
  
  __list_iterator() {}

  __list_iterator(const iterator& x) : node(x.node) {}

  bool operator==(const self& x) const { return node == x.node; }
  bool operator!=(const self& x) const { return node != x.node; }
  reference operator*() const { return (*node).data; }

#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

//为了区分前置和后置,统一在后置中加一个int参数
  self& operator++() { 
    node = (link_type)((*node).next);
    return *this;
  }
  self operator++(int) { 
    self tmp = *this;
    ++*this;
    return tmp;
  }

  self& operator--() { 
    node = (link_type)((*node).prev);
    return *this;
  }
  self operator--(int) { 
    self tmp = *this;
    --*this;
    return tmp;
  }
};

5.list的排序问题

在list中,一般不在成员函数中实现排序函数,因为,在list中直接进行排序是得不偿失的,相较而言,将其赋值到vector中进行排序后,在进行数据覆盖是更加高效的做法。

在vector和list中,也提供了通过迭代器始末进行构造的构造函数,如果一定要在成员函数中实现排序,使用堆排序是比较好的一种做法,眼见为实,我们进行五百万个数据的排序进行比较

 如下,其实我们也知道,sort是使用快速排序,比堆排序快是理所当然的,并且随着数据量的增加,差异会越来越大,而拷贝数据的效率消耗可以忽略不计。

如果在list中自己实现排序,对于少量数据还是有一定作用的,但是大量数据就会事半功倍。

以上是我个人学习list主要功能过程碰到的一些问题,总结以便复习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值