首页 > 其他分享 >list容器

list容器

时间:2024-04-21 17:12:36浏览次数:29  
标签:node 容器 typedef const iterator list type

list 是一种双向链表。list 的设计更加复杂一点,好处是每次插入或删除一个元素,就配置或释放一个元素,list 对于空间的运用有绝对的精准,一点也不浪费。而且对于任何位置的元素插入或删除,list 永远是常数空间。

list 源码分成了两个部分,一个部分是 list 结构另一部分是 list 节点的结构

为什么 list 节点分为了两个部分,而不是在一个结构体里面呢? 也就是说为什么指针变量和数据变量分开定义呢?这里是为了给迭代器做铺垫,因为迭代器遍历的时候不需要数据成员的,只需要前后指针就可以遍历该 list。

1. list node结构

__list_node 用来实现节点,数据结构中就储存前后指针和属性。

template <class T> struct __list_node {
    // 前后指针
   typedef void* void_pointer;
   void_pointer next;
   void_pointer prev;
    // 属性
   T data;
};

基本类型

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;  
 
    // 迭代器是bidirectional_iterator_tag类型
   typedef bidirectional_iterator_tag iterator_category;
   typedef T value_type;
   typedef Ptr pointer;
   typedef Ref reference;
   typedef size_t size_type;
   typedef ptrdiff_t difference_type;
    ... 
};

构造函数:

template<class T, class Ref, class Ptr> struct __list_iterator {
    ...
    // 定义节点指针
   typedef __list_node<T>* link_type;
   link_type node;
 	// 构造函数
   __list_iterator(link_type x) : node(x) {}
   __list_iterator() {}
   __list_iterator(const iterator& x) : node(x.node) {}
   ... 
};

重载:

template<class T, class Ref, class Ptr> struct __list_iterator  {
    ...
   // 重载
   bool operator==(const self& x) const { return node == x.node; }
   bool operator!=(const self& x) const { return node != x.node; }
   ...

   // ++和--是直接操作的指针指向next还是prev, 因为list是一个双向链表
   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;
   }
};

2. list 结构

list 迭代器是 bidirectional_iterator_tag 类型,并不是一个普通指针。list在定义 node 节点时, 定义的不是一个指针。

template <class T, class Alloc = alloc>
class list {
protected:
    typedef void* void_pointer;
    typedef __list_node<T> list_node; // 节点 就是前面分析过的
    typedef simple_alloc<list_node, Alloc> list_node_allocator; // 空间配置器
public:      
    // 定义嵌套类型
    typedef T value_type;
    typedef value_type* pointer;
    typedef const value_type* const_pointer;
    typedef value_type& reference;
    typedef const value_type& const_reference;
    typedef list_node* link_type;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    
protected:
    // 定义一个节点, 这里节点并不是一个指针.
    link_type node;
    
public:
    // 定义迭代器
    typedef __list_iterator<T, T&, T*>             iterator;
    typedef __list_iterator<T, const T&, const T*> const_iterator;
 	...
};

3. 成员函数

成员函数 功能
begin() 返回指向容器中第一个元素的双向迭代器。
end() 返回指向容器中最后一个元素所在位置的下一个位置的双向迭代器。
rbegin() 返回指向最后一个元素的反向双向迭代器。
rend() 返回指向第一个元素所在位置前一个位置的反向双向迭代器。
cbegin() 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
cend() 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crbegin() 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crend() 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
empty() 判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。
size() 返回当前容器实际包含的元素个数。
max_size() 返回容器所能包含元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。
front() 返回第一个元素的引用。
back() 返回最后一个元素的引用。
assign() 用新元素替换容器中原有内容。
emplace_front() 在容器头部生成一个元素。该函数和 push_front() 的功能相同,但效率更高。
push_front() 在容器头部插入一个元素。
pop_front() 删除容器头部的一个元素。
emplace_back() 在容器尾部直接生成一个元素。该函数和 push_back() 的功能相同,但效率更高。
push_back() 在容器尾部插入一个元素。
pop_back() 删除容器尾部的一个元素。
emplace() 在容器中的指定位置插入元素。该函数和 insert() 功能相同,但效率更高。
insert() 在容器中的指定位置插入元素。
erase() 删除容器中一个或某区域内的元素。
swap() 交换两个容器中的元素,必须保证这两个容器中存储的元素类型是相同的。
resize() 调整容器的大小。
clear() 删除容器存储的所有元素。
splice() 将一个 list 容器中的元素插入到另一个容器的指定位置。
remove(val) 删除容器中所有等于 val 的元素。
remove_if() 删除容器中满足条件的元素。
unique() 删除容器中相邻的重复元素,只保留一个。
merge() 合并两个事先已排好序的 list 容器,并且合并之后的 list 容器依然是有序的。
sort() 通过更改容器中元素的位置,将它们进行排序。
reverse() 反转容器中元素的顺序。

4. 析构和构造

每个构造函数都会创造一个空的 node 节点,为了保证我们在执行任何操作都不会修改迭代器。

list 默认使用 alloc 作为空间配置器,并根据这个另外定义了一个 list_node_allocator,目的是更加方便以节点大小来配置单元

template <class T, class Alloc = alloc>
class list {
protected:
    typedef void* void_pointer;
    typedef __list_node<T> list_node; // 节点
    typedef simple_alloc<list_node, Alloc> list_node_allocator; // 空间配置器
}

其中,list_node_allocator(n)表示配置 n 个节点空间。以下四个函数,分别用来配置,释放,构造,销毁一个节点。

 

class list {
protected:
      // 配置一个节点并返回
      link_type get_node() { return list_node_allocator::allocate(); }
      // 释放一个节点
      void put_node(link_type p) { list_node_allocator::deallocate(p); }
      // 产生(配置并构造)一个节点带有元素初始值
      link_type create_node(const T& x) {
          link_type p = get_node();
          __STL_TRY {
            construct(&p->data, x);
          }
          __STL_UNWIND(put_node(p));
          return p;
      }
      //销毁(析构并释放)一个节点
      void destroy_node(link_type p) {
            destroy(&p->data);
            put_node(p);
      }
      // 对节点初始化
      void empty_initialize() { 
            node = get_node();
            node->next = node;
            node->prev = node;
      }  
};

5. 基本属性获取

template <class T, class Alloc = alloc>
class list {
    ...
public: 
 	iterator begin() { return (link_type)((*node).next); } // 返回指向头的指针
    const_iterator begin() const { return (link_type)((*node).next); }
    iterator end() { return node; } // 返回最后一个元素的后一个的地址
    const_iterator end() const { return node; }
    
    // 这里是为旋转做准备, rbegin返回最后一个地址, rend返回第一个地址. 我们放在配接器里面分析
    reverse_iterator rbegin() { return reverse_iterator(end()); }
    const_reverse_iterator rbegin() const { 
      	return const_reverse_iterator(end()); 
    }
    reverse_iterator rend() { return reverse_iterator(begin()); }
    const_reverse_iterator rend() const { 
      	return const_reverse_iterator(begin());
    } 
    
    // 判断是否为空链表, 这是判断只有一个空node来表示链表为空.
    bool empty() const { return node->next == node; }
    // 因为这个链表, 地址并不连续, 所以要自己迭代计算链表的长度.
    size_type size() const {
          size_type result = 0;
          distance(begin(), end(), result);
          return result;
    }
    size_type max_size() const { return size_type(-1); }
    // 返回第一个元素的值
    reference front() { return *begin(); }
    const_reference front() const { return *begin(); }
    // 返回最后一个元素的值
    reference back() { return *(--end()); }
    const_reference back() const { return *(--end()); }
    
    // 交换
    void swap(list<T, Alloc>& x) { __STD::swap(node, x.node); }
    ...
};
template <class T, class Alloc>
inline void swap(list<T, Alloc>& x, list<T, Alloc>& y) {
   	x.swap(y);
}

6. 插入和删除操作

在 list 中,push 操作都调用 insert 函数, pop 操作都调用 erase 函数。

template <class T, class Alloc = alloc>
class list {
    ...
    // 直接在头部或尾部插入
    void push_front(const T& x) { insert(begin(), x); } 
    void push_back(const T& x) { insert(end(), x); }
    // 直接在头部或尾部删除
    void pop_front() { erase(begin()); } 
    void pop_back() { 
          iterator tmp = end();
          erase(--tmp);
    }
    ...
};

上面的两个插入函数内部调用的 insert 函数。

class list {
    ...
public:
    // 最基本的insert操作, 之插入一个元素
    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 函数来实现的, 其他的所有函数都是直接或间接调用 erase。list 是链表, 所以链表怎么实现删除, list 就在怎么操作:很简单,先保留前驱和后继节点, 再调整指针位置即可。由于它是双向环状链表,只要把边界条件处理好,那么在头部或者尾部插入元素操作几乎是一样的,同样的道理,在头部或者尾部删除元素也是一样的。

template <class T, class Alloc = alloc>
class list {
     ...
 	 iterator erase(iterator first, iterator last);
     void clear();   
     // 参数是一个迭代器 修改该元素的前后指针指向再单独释放节点就行了
     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);
     }
     ...
};

 

标签:node,容器,typedef,const,iterator,list,type
From: https://www.cnblogs.com/love-9/p/18149168

相关文章

  • vcetor容器
    1.基本数据结构template<classT,classAlloc=alloc>classvector{public:typedefTvalue_type;typedefvalue_type*pointer;typedefconstvalue_type*const_pointer; //定义迭代器,这里就只是一个普通的指针typedefvalue_type*iter......
  • 快速理解Laravel容器(IOC、DI、Provider、Contract)
    源码理解思维的提升分享一些个人见解。Laravel里面的某些概念,就像魔术一样,看起来很厉害,当知道魔术怎么变的,就会认为也不过如此。所以不必感觉Laravel里有些概念难以理解。应当抛除被框架约束思维的枷锁,用PHP设计的角度去思考,关注大概,而不是在在框架层面逐行磨叽。毕竟源码那么......
  • 在Linux中,如何实现虚拟机和容器之间的互操作性?
    在Linux中,实现虚拟机和容器之间的互操作性是一个涉及多个步骤的过程。以下是一些关键的步骤和考虑因素:选择适合的虚拟化技术和容器技术:虚拟化技术:常见的虚拟化技术有VMware、VirtualBox等。它们允许你在一个物理机上创建和运行多个虚拟机,每个虚拟机都有自己的操作系统和应用程......
  • 在Linux中,如何优化虚拟机和容器的性能和资源使用?
    在Linux中优化虚拟机(VM)和容器的性能和资源使用涉及多个层面,以下是一些关键的优化策略:1.虚拟机性能优化:合理配置CPU资源:根据虚拟机的实际需求分配合适的vCPU数量,避免过度分配导致资源争抢。启用CPU亲和性设置,保证虚拟机在物理CPU核心上的稳定调度。使用NUMA(Non-UniformMe......
  • 在Linux中,如何进行虚拟机和容器的备份和迁移?
    在Linux环境中,虚拟机和容器(如Docker容器)的备份和迁移过程有所不同,下面分别详细说明:1.虚拟机的备份与迁移虚拟机备份使用虚拟化平台工具:对于VMware环境,可以通过以下步骤进行备份:关闭或暂停虚拟机以确保数据一致性。右键单击虚拟机,在管理菜单中选择“克隆”,根据需要选择......
  • Java 集合进阶使用(List Map Set)
    CollectionCollection是其子集的父类,所以可以使用多态的规矩,比如:创建一个ArrayList对象,用Collection接收Collection<Integer>collection=newArrayList<>();注意:Collection为接口,不能直接创建对象,但可以利用其子类,使用Collection方法,就如上方代码一样Collection......
  • C++ STL -- list
    listlist是一种基于双向链表的数据结构,适用于需要在序列中执行频繁插入和删除操作的场景特性本质上是一个双向链表,允许在序列的两端和中间执行插入和删除操作只能通过迭代器访问元素,即访问元素的时间复杂度为\(O(n)\)动态内存管理,内部通过类似指针的节点实现元素存储,一个节......
  • centos6.5重启docker容器死机问题
      概述近期在整理服务问题,使用docker容器重新部署服务。过程中有不少坑,主要是系统配置和系统版本的问题。环境CentOSrelease6.5(Final)dockerversion1.7.1问题现象使用restart命令重启docker容器,系统突然卡死,并不断重启,重启3次后恢复。检查系统日志“/var/log/......
  • day15_我的Java学习笔记 (Collection、数据结构、List、泛型深入)
    1.集合概述2.Collection集合的体系特点3.Collection集合常用API1.添加元素,添加成功返回true,失败返回false2.清空集合的元素3.判断集合是否为空,是空返回true,反之为false4.获取集合的大小5.判断集合中是否包含某个元素6.删除某个元素(......
  • WPF/C#:让绘制的图形可以被选中并将信息显示在ListBox中
    实现的效果如果你对此感兴趣,可以接着往下阅读。实现过程绘制矩形比如说我想绘制一个3行4列的表格:privatevoidButton_Click_DrawRect(objectsender,RoutedEventArgse){intRow=3;intCol=4;for(inti=0;i<Row;i++){......