【STL】list的应用和模拟实现

1.认识STL

    STL(标准模板库)是C++标准库的重要组成部分,共六大组件:容器,算法,迭代器,仿函数,适配器,空间配置器。此篇博客主要讲容器里的list的应用和简化版的模拟实现。

2.list的相关应用

    list可以说是我们平常所写的链表,但是不完全相同,库里的list是一个用模板实现的双向循环链表。除此之外还包括迭代器的一些操作。我们先来看看list它都包含些什么:


    我们先看迭代器的相关操作,迭代器是用来访问容器的。list的迭代器相当于一个指针,但其实它并不是指针,相当于对结点的一个封装。

    begin():它返回的是头结点的下一个结点。因为库里的list是带头结点的链表。

    end(): 它返回的是头结点,也就是说返回尾结点的下一个结点。

   所以如果我们可以通过下面的代码来遍历list:

// list::begin
#include <iostream>
#include <list>
using namespace std;

int main ()
{
  int myints[] = {75,23,65,42,13};
  list<int> mylist (myints,myints+5);

  list<int>::iterator it;

  cout << "mylist contains:";
  for ( it=mylist.begin() ; it != mylist.end(); it++ )
    cout << " " << *it;

  cout << endl;

  return 0;
}


可以看出来,迭代器总是会给一个左闭右开的区间。

rbegin()和rend()是逆序访问list的意思,看下面的测试代码你就明白了。

// list::rbegin/rend
#include <iostream>
#include <list>
using namespace std;

int main ()
{
  list<int> mylist;
  for (int i=1; i<=5; i++) mylist.push_back(i);

  cout << "mylist contains:";
  list<int>::reverse_iterator rit;
  for ( rit=mylist.rbegin() ; rit != mylist.rend(); ++rit )
    cout << " " << *rit;

  cout << endl;

  return 0;
}


输出:5 4 3 2 1 


    当然首先它有构造函数,析构函数和赋值运算符重载,有一定C++基础的话都知道它们是用来干什么的。

    

 这是list里面包含的一些成员方法:

    assign()是赋值操作,在实际的开发中很少会用到。

    void assign ( InputIterator first, InputIterator last );  //传进来两个迭代器,assign用两个迭代器之间的内容来填充对象。
    void assign ( size_type n, const T& u );                //用n个u来填充对象


  看以下测试用例:

   

// list::assign
#include <iostream>
#include <list>
using namespace std;

int main ()
{
  list<int> first;
  list<int> second;

  first.assign (7,100);                      // 7 ints with value 100

  second.assign (first.begin(),first.end()); // a copy of first

  int myints[]={1776,7,4};
  first.assign (myints,myints+3);            // assigning from array
 
  cout << "Size of first: " << int (first.size()) << endl;      //3
  cout << "Size of second: " << int (second.size()) << endl;    //7
  return 0;
}


    push_front是头插。函数原型如下:

    

void push_front ( const T& x );


它是如何使用的呢:

#include<iostream>
#include<list>

using namespace std;
void TestList()
{
	list<int> li;
	li.push_front(1);
	li.push_front(2);
	li.push_front(3);
	li.push_front(4);
	li.push_front(5);
	list<int>::iterator it;
	for (it = li.begin(); it != li.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
输出:


pop_front()顾名思义,头删,也很简单。这里就不再列举测试代码了

push_back() 尾插,和头插类似。

pop_back() 尾删。

insert()插入操作,函数原型:

iterator insert ( iterator position, const T& x );   //在position前面插入元素x
    void insert ( iterator position, size_type n, const T& x );   //在position前面插入n个x
template <class InputIterator>
    void insert ( iterator position, InputIterator first, InputIterator last );   //在position前面插入从first到last之间的内容


测试一下:


#include<iostream>
#include<list>
using namespace std;
void TestList()
{
	list<int> li;
	li.push_front(1);
	li.push_front(2);
	li.push_front(3);
	li.push_front(4);
	li.push_front(5);
	list<int>::iterator it;
	for (it = li.begin(); it != li.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	li.insert(li.begin(), 10);    //前面插个10
	for (it = li.begin(); it != li.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	li.insert(li.end(), 3, 6);    //后面插3个6
	cout << endl;
	for (it = li.begin(); it != li.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
输出:

erase删除相关操作。函数原型:

iterator erase ( iterator position );   //删除position位置的元素并返回其后位置的迭代器。
iterator erase ( iterator first, iterator last );  //删除[first,last)区间的结点,并且返回last位置的迭代器。

#include <iostream>
#include <list>
using namespace std;

int main ()
{
  unsigned int i;
  list<unsigned int> mylist;
  list<unsigned int>::iterator it1,it2;

  // set some values:
  for (i=1; i<10; i++) mylist.push_back(i*10);

                              // 10 20 30 40 50 60 70 80 90
  it1 = it2 = mylist.begin(); // ^^
  advance (it2,6);            // ^                 ^
  ++it1;                      //    ^              ^

  it1 = mylist.erase (it1);   // 10 30 40 50 60 70 80 90
                              //    ^           ^

  it2 = mylist.erase (it2);   // 10 30 40 50 60 80 90
                              //    ^           ^

  ++it1;                      //       ^        ^
  --it2;                      //       ^     ^

  mylist.erase (it1,it2);     // 10 30 60 80 90
                              //        ^

  cout << "mylist contains:";
  for (it1=mylist.begin(); it1!=mylist.end(); ++it1)
    cout << " " << *it1;
  cout << endl;

  return 0;
}

swap()设计到容器适配器,我们先不看它。

clear(),删除链表中的全部结点。很简单,这里不再测试。

 

这是list的容器适配器部分的内容。

splice()  //往一个list里的某个位置插入另一个list的元素。

// splicing lists
#include <iostream>
#include <list>
using namespace std;

int main ()
{
  list<int> mylist1, mylist2;
  list<int>::iterator it;

  // set some initial values:
  for (int i=1; i<=4; i++)
     mylist1.push_back(i);      // mylist1: 1 2 3 4

  for (int i=1; i<=3; i++)
     mylist2.push_back(i*10);   // mylist2: 10 20 30

  it = mylist1.begin();
  ++it;                         // points to 2

  mylist1.splice (it, mylist2); // mylist1: 1 10 20 30 2 3 4
                                // mylist2 (empty)
                                // "it" still points to 2 (the 5th element)
                                          
  mylist2.splice (mylist2.begin(),mylist1, it);
                                // mylist1: 1 10 20 30 3 4
                                // mylist2: 2
                                // "it" is now invalid.
  it = mylist1.begin();
  advance(it,3);                // "it" points now to 30

  mylist1.splice ( mylist1.begin(), mylist1, it, mylist1.end());
                                // mylist1: 30 3 4 1 10 20

  cout << "mylist1 contains:";
  for (it=mylist1.begin(); it!=mylist1.end(); it++)
    cout << " " << *it;

  cout << "\nmylist2 contains:";
  for (it=mylist2.begin(); it!=mylist2.end(); it++)
    cout << " " << *it;
  cout << endl;

  return 0;
}


remove()函数原型:

void remove ( const T& value );  //找出value然后删除
remove_if()函数原型:

void remove_if ( Predicate pred );   //条件删除,参数是条件,在特定删除是特别方便,比如删除奇数或者删除10以下的数
// list::remove_if
#include <iostream>
#include <list>
using namespace std;

// a predicate implemented as a function:
bool single_digit (const int& value) { return (value<10); }    //判断数据是否小于10

// a predicate implemented as a class:
class is_odd
{
public:
  bool operator() (const int& value) {return (value%2)==1; }    //判断是否是奇数
};

int main ()
{
  int myints[]= {15,36,7,17,20,39,4,1};
  list<int> mylist (myints,myints+8);   // 15 36 7 17 20 39 4 1

  mylist.remove_if (single_digit);      // 15 36 17 20 39

  mylist.remove_if (is_odd());          // 36 20

  cout << "mylist contains:";
  for (list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    cout << " " << *it;
  cout << endl;

  return 0;
}


unique()函数原型:

void unique ( );  //去掉重复值
template <class BinaryPredicate>
  void unique ( BinaryPredicate binary_pred );  //条件去重,比如浮点数整数部分相同的删除掉,或者两数相差小于5的删除掉

// list::unique
#include <iostream>
#include <cmath>
#include <list>
using namespace std;

// a binary predicate implemented as a function:
bool same_integral_part (double first, double second)
{ return ( int(first)==int(second) ); }

// a binary predicate implemented as a class:
class is_near
{
public:
  bool operator() (double first, double second)
  { return (fabs(first-second)<5.0); }
};

int main ()
{
  double mydoubles[]={ 12.15,  2.72, 73.0,  12.77,  3.14,
                       12.77, 73.35, 72.25, 15.3,  72.25 };
  list<double> mylist (mydoubles,mydoubles+10);
  
  mylist.sort();             //  2.72,  3.14, 12.15, 12.77, 12.77,
                             // 15.3,  72.25, 72.25, 73.0,  73.35

  mylist.unique();           //  2.72,  3.14, 12.15, 12.77
                             // 15.3,  72.25, 73.0,  73.35

  mylist.unique (same_integral_part);  //  2.72,  3.14, 12.15
                                       // 15.3,  72.25, 73.0

  mylist.unique (is_near());           //  2.72, 12.15, 72.25

  cout << "mylist contains:";
  for (list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    cout << " " << *it;
  cout << endl;

  return 0;
}


注意:unique是在有序的前提下进行去重。所以,在使用它之前最好先对list排一下序。

merge()函数原型:

void merge ( list<T,Allocator>& x );  //将x 和对象进行合并,合并完成后x里数据全部被删除掉
template <class Compare>
  void merge ( list<T,Allocator>& x, Compare comp );


sort()函数原型:

  void sort ( );
template <class Compare>
  void sort ( Compare comp );


对list中的元素进行排序。

reverse()函数原型:

void reverse ( );

很简单,对list进行逆序。

    

    front()返回头结点的数据。

    back()返回尾结点的数据。

3.简单模拟实现list

#pragma once
#include<iostream>
#include<cassert>
using namespace std;

template <class T>
struct LinkNode
{
	typedef LinkNode<T> node;
	LinkNode(T n=0)
		:_data(n), _prev(0), _next(0)
	{}
	T _data;
	node * _prev;
	node * _next;
};


template <class T,class Ptr,class Ref>
class LinkIterator
{
public:
	typedef LinkIterator<T, Ptr, Ref> Self;
	typedef LinkIterator<T, T*, T&> Iterator;
	typedef LinkNode<T> node;

	LinkIterator(node* x)
		:_node(x)
	{}
	LinkIterator()
	{}
	LinkIterator(const Self& it)
	{
		_node = it._node;
	}
	bool operator==(const Self& it)
	{
		return _node == it._node;
	}
	bool operator!=(const Self& it)
	{
		return _node != it._node;
	}
	Ref operator*()
	{
		return _node->_data;
	}

	Ptr operator->()
	{
		return &(_node->_data);
	}

	Self& operator++()
	{
		_node = _node->_next;
		return *this;
	}

	Self operator++(int)
	{
		Self tmp(*this);
		_node = _node->_next;
		return tmp;
	}

	Self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}

	Self operator--(int)
	{
		Self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}
	node* _node;

};
template <class T>
class Link
{
public:

	typedef LinkIterator<T, T*, T&> Iterator;
	typedef Link<T> link;
	typedef LinkNode<T> node;
	typedef node* node_type;
	Link()
		:_head(new node(T()))
	{
		_head->_next = _head;
		_head->_prev = _head;
	}
	~Link()
	{
		Clear();
		delete _head;
		_head = NULL;
	}
	/*****************插入相关操作**********************/
	void PushBack(T x)   //尾插
	{
		/*node* NewNode = BuyNewNode(x);
		node* tmp = _head->_prev;
		NewNode->_prev = tmp;
		NewNode->_next = _head;
		tmp->_next = NewNode;
		_head->_prev = NewNode;*/
		Insert(End(), x);
	}
	void PushFront(T x)   //头插
	{
		Insert(Begin(), x);
	}

	Iterator Insert(Iterator pos, const T& x) // 在pos前插入值t的元素,返回新添加元素的迭代器  
	{
		node_type NewNode = BuyNewNode(x);
		node_type cur = pos._node;
		NewNode->_next = cur;
		cur->_prev->_next = NewNode;
		NewNode->_prev = cur->_prev;
		cur->_prev = NewNode;
		return Iterator(NewNode);
	}

	void Insert(Iterator pos, size_t n, const T &t)//在pos前插入n个值为t的元素 
	{
		for (size_t i = 0; i < n; i++)
		{
			Insert(pos, t);
		}
	}
	void Insert(Iterator pos, Iterator b, Iterator e)//在pos前插入[b,e)范围的元素
	{
		for (Iterator tmp = b; tmp != e; tmp++)
		{
			Insert(pos, tmp._node->_data);
		}
	}
	node* BuyNewNode(T x=0)
	{
		node*tmp = new node(x);
		tmp->_next = tmp;
		tmp->_prev = tmp;
		return tmp;
	}


	
	/**********删除相关操作*******************/
	Iterator Erase(Iterator it)//删除it所指向的元素,返回所删除元素的下一个元素对应的迭代器  
	{
		assert(it != End());
		node_type cur = it._node;
		node_type del = cur;
		cur = cur->_next;
		cur->_prev = del->_prev;
		del->_prev->_next = cur;
		delete del;
		del = NULL;
		return Iterator(cur);
	}
	void Clear()//删除容器内的所有元素  
	{
		node_type cur = _head->_next;
		while (cur != _head)
		{
			node* del = cur;
			cur = cur->_next;
			delete del;
			del = NULL;
		}
	}
	void PopBack()//删除容器内最后一个有效的元素  
	{
		Erase(--End());
	}
	void PopFront()//删除容器内第一个有效的元素 
	{
		Erase(Begin());
	}
	/***************访问相关*******************/
	Iterator Begin()
	{
		return Iterator(_head->_next);
	}

	Iterator End()
	{
		return Iterator(_head);
	}

	T& Front()
	{
		return _head->_next->_data;
	}

	T& Back()
	{
		return _head->_prev->_data;
	}
	bool Empty() const
	{
		return _head->_next == _head;
	}

	size_t Size()
	{
		size_t count = 0;
		for (Iterator it = Begin(); it != End(); it++)
		{
			count++;
		}
		return count;
	}

	


private:
	node_type _head;
};
测试用代码:
#include"Link.h"

void TestLink()
{
	Link<int> l;
	l.PushBack(1);     //测试尾插,插入函数
	l.PushBack(2);
	Link<int> l2;
	l2.PushFront(1);    //测试头插
	l2.PushFront(2);
	Link<int>::Iterator it;
	for (it = l.Begin(); it != l.End(); it++)      //测试迭代器
	{
		cout << *it << " ";
	}
	cout << endl;
	for (it = l2.Begin(); it != l2.End(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	l2.Insert(l2.Begin(), 4, 1);     //测试重载的插入函数
	for (it = l2.Begin(); it != l2.End(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	l.Insert(l.Begin(), l2.Begin(), l2.End());  //测试重载的插入函数
	for (it = l.Begin(); it != l.End(); it++)     
	{
		cout << *it << " ";
	}
	cout << endl;
	l.Erase(--l.End());//测试删除函数
	for (it = l.Begin(); it != l.End(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	cout << l.Front() << endl;  //测试访头函数
	cout << l.Back() << endl;  //测试访尾函数
	cout << l.Size() << endl;  //测试容器大小函数
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值