迭代器iterator
源码:
```baidu 迭代器(iterator)有时又称光标(cursor)是程序设计的软件设计模式,可在容器对象(container,例如链表或数组)上遍访的接口,设计人员无需关心容器对象的内存分配的实现细节。 软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。 ```
效果:
迭代器(iterator)有时又称光标(cursor)是程序设计的软件设计模式,可在容器对象(container,例如链表或数组)上遍访的接口,设计人员无需关心容器对象的内存分配的实现细节。
软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
(这波抄袭复制百度掩饰得不错)
概念
所以说,迭代器没什么高大上的,就只是一种代码经验,代码习惯。
比如说有些人习惯用\(dp_0\)表示不定长数组\(dp\)当前的长度,这就是一种代码的经验。
有人喜欢把一个程序的所有初始化(清零,读入)都放在inline void init()里面,这也是一种经验。
还有很多很多。。。
总之,迭代器只是一种程序设计的思路,可有可无。
优势
那有什么用呢?主要就让你很好的遍历容器里面的所有元素。
比如说,我定义一个队列,不给用STL(我也不知道为什么),那么你就会
int que[N],hd,ed;
然后用循环队列的方式来实现这个队列
那么如果我要按顺序访问队列中的元素
你就会
for(int i=hd;i<ed+(N&((ed-hd)>>32));i=(i+1)%N)
{
cout<<que[i];
}
emmm...确实还可以
我定义(别问我为什么要定义)元素\(i\)的\(val\)值为\(val_i\)
我要输出队列中第\(i\)个元素的\(val\)
是不是就会有人写成
cout<<val[i];
实际上应该是
cout<<val[que[i]];
如果套更多的话。。。不堪设想。
但是迭代器就没有这个问题。
迭代器实质上是一个结构体,你如果往数组下标传入结构体会类型错误,那么你就知道你调用错了。
那么你就说,这种东西细心一点也没什么嘛。。。
那好吧我承认目前我认知到迭代器最后一个功能就是
装X
反正。。。迭代器就是一种编程习惯,你爱写不写。
书写迭代器可以让你的代码更加整洁,思路更加清晰,不会让你的代码跑得更快(甚至会慢一点。。。)(敲黑板划重点)
迭代器可以保证你遍历元素的时候按照一定的顺序(比如集合set按照默认升序,链表list按照从前到后),然后调用的时候不需要关注具体的内存地址。
比如你实现平衡树的时候,如果你不写迭代器,你要求一个数的前驱或者后继,你就要一个个结点去跳前驱后继。但是如果有迭代器,直接
Treap::iterator it;
++it;
是不是很快。。。
(完了我编不下去了)
实现
这个东西其实很简单。我们用队列来举个例子。
首先你要用指针表示链表
struct que
{
que *nxt;
int dat;
};
然后再用一个大的结构体包装一下(也没见你调用队列之类的东西用指针调用的吧?)
struct Que
{
struct que
{
que *nxt,*pre;
int dat;
que() { pre=nxt=0x0; dat=0; }
}*hd,*ed; // 队头和队尾的指针
Que() { ed=hd=new que; }
struct iterator
{
que* M_current; // 当前迭代器指向的元素的指针
iterator() { M_current=0x0; }
iterator(que* a) { M_current=a; }
iterator operator ++ () { M_current=M_current->nxt; return *this; } // 让迭代器指向前一个元素
iterator operator -- () { M_current=M_current->pre; return *this; } // 让迭代器指向后一个元素
bool operator != (iterator b) const { return M_current!=b.M_current; } // 两个迭代器不相等
bool operator == (iterator b) const { return M_current==b.M_current; } // 两个迭代器相等,当且仅当他们指向的地址相等
int operator * () const { return M_current->dat; } // 返回指向的元素
};
inline iterator begin() const { return iterator(hd); }
inline iterator end() const { return iterator(ed); }
};
如果不是队列而是其他的话,就自增和自减运算符的实现方法不一样而已。
所以看见了吧?迭代器其实很简单,就是用一堆的重定义运算符来吓唬人,实现很多高大上的操作。
而iterator就是容器内定义的结构体,所以我们定义一个迭代器需要
Que::iterator it;
如果我们要遍历整个队列
Que q;
push_many_numbers(q);
for(Que::iterator it=q.begin();it!=q.end();++it)
{
cout<<*it<<' '<<val[*it];
}
很多STL容器都是自带迭代器的,所以我们为什么还要自己写迭代器呢?
(回去问问为什么你要自己写结构体STL那么多好用的数据结构)
我们自己写迭代器,可以了解其中的思想,让我们的代码变得更加整洁,思路更加清晰。
而且STL也不是万能的,总有一天我们要自己写数据结构的时候,就难免会碰到这样的问题。
比如说这道题(说了这么多其实是为了纪念自己搞定了这道题)
[USACO21JAN] Dance Mooves G
他需要保存下来很多牛在一轮之中经过的位置。由于这个是不定的,所以用数组浪费空间让我很不爽我们用链表来储存
然后我就定义了迭代器。。。
(具体这道题怎么搞参考题解)
#include <cstdio>
#include <algorithm>
#include <cstring>
struct lce
{
unsigned first,second;
lce(unsigned a=0,unsigned b=0):first(a),second(b){}
lce operator=(lce b)
{
first=b.first; second=b.second; return *this;
}
};
template <typename T>
struct List
{
private:
struct list
{
list *nxt, *pre;
T dat;
list() { pre=nxt=0x0; dat=0; }
~list() { if(nxt) delete nxt; }
};
list *hd, *ed,*rst_end;
unsigned sze;
public:
List() { rst_end=ed=hd=new list; sze=0; }
~List()
{
delete hd;
}
struct iterator
{
list *M_current;
T operator *() const { return M_current->dat; }
iterator operator ++() { M_current=M_current->nxt; return *this; }
iterator operator --() { M_current=M_current->pre; return *this; }
bool operator != (iterator a) const { return M_current!=a.M_current; }
iterator(list *a=0x0) { M_current=a; }
};
inline iterator begin() const { return iterator(hd); }
inline iterator end() const { return iterator(ed); }
inline iterator rst() const { return iterator(rst_end?rst_end:ed); }
inline unsigned size() const { return sze; }
inline iterator append(T a,const bool k=0)
{
++sze;
ed->dat=a;
register const iterator It(ed);
ed->nxt=new list;
ed->nxt->pre=ed;
ed=ed->nxt;
if(k) rst_end=ed;
return It;
}
};
struct Graph
{
/// 此处略去1766字节
};
const int N=100001;
List <unsigned> pass_by[100001];
int n,k,a,b,ans[N];
unsigned *tmp;
long long int m;
inline void deal(unsigned,unsigned,unsigned,unsigned*);
inline void deal(unsigned,unsigned*);
int main()
{
scanf("%d%d%lld",&n,&k,&m);
Graph g(n);
register const unsigned times_opt=m/k;
register const unsigned rest_opt=m-k*times_opt;
tmp=new unsigned[n+1];
for(int i=1;i<=n;++i) pass_by[i].append(tmp[i]=i,rest_opt>=1);
for(int i=1;i<=k;++i)
{
scanf("%d%d",&a,&b);
pass_by[tmp[a]].append(b,rest_opt>=i); pass_by[tmp[b]].append(a,rest_opt>=i);
tmp[a]^=tmp[b]^=tmp[a]^=tmp[b];
}
for(int i=1;i<=n;++i) g.add(*pass_by[i].begin(),*(--pass_by[i].end()));
std::memset(tmp,0,sizeof(tmp[0])*(n+1));
List<lce> sze;
g.Tarjan(sze,tmp);
for(List<lce>::iterator it=sze.begin();it!=sze.end();++it)
{
register unsigned x=(*it).first, cnt=(*it).second;
std::memset(tmp,0,sizeof(tmp[0])*(n+1));
if(cnt<=times_opt) deal(x,tmp);
else deal(x,times_opt,rest_opt,tmp);
}
for(register int i=1;i<=n;++i) printf("%d\n",ans[i]);
return 0;
}
inline void deal(unsigned s,unsigned* buf)
{
register unsigned res=0,now=s;
List<unsigned>::iterator ed;
do
{
ed=pass_by[now].end();
for(List<unsigned>::iterator it=pass_by[now].begin();it!=ed;++it)
{
if(buf[*it]) continue;
++res; buf[*it]=true;
}
now=*--ed;
}while(now!=s);
now=s;
do
{
ans[now]=res;
now=*--pass_by[now].end();
}while(now!=s);
}
inline void deal(unsigned s,unsigned cnt,unsigned rest,unsigned* buf)
{
register unsigned res=0, now=s,xi=s;
List<unsigned>::iterator ed;
for(unsigned i=0;i<cnt;++i)
{
ed=pass_by[xi].end();
for(List<unsigned>::iterator it=pass_by[xi].begin();it!=ed;++it) if(!(buf[*it]++)) ++res;
xi=*--ed;
}
ed=pass_by[xi].rst();
for(List<unsigned>::iterator it=pass_by[xi].begin();it!=ed;++it) if(!(buf[*it]++)) ++res;
ans[s]=res;
while(*--pass_by[now].end()!=s)
{
ed=pass_by[now].end();
for(List<unsigned>::iterator it=pass_by[now].begin();it!=ed;++it) if(!(--buf[*it])) --res;
now=*--ed;
ed=pass_by[xi].end();
for(List<unsigned>::iterator it=pass_by[xi].rst();it!=ed;++it) if(!(buf[*it]++)) ++res;
xi=*--ed;
ed=pass_by[xi].rst();
for(List<unsigned>::iterator it=pass_by[xi].begin();it!=ed;++it) if(!(buf[*it]++)) ++res;
ans[now]=res;
}
}