STL learning (9): iterator

That iterator is a pointer, may be any desired type, the biggest advantage is that the container can be separated and algorithms. Conventional thinking is that each class has its own container display, search, sorting function. Careful analysis can be drawn: a different container perform the same function code in general the idea is the same, then they can not put out the abstract, a plurality of containers corresponding to only one display, a query, a sort function? This is the inevitable result of the development of generic thinking.

STL (Standard Template Library), is built-in support of C ++ library. It utilizes the mechanisms underlying C ++ class templates and function templates,

It consists of three parts: container, algorithms, and iterators.

                                                         

An array of containers, container list compiled jointly display function.

MyArray array class initial code shown below.

//文件名:e3_1.cpp(本示例中所有头文件及源文件内容都在该文件中)
#include <stdio.h>
template<class T> 
class MyArray
{
private:
	int m_nTotalSize; 	//数组总长度
	int m_nValidSize;	//数组有效长度
	T *m_pData;		//数据
public:
	MyArray(int nSize = 3)//数组默认总长度是3
	{
		m_pData = new T[nSize];
		m_nTotalSize = nSize;
		m_nValidSize = 0;
	}
	void Add(T value)		//向m_pData添加数据
	{
		//同例1.1
	}
	int GetSize()		//返回数组有效长度
	{
		return m_nValidSize;
	}
	T Get(int pos)		//返回某一位置元素
	{
		return m_pData[pos];
	}
	virtual ~MyArray()
	{
		if(m_pData != NULL)
		{
			delete []m_pData;
			m_pData = NULL;
		}
	}
};

Objectlist MyLink initial code shown below.

template <class T>
struct Unit		//链表单元
{
	T value;
	Unit *next;
};
template <class T>
class MyLink
{
	Unit<T> *head;	//链表头
	Unit<T> *tail;	//链表尾
	Unit<T> *prev;
public:
	MyLink()
	{
		head = tail = prev = NULL;
	}
	void Add(T &value)//向链表中添加元素
	{
		Unit<T> * u = new Unit<T>();
		u->value = value;
		u->next = NULL;
		if(head == NULL)
		{
			head = u;
			prev = u;			
		}
		else
		{
			prev->next = u;
			prev = u;
		}
		tail = u->next;
	}
	virtual ~MyLink()
	{
		if(head != NULL)
		{
			Unit<T> *prev = head;
			Unit<T> *next = NULL;
			while(prev != tail)
			{
				next = prev->next;
				delete prev;
				prev = next;
			}
		}
	}
};

So, how to MyArray, MyLink is based on the completion of a common display function? In fact, very simple, starting with needs, consider the reverse, the first to write a generic number is displayed, as shown below.

template<class Init>
void display(Init start, Init end)
{
	cout << endl;
	for(Init mid=start; start != end; mid++)
	{
		cout << *mid << "\t" ;
	}
	cout << end;
}

Init template type parameter is a pointer, start is the starting pointer, end to end pointer, and * pointer ++ support operations. display function is not directly related to a specific container, indirect association is necessary. For MyArray, Init corresponds to the operation of the T *, for the MyLink, the equivalent of the operation of the Unit *. Therefore leads iterator class, it is still a template class, for this example, the template T * or parameter Unit *.

MyArray the corresponding iterator class ArrayIterator shown below.

template<class Init>
class ArrayIterator
{
	Init *init;
public:
	ArrayIterator(Init *init)
	{
		this->init = init;
	}
	bool operator!=(ArrayIterator& it)
    {
	    return this->init != it.init;
    }
    void operator++(int)
    {
	init ++;
    }
    Init operator*()
    {
	   return *init;
    }
  
};

In addition, the need to add two functions MyArray class Begin, End, to obtain the iteration start and end pointers.

T *Begin()	//起始迭代指针
{
	return m_pData;
}
T *End()		//结束迭代指针
{
   return m_pData + m_nValidSize;
}

As shown in the following test function.

void main()
{
	MyArray<int> ary;
	for(int i=0; i<5; i++)
	{
		ary.Add(i+1);
	}
	ArrayIterator<int> start(ary.Begin());
	ArrayIterator<int> end(ary.End());
	cout << "数组元素为:" ;
	display(start, end);
}

Similarly complete list iterator class LinkIterator, as shown below.

template<class Init>
class LinkIterator
{
    Init *init;
public:
    LinkIterator(Init *init)
    {
        this->init = init;
    }
    bool operator != (LinkIterator& it)
   {
	   return this->init != it.init;
   }
   void operator ++(int)
   {
	   init = init->next;
   }
   Init operator*()
   {
	   return *init;
   }
};

It can be seen operator! =, Operator * overloaded content ArrayIterator content is the same, only different contents of operator ++, for purposes of the list in terms of the memory array is not continuous, the pointer is turned, and therefore must not written init = init ++, can only be init = init-> next.

In addition, the need to add two functions MyArray class Begin, End, to obtain the iteration start and end pointers.

T *Begin()	//起始迭代指针
{
    	return m_pData;
}
T *End()		//结束迭代指针
{
          return m_pData + m_nValidSize;
} 

Objectlist test function shown below.

void main()
{
    int m = 0;
    MyLink<int> ml;
    for(int i=0; i<5; i++)
    {
        m = i+1;
        ml.Add(m);
    }
    LinkIterator<Unit<int> > start(ml.Begin());
    LinkIterator<Unit<int> > end(ml.End());
    display(start, end);
}

Fusion iterator class

Custom arrays iterator Methodology list iterators, iterator class is located outside the vessel. But a closer analysis can be found: Array iterators can only be applied to an array of container, the container can not be used in list; the list iterator can only be applied to list the container, the container can not be applied to the array. That particular container should have a specific iterators. Thus, the inner iterator class as more in line with the characteristics of the class container application to MyLink example, fusion LinkIterator code is as follows.

class LinkIterator;
template <class T>
class MyLink
{
public:
	struct Unit		//链表单元
	{
		T value;
		Unit *next;
	};
	class LinkIterator
	{
		Unit *init;
	public:
		LinkIterator(Unit *init)
		{
			this->init = init;
		}
		bool operator != (LinkIterator& it)
		{
			return this->init != it.init;
		}
		void operator ++(int)
		{
			init = init->next;
			cout<<"asdf";
		}
		Unit operator*()
		{
			return *init;
		}
		friend ostream & operator << (ostream & out, LinkIterator & A);
	};
	Unit *head;	//链表头
	Unit *tail;	//链表尾
	Unit *prev;
public:
	MyLink()
	{
		head = tail = prev = NULL;
	}
	void Add(T &value)//向链表中添加元素
	{
		Unit * u = new Unit();
		u->value = value;
		u->next = NULL;
		if(head == NULL)
		{
			head = u;
			prev = u;
		}
		else
		{
			prev->next = u;
			prev = u;
		}
		tail = u->next;
	}
	Unit *Begin()
	{
		return head;
	}
	Unit *End()
	{
		return tail;
	}
	virtual ~MyLink()
	{
		if(head != NULL)
		{
			Unit *prev = head;
			Unit *next = NULL;
			while(prev != tail)
				{
				next = prev->next;
				delete prev;
				prev = next;
			}
		}
	}
};

ostream & operator << (ostream & out, MyLink<int>::LinkIterator & A)
{
    //输出s的代码
    out << A.init->value;
    return out;
}
template<class Init>
void display(Init start, Init mend)
{
	cout<<endl;
	for(Init mid=start; start != mend; mid++)
	{
		cout<< mid << "\t" ;
	}
	cout<<endl;
}
int main()
{
    int m = 0;
    MyLink<int> ml;
    for(int i=0; i<5; i++)
    {
	    m = i+1;
	    ml.Add(m);
    }
    MyLink<int>::LinkIterator start = ml.Begin();
    MyLink<int>::LinkIterator mend = ml.End();
    display(start, mend);
    return 0;
}

Further understanding of iterators

Containers, iterators, the algorithm follows a schematic diagram of the relationship.

Each container should have a corresponding iterator, a specific algorithm shared by the iterator container, a specific algorithm is not attached to a particular container. Iterator functions as an intermediary through which the algorithm associated with the container. In other words a more appropriate words: iterator thinking is the inevitable result of the development of the preparation of common generic algorithms, algorithms in order to access container elements by iterators.

You can draw basic steps STL Standard Template Library programming:

  • Container element is formed;
  • Remove the iteration pointer needs;
  • Call general algorithm.

In fact, there are many "iterator" phenomenon in life, in the final analysis is the need for "common" reasons. Such as online resources is a universal demand, every family the equivalent of a container node, then communications equipment such as telephone lines, and is equivalent to an iterator. Millions of households through the Internet can query the information they need. Another example is the use of tap water is life in general demand, every family is still the equivalent of a node, then the water pipelines is equivalent iterator.

Since the common needs of life contributed to the development of various undertakings of communication, so for general-purpose software algorithm, it will be able to promote the continuous progress of the iterator. Therefore, I hope the students to observe the phenomena of life, since many design software all around our lives. If every idea you can design software can find examples of life, the design software you will be able to feel very happy, not so boring.

STL iterators is divided into five types.    

  1. Input iterator
  2. Output iterator
  3. Forward iterators
  4. Bidirectional iterators
  5. Random iterators

Input iterator

Sequential read only once. Complete function are: the default configuration and can be constructed, can be copied or assignment can be compared for equality, can move forward stepwise, the value can be read. FIG main input iterator Overload operator follows.

STL提供的主要输入迭代器是istream_iterator,支持表3.1中的所有操作,值得注意的是它的构造函数,有两种形式:

  1. istream_iterator() 默认的构造器,创建了一个流结束的迭代器。
  2. istream_iterator(istream &) 参数是输入流。含义是从输入流中读数据,当遇到流结束符时停止。
int main(int argc, char* argv[])
{
	cout <<"input data : "<<endl;
	istream_iterator<int> a(cin) ;  //建立键盘输入流,用istream_iterator枚举整形数据
	istream_iterator<int> b;	 //建立输入流结束迭代器
	while(1)
	{
	    cout << *a << endl;	//输出整形数据调用operator*()
	    a ++ ;		//迭代器指针指向下一个元素—>调用operator++(int)
	    if(a == b)                  //如果当前迭代器等于结束迭代器,则operator==
	    {                              //退出while循环
		break;
	    }
    }
    return 0;
}

//输出为:
input data :
1 2 3,
1
2
3

到我们只要输入的不是整数就会结束输入。

输出迭代器

只写一次,完成的功能有:能进行构造或缺省构造,能被复制或赋值,能进行相等性比较,能进行逐步前向移动,能进行写入值(*p=x,但不能读出)。输出迭代器重载主要操作符 如下所示。

STL提供的主要输出迭代器是ostream_iterator,支持表2.2中的所有操作,值得注意的是它的构造函数,有两种形式:

  1. ostream_iterator(ostream& out)     创建了流输出跌代器, 用来迭代out输出流。
  2. ostream_iterator(ostream& out, const char *delim)     创建了流输出迭代器, 用来向out输出流输出数据,输出的数据之间用delim字符串分割,也即是每向out输出流输出一个数据后,再向out输出流输出一个分隔符delim。
int main(int argc, char* argv[])
{
    cout << "输出迭代器演示结果为: " ;
    ostream_iterator<int> myout(cout, "\t"); //创建标准输出迭代器
    *myout = 1;
    myout++;
    *myout = 2;
    myout++;
    *myout = 3;
    return 0;
}

执行结果为:

输出迭代器演示结果为:1    2    3

前向迭代器

使用 输入迭代器 和输出迭代器可以基本满足算法和容器的要求。但还是有一些算法需要同时具备两者的功能。     STL本身并没有专为前向迭代器预定义的迭代器 。

双向迭代器:

具有前向迭代器的全部功能,另外它还可以利用自减操作符operator—向后一次移动一个位置。例如双向链表容器中需要的就是双向迭代器。

随机访问迭代器:

具有双向迭代器的所有功能,再加上一个指针所有的功能。包括使用操作符operator[]进行索引,加某个整数值到一个指针就可以向前或向后移动若干个位置,或者使用比较运算符在迭代器之间进行比较。

综观五种 iterator,我们发现从前到后需求越来越多5,也就是所谓的细化。这样在一切情况下都可以使用需求最细的随机迭代器,确实可以,但不好,因为过多的需求自然会降低它的效率,实际编程时应该选择正好合适的iterators 以期得到最高的效率。

 

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/QQ2558030393/article/details/93383118