4双向链表(list)

1、list概述

list是一个双向链表,它的好处是每次插入或删除一个元素,就配置或释放一个元素空间,对于任何位置的元素插入或元素的移除,list永远是常数时间。list的节点结构如下:

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

2、list迭代器

list节点不保证在存储空间中连续存在,list迭代器必须有能力指向list的节点,并有能力进行正确的递增++、递减--、取值*、成员取用->,也就是递增时指向下一个节点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用的是节点的成员。由于list是一个双向链表,迭代器必须具备前移、后移的能力,所以list迭代器类型是Bidirectional Iterators。list一个重要性质:插入(insert)操作和接合(splice)操作都不会导致原来的list迭代器失效,这在vector是不成立的。

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) {}
  __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; }

  pointer operator->() const { return &(operator*()); }

  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;
  }
};

3、list数据结构

list不仅是一个双向链表,而且还是一个环状双向链表,所以它只需要一个指针,便可以完整表现整个链表。list会让指针node指向刻意置于尾端的一个空白节点,node便能符合STL对于前闭后开[begin,end)区间的要求,成为last迭代器。这么一来一下几个函数便都可以轻易实现:

iterator begin() { return (link_type)((*node).next); }
iterator end() { return node; }
bool empty() const { return node->next == node; }
  size_type size() const {
    size_type result = 0;
    distance(begin(), end(), result);
    return result;
 }
 reference front() { return *begin(); }
 reference back() { return *(--end()); }

4、list构造与内存管理

list有以下四个函数分别用来配置、释放、构造、销毁一个节点,list提供有许多constructors,其中一个是default constructor,用来不指定任何参数做出一个空的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);
  }

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

当我们以push_back()将新元素插入到list尾端时,此函数调用insert(),首先配置并构造一个节点,然后在尾端进行适当的指针操作,将新节点插入进去:

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;
 }

5、list元素操作

(1)push_front

插入一个节点,作为头节点

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

(2)push_back

插入一个节点,作为尾节点

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

(3)erase

移除迭代器position所指的节点

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)pop_front

移除头节点

void pop_front() { erase(begin()); }

(5)pop_back

移除尾节点

void pop_back() {
    iterator tmp = end();
    erase(--tmp);
  }

(6)clear

清除所有节点

template <class T, class Alloc>
void list<T, Alloc>::clear()
{
  link_type cur = (link_type) node->next;
  while (cur != node) {
    link_type tmp = cur;
    cur = (link_type) cur->next;
    destroy_node(tmp);
  }
  node->next = node;
  node->prev = node;
}

(7)remove

将数值为value的所有元素移除

template <class T, class Alloc>
void list<T, Alloc>::remove(const T& value) {
  iterator first = begin();
  iterator last = end();
  while (first != last) {
    iterator next = first;
    ++next;
    if (*first == value) erase(first);
    first = next;
  }
}

(8)unique

移除数值相同的连续元素,如果下一个节点值与当前节点值相等就移除,否则当前节点指向下一个节点

template <class T, class Alloc>
void list<T, Alloc>::unique() {
  iterator first = begin();
  iterator last = end();
  if (first == last) return;
  iterator next = first;
  while (++next != last) {
    if (*first == *next)
      erase(next);
    else
      first = next;
    next = first;
  }
}

(9)transfer

list内部提供一个迁移操作(transfer)非公开接口:将某连续范围[first,last)的元素迁移到某个特定位置postion之前。这个操作为其他复杂操作如slice、sort、merge等奠定良好的基础。

先将所有的next线牵起来再改变pre线:postion的前一个节点设为pre

  1. last的前一个节点指向pos
  2. first的前一个节点指向last
  3. pre的next指向first
  4. pos的prev指向last的前一个节点
  5. last的prev指向first的前一个节点
  6. first的prev指向pre
void transfer(iterator position, iterator first, iterator last) {
    if (position != last) {
      (*(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;
    }
  }

(10)splice

list公共提供的是接合操作(splice):将某连续范围[first,last)的元素从一个list移动到另一个或同一个list的某个定点position。

void splice(iterator position, list& x) {
    if (!x.empty())
      transfer(position, x.begin(), x.end());
  }
  void splice(iterator position, list&, iterator i) {
    iterator j = i;
    ++j;
    if (position == i || position == j) return;
    transfer(position, i, j);
  }
  void splice(iterator position, list&, iterator first, iterator last) {
    if (first != last)
      transfer(position, first, last);
  }

(11)merge

将两个排序好的list合并

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);
      first2 = next;
    }
    else
      ++first1;
  if (first2 != last2) transfer(last1, first2, last2);
}

(12)reverse

类似头插法将list逆序

template <class T, class Alloc>
void list<T, Alloc>::reverse() {
  if (node->next == node || link_type(node->next)->next == node) return;
  iterator first = begin();
  ++first;
  while (first != end()) {
    iterator old = first;
    ++first;
    transfer(begin(), old, first);
  }
}

(13)sort

采用quick sort,时间复杂度O(nlogn)

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()) {
    carry.splice(carry.begin(), *this, begin());
    int i = 0;
    while(i < fill && !counter[i].empty()) {
      counter[i].merge(carry);
      carry.swap(counter[i++]);
    }
    carry.swap(counter[i]);
    if (i == fill) ++fill;
  }

  for (int i = 1; i < fill; ++i) counter[i].merge(counter[i-1]);
  swap(counter[fill-1]);
}

单链表的quick sort

//快速排序head->next到tail的节点,其中head节点是为了方便比枢轴小的节点前移同时可以保持枢轴左右两边处于连接状态,属于无效节点不需要排序
ListNode* QuickSort(ListNode* head, ListNode* tail)
{
	if (head->next == tail || head == tail)
		return tail;
	else
	{
		//pre指向枢轴的左边最后一个节点,pivot为枢轴取第一个节点,end指向枢轴的右边最后一个节点
		ListNode* pre = head, * pivot = head->next, * end = head->next;
		//遍历枢轴右边所有的节点
		while (end->next != tail->next)
		{
			//比枢轴小的全部放到枢轴的前面
			if (end->next->val < pivot->val)
			{
				ListNode* cur = end->next;
				end->next = cur->next;
				pre->next = cur;
				pre = pre->next;
			}
			//比枢轴大的依然放在枢轴的后面,继续遍历下一个节点
			else
				end = end->next;
		}
		pre->next = pivot;    //保持左右两边连接
		QuickSort(head, pre);  //继续递归枢轴左边的节点
		QuickSort(pivot, end);  //继续递归枢轴右边的节点
		return head->next;  //head是无效节点,最后返回head->next
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值