Take you deep into the STL list container

Source: Internet
Author: User
Tags prev

The vectors and arrays described in the previous blog, which have a contiguous memory space and have a constant starting address, are good for random access, but because of the continuous space, the insertion and deletion in the middle causes the memory block to be copied and moved, In addition, when there is not enough memory space, you need to reapply a large memory for the memory copy. To overcome these flaws, the STL defines another container list, which has an O (1) time complexity for data insertion and deletion, and no more frequent copy transfers in memory. Below, together to see the list of the source code to achieve it. List Overview

The list and vector are all STL sequential containers, the only difference being that the vector is a contiguous memory space, and the list is a discrete memory space, and the list needs only to configure or release an element space each time it inserts and deletes, compared to the vector. , the list can always do constant time for insertions and deletions anywhere. However, because the list does not support random addressing because of the discontinuous memory space, the ruler has a short length, and the choice of the container in the program depends on the construction complexity and the access behavior of the element. the node of the list

The node structure of the list is as follows:

Template <class t>
struct __list_node
{
  typedef void* void_pointer; 
  Void_pointer Next;    Type is void*, can also be set as __list_node<t>*
  void_pointer prev;
  T data;
};

From the node structure, it can be seen that the list is a two-way list, its structure as shown in the following figure:

iterator for list

In Vector, because it is continuous storage space, support random access, so its iterator can be directly replaced by ordinary pointers. But it won't work in the list. The list must have the ability to point to the nodes of the list, and to be able to perform the proper increment, decrement, value, and member access operations.

The

List is a two-way list, and the iterator must have the ability to move forward and back, so the list iterator is a bidirectional iterator. If the iterator fails after inserting and deleting operations in the vector, the list has an important property that the insert and join operations do not cause the original list iterator to fail. Also, when you delete a node, only the iterator that points to the deleted element is invalidated, and the other iterators are unaffected. Let's look at the source of the list iterator.

Template<class T, Class Ref, class ptr> struct __list_iterator {typedef __list_iterator<t, T&amp, t*>   iterator;
  Support iterator_traits typedef __list_iterator<t, const T&AMP;, const t*> const_iterator;

    typedef __list_iterator<t, REF, ptr> self; The following are some types of typedef bidirectional_iterator_tag Iterator_category defined to support iterator_traits;                                
  The iterator type of list is bidirectional iterator typedef T VALUE_TYPE;    
  typedef PTR Pointer;                                
  typedef REF Reference;
  typedef size_t SIZE_TYPE;

  typedef ptrdiff_t DIFFERENCE_TYPE;                     

  typedef __list_node<t>* LINK_TYPE;

  This is the resource pointer link_type node that the iterator actually manages; Iterator constructor __list_iterator (Link_type x): node (x) {} __list_iterator () {} __list_iterator (const iterator& x): N
  Ode (X.node) {}//In the STL algorithm requires iterators to provide support for bool operator== (const self& x) Const {return node = = X.node;} BOOL Operator!= (const self& x) Const {REturn node!= x.node;

  }//Overload operator *, returns the actual maintained data reference operator* () const {return (*node). Data}

  Member invocation operator pointer operator-> () const {return & (operator* ());}
    Prefix from self& operator++ () {node = (Link_type) ((*node). Next);
  return *this;
    }//suffix is added, it needs to produce a copy of itself first, then it will operate on itself, and finally return the copy 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; }
}

The iterator of list implements the operation of ==,!=,++,–, value and member invocation, because it is stored in the discontinuous memory space, so the p+n operation of vector is not supported. data structure of list

List of data structure of a list of node data structure is defined separately, SGI list is not only a two-way linked list, but also a circular two-way linked list, so it only needs a pointer, you can fully represent a linked list.

Template <class T, class Alloc = alloc>
class list
{
protected:
  typedef void* Void_pointer;
  typedef __list_node<t> List_node;

  This provides STL standard allocator interface
  typedef simple_alloc<list_node, alloc> list_node_allocator;

  The head node of the linked list does not store the data
  link_type node;

  //.... The following is also a list of action functions
}

List Constructor

The list provides an empty constructor, as follows:

List () {empty_initialize ();}

For the establishment of an empty list
void Empty_initialize ()
{
  node = Get_node ();
  node->next = node;  The front node points to itself
  Node->prev = node;  The back node points to itself
}

In addition, the list provides a constructor with a parameter that supports the following initialization operations:

List<int> myList (5,1); Initializes 5 1-linked lists, {1,1,1,1,1}

The source code of its constructor is as follows:

With parameter constructor
list (size_type N, const t& value) {fill_initialize (n, value);}

Creates a linked list
void Fill_initialize (size_type n, const t& value)
{
  empty_initialize ()  with value of n nodes. First create an empty list insert
  (begin (), n, value);//insert N Value of node
}

//insert n x at specified location
void Insert (iterator pos , int n, const t& x)
{
  Insert (pos, (size_type) n, x);
}

Insert n
Template <class T, class alloc>
void List<t, Alloc>::insert (iterator) before position Position, Size_type N, const t& x)
{for
  (; n > 0;--n)
    Insert (position, x);

Okay, here's the real insert operation
//very simple bidirectional linked list insert operation
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;
}

The STL list provides a number of constructors, which I've listed here as an example. Other action functions for list Get_node

This function is used to configure a node.

Configures a node and returns
Link_type Get_node () {return 
    list_node_allocator::allocate (); 
}
Put_node

This function is used to free a node.

Releases the specified node, without destructors, to the global destroy,
void Put_node (Link_type p) {
    list_node_allocator::d eallocate (P); 
}
Create_node

This function is used to configure and construct a node and initialize its value

Configures a node and initializes its value to x
link_type create_node (const t& x)
{
  Link_type p = get_node ();
  Construct (&p->data, x);   global function return
  p;
}
Destory_node

This function is used to deconstruct a node.

Destructors the node element and frees the memory
void Destroy_node (Link_type p)
{
    destroy (&p->data);  Global function
    Put_node (p);
}
Insert

This function is used to insert a node in the development location (this function is mentioned above, repeat here, the main insertion of the list is given to this function), the function is an overloaded function, which has many forms.

Okay, here's the real insert operation
//very simple bidirectional linked list insert operation
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;
}
It also has the following multiple forms of overloaded functions
//inserting elements within [first,last] intervals
template <class T, class alloc> template <class inputiterator>
void List<t, Alloc>::insert (iterator position,
                            inputiterator-A, Inputiterator Last)
{
  for (; I!= last; ++first)
    Insert (position, *first);
}
Inserts an element at the position position, and the element calls the type default constructor
iterator insert (iterator position) {return insert (position, T ());
push_back

At the end of the insert element, with the above insert function, Push_back is easier to implement.

Insert node
void push_back (const t& x) {Insert (end (), X) on the linked list
Pop_front
Inserts a node
void Push_front (const t& x) {insert (Begin (), X) at the front end of the list;
Earse

Remove the element that the iterator refers to

Erase
The operation of the specified node iterator erase (iterator position)
{
    //bidirectional linked list removing nodes
    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);
}

The above function also has an overloaded version that removes all nodes in the interval/
/erase node
template <class T, class alloc>
list<t, Alloc>::iterator list<t, Alloc>::erase (iterator-I, iterator last) {while (before-
    != last) Erase ( first++);
    return to last;
}
Pop_front

Remove the head node elements, with the above erase function, it is very convenient to implement.

Deletes the first node void Pop_front () {erase () of the linked list (
begin ());}
Pop_back

Remove the last element in a linked list

Deletes the last node of the linked list
void Pop_back ()
{
    iterator tmp = end ();
    Erase (--TMP);
}
Clear

Clears all nodes in a linked list, that is, a single purge

Destroy all nodes, place the linked list empty
template <class T, class alloc>
void List<t, Alloc>::clear ()
{
  link_ Type cur = (link_type) node->next;
  while (cur!= node) {//Traverse each node
    link_type tmp = cur;
    Cur = (link_type) cur->next;
    Destroy_node (TMP);
  }
  Node->next = node;//after removal Note to keep the linked list is a cyclic list
  Node->prev = node;
Remove

Remove a node with value in the list

Removes all nodes
//Time complexity O (n)
template <class T, class alloc>
void List<t, Alloc>::remove (const t&) for a specific value Amp Value)
{
    iterator-i = begin ();
    Iterator last = end ();
    while (the!= last) {//guarantee that the list is not empty
        iterator next = A;
        ++next;
        if (*first = = value) erase (a);  Erase the node
        , the next;
Transfer

Migrates elements in a contiguous range to a specified location. (non-public interface)

void transfer (iterator position, iterator a, iterator last)
{
    if (position!=)
    {
        (*) (LINK_ Type ((*last.node). prev)). Next = Position.node;
        (* (Link_type (*first.node). prev)). Next = Last.node;
        (* (Link_type (*position.node). prev)). Next = First.node;
        Link_type tmp = Link_type ((*position.node). prev);
        (*position.node). Prev = (*last.node). prev;
        (*last.node). Prev = (*first.node). prev;
        (*first.node). prev = tmp;
    }
}

Here, borrow Mr. Houtie's "STL Source Analysis" in a picture to illustrate this process.

Splice

The join function provided by list is splice, and the above transfer is a non-public function. There are several versions of the splice function:

Move the list x before position
void splice (iterator position, list& x)
{
    if (!x.empty ())
        Transfer (position , X.begin (), X.end ()); Just call the transfer function
}

//Move the I-pointed content in the list to position before
void splice (iterator position, list& iterator i)
{
    iterator j = i;
    ++j;
    if (position = i | | | position = = j) return;
    Transfer (position, I, j);
}

Move [First, last} elements before position
void splice (iterator position, List&, iterator first, iterator last)
{ C17/>if (!= last)
        transfer (position, I, last);
}
Merge

This function is used to merge two lists, where the two lists must be well sequenced.

Suppose the current container and X are ordered to ensure that the two containers are merged and still ordered
template <class T, class alloc>
void List<t, Alloc>::merge (List<t, alloc>& x)
{
  iterator first1 = begin ();
  Iterator Last1 = end ();
  Iterator First2 = X.begin ();
  Iterator last2 = X.end ();
  while (First1!= last1 && first2!= last2)
    if (*first2 < *first1) {
      iterator next = first2;
      Transfer (First1, First2, ++next); After migrating the FIRST2 node to first1
      first2 = next;
    else
      ++first1;
  if (first2!= last2) transfer (Last1, First2, last2);  If the first2 still has the remaining, direct join again linked List 1 tail
}
Reverse

This function is used to reverse the linked list, which is specifically implemented as follows:

Invert the list to
template <class T, class alloc>
void List<t, Alloc>::reverse ()
{
  if (node-> Next = node | | Link_type (node->next)->next = = node) return;
  Iterator-A-begin ();
  ++first;
  while (the!= end ()) {
    iterator old = i;   Remove a node
    ++first;
    Transfer (begin (), old, and a);  Insert after begin ()}
Sort

This function sorts the list in ascending order, which is implemented as follows:

Sorted in ascending order
template <class T, class alloc>
void List<t, Alloc>::sort ()
{
  if (Node->next = = Node | | Link_type (node->next)->next = = node) return;
  List<t, alloc> carry;
  List<t, alloc> counter[64];
  int fill = 0;
  while (!empty ()) {
    //takes a node from the list
    Carry.splice (Carry.begin (), *this, Begin ());
    int i = 0;
    Merge the new elements in the carry with the results in counter while
    (I < fill &&!counter[i].empty ()) {
      Counter[i].merge ( carry);
      Carry.swap (counter[i++]);
    The merged results are deposited in the counter[i]
    Carry.swap (counter[i]);
    has reached 2*fill,fill 1
    if (i = = fill) ++fill;
  }
  Merges all elements in the counter for
  (int i = 1; i < fill; ++i) Counter[i].merge (counter[i-1));
  Swap the counter linked list and this list for swaps
  (Counter[fill-1]);

Exchange this list and list x
void swap (list<t, alloc>& x) { 
    Swap (node, x.node); 
}

Here is an example to illustrate this process: (To list 5,3,6,4,7,9,1,2,8)

Carry each time you take a number from an array and then merge it into the counter array, the algorithm can only sort 2 of 64 of the number of times.

"STL Source Analysis" Written here is a quick sort, in fact I think should be merge sort. PostScript

List chain provides a lot of operation functions, read the source feel that they have reviewed the data structure of the commonly used linked list operations, but also mastered the STL linked list of commonly used functions. Benefit.. In addition, sort does not know is Mr. Houtie's clerical error or what, how does not look like is the quick sort. Finally, we have any doubts can be the bottom of the message.

Reference: Mr. Houtie's "STL Source Analysis" C + + STL Source Analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.