关于stl中rope的实用讲解

Arcturus1350

2018-07-10 14:57:25

Personal

一般说的浅谈是永远不会短的 然后$qwq$本宝宝并不想讲实现原理 会用就行了呗 然后方便起见,本文规定数组$a$的第$1$位为$a[0]$ 并且本文的所有$debug$为了方便看到我们$rope$长度之后的东西,会多输出若干位(看$debug$程序就懂了) 所以一些输出可能跟我的不一样(比较明显,显然数组越界) 进入正题 首先需要的头文件: ```cpp #include<ext/rope> ``` 需要的命名空间 ```cpp using namespace __gnu_cxx; ``` 之后声明一个$rope$ ```rope</*这里面是填变量类型*/> ro;``` 如果命名空间是$std$的话可以这么写: ```cpp __gnu_cxx::rope</*变量类型*/> ro; ``` --- 这里以变量类型为$int$的$rope$来举例 前置技能是知道怎么访问: 获取$ro$的第$i$位是$ro[i-1]$ 因为$rope$是从$0$开始的 ```cpp /*前置的头文件和函数声明*/ #include<iostream> #include<cstdio> #include<algorithm> #include<ext/rope> using namespace std; __gnu_cxx::rope<int>ro; int n,m,p; void debug(int len) { for(int i=0;i<=len;i++) printf("%d %d \n",i,ro[i]);//输出0~len这len+1位存的是啥 puts(""); return ; } ``` 然后是添加删除,       (1). $push \_ back$和$push \_ front$    $push \_ back(n);$    表示在当前$rope$序列最后添加一个$n$;    $push \_ front(n)$就是在最前面啦。   然后测试一下: ```cpp int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&m),ro.push_back(m); debug(n); return 0; } /* testdata.in: 5 1 2 3 4 5 testdata.out: 0 1 1 2 2 3 3 4 4 5 5 2576(或者别的) */ ``` 然后又知道了如果我们访问的第$i$位要是没赋值的话会输出随机的一个数(刚刚就是$ro[5]$我们并没有赋值)。 ```cpp int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&m),ro.push_front(m); debug(n); return 0; } /* testdata.out 0 5 1 4 2 3 3 2 4 1 5 0 (或者其它) */ ```   然后自己动手试试就更能理解了。       (2).一个极其好用的插入函数:$insert(pos,x)$表示在第$pos$位插入一个数$n$(就是第$pos$位变成$n$,之前的第$pos$和$pos$后面的依次向右移) ```cpp int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&m),ro.push_back(m); debug(n); int ll; scanf("%d",&ll); for(int i=1;i<=ll;i++) scanf("%d%d",&m,&p),ro.insert(m,p),debug(n); return 0; } /* testdata.in: 5 1 2 3 4 5 1 1 10 testdataout: 0 1 1 2 2 3 3 4 4 5 5 312 (或者其他) 0 1 1 10 2 2 3 3 4 4 5 5 */ ```    所以$insert(0,n)$就等同于$push \_ front(n)$    然后这个$insert()$还有个好处是这玩意支持整个数组同时插入    $insert(pos,a)$(a为一个数组名)表示将a数组整个插入(从$a[0]$开始一直插入,直到某一位为$0$,不插入值为$0$的这一位) ```cpp int ll;int a[5]={0,0,0,0,0}; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&m),ro.push_back(m); scanf("%d",&ll); for(int i=0;i<ll;i++) scanf("%d",&a[i]); int pos;scanf("%d",&pos); ro.insert(pos,a); n+=ll; debug(n); return 0; } ``` ```cpp /* testdata1.in: 5 1 2 3 4 5 3 11 12 13 1 testdata1.out: 0 1 1 11 2 12 3 13 4 2 5 3 6 4 7 5 8 0 */ /* testdata2.in: 5 1 2 3 4 5 3 0 11 13 1 testdata2.out: 0 1 1 2 2 3 3 4 4 5 5 0 6 0 7 0 8 0 */ /* testdata3.in: 5 1 2 3 4 5 3 11 0 13 1 testdata3.out: 0 1 1 11 2 2 3 3 4 4 5 5 6 0 7 0 8 0 */ ```    通过第一个数据我们见识到了$insert$的整段插入,第二,三个数据说明了$insert$会插入到下一位是$0$的这一位。    当然,万一我们的某些题里一定要有$0$怎么办?我们不想全部插入怎么办?    $insert(pos,a+x,a+y)$表示将$a$数组的$a[x]$开始到$a[y-1]$位总共$y-x$位一起在$pos$插入到$rope$里。 ```cpp int ll;int a[5]={0,0,0,0,0}; int x,y; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&m),ro.push_back(m); scanf("%d",&ll); for(int i=0;i<ll;i++) scanf("%d",&a[i]); scanf("%d%d",&x,&y); int pos;scanf("%d",&pos); ro.insert(pos,a+x,a+y); n+=ll; debug(n); return 0; } ``` ```cpp /* testdata.in: 5 1 2 3 4 5 4 11 0 13 14 1 3 1 testdata.out: 0 1 1 0 2 13 3 2 4 3 5 4 6 5 7 0 8 0 9 0 */ ```   下面开始讲删除操作    删除的函数很少啊$……$    $erase(pos)$一个很玄学的参数,表示从$ro[pos]$开始为第$1$位 ,往后删掉共$pos+1$位 ```cpp int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&m),ro.push_back(m); debug(n); int pos; scanf("%d",&pos); ro.erase(pos); debug(n); return 0; } ``` ```cpp /* testdata1.in: 6 1 2 3 4 5 6 0 testdata1.out: 0 1 1 2 2 3 3 4 4 5 5 6 6 40 (or any) 0 2 1 3 2 4 3 5 4 6 5 1028672837 (or any) 6 1432107587 (or any) */ /* testdata2.in: 6 1 2 3 4 5 6 1 testdata2.out: 0 1 1 2 2 3 3 4 4 5 5 6 6 40 (or any) 0 1 1 4 2 5 3 6 4 0 (or any) 5 0 (or any) 6 0 (or any) */ /* testdata3.in: 6 1 2 3 4 5 6 4 testdata3.out: 0 1 1 2 2 3 3 4 4 5 5 6 6 40 (or any) 0 1 1 2 2 3 3 4 4 1409315703 (or any) 5 1028672837 (or any) 6 1432107587 (or any) */ ``` 其中$(or any)$表示是或者其他值(应该是$or \ \ else$ 的吧……本宝宝的英语好菜啊)    $erase(pos,len)$表示从$ro[pos]$开始为第$1$位,往后删掉共$len$位。 ```cpp int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&m),ro.push_back(m); debug(n); int pos;int ll; scanf("%d%d",&pos,&ll); ro.erase(pos,ll); debug(n); return 0; } /* testdata.in: 6 1 2 3 4 5 6 1 4 testdata.out: 0 1 1 2 2 3 3 4 4 5 5 6 6 40 (or else) 0 1 1 6 2 6816088 (or else) 3 0 (or else) 4 0 (or else) 5 0 (or else) 6 0 (or else) */ ``` --- 嘤嘤嘤!插入终于写完了,累死宝宝了$qwq$,歇一会,回来再更 $2018.7.9 \ \ 9:54$ 本宝宝回来了$2018.7.9 \ \ 10:38$ --- 然后就是修改替换转移了   $copy(pos,len,&x)$其中$&x$为一个指针或者数组名(不也是一个指针么?qwq)表示将$ro[pos]$为第一位到$ro[pos+len-1]$这总共$len$位的东西赋值到$a$上(数组的话从$a[0]$开始)   $ps:\text{本小可爱这辈子都学不会指针的}$ ```cpp int a[5]={0,0,0,0,0}; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&m),ro.push_back(m); debug(n); int pos;int ll; scanf("%d%d",&pos,&ll); ro.copy(pos,ll,a); // debug(n); 看心情,反正能不开也没事 for(int i=0;i<5;i++) printf(" %d ",a[i]); return 0; } ``` ```cpp /* testdata.in: 6 1 2 3 4 5 6 1 3 testdata.out: 0 1 1 2 2 3 3 4 4 5 5 6 6 40 (or else) 2 3 4 0 0 */ ```  我们发现,我们在$testdata$里目的是将$1$到$3$替换成$11$然后输出中告诉我们了,我们把原先$1$到$3$的值也顺便覆盖掉了。   其实相当于先$erase(pos,len)$然后在$insert(pos,newval)$   $ replace(pos,st,\&x,en) $ 在$pos$插入$x$的前$en$位,其中重叠$st$位.(详见数据) ```cpp int a[5]={0,0,0,0,0}; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&m),ro.push_back(m); // debug(n); int pos;int len; scanf("%d%d",&pos,&len); for(int i=0;i<len;i++) scanf("%d",&a[i]); int st,en; scanf("%d%d",&st,&en); ro.replace(pos,st,a,en); debug(n+4);//多输出点看看 return 0; } ``` #### UPD:从这里起省略(or else)自己想吧 ```cpp /* testdata1.in: 6 1 2 3 4 5 6 2 4 11 12 13 14 0 1 testdata1.out: 0 1 1 2 2 11 3 3 4 4 5 5 6 6 7 0 8 0 9 0 10 1658256847 */ /* testdata2.in: 6 1 2 3 4 5 6 2 4 11 12 13 14 0 2 testdata2.out: 0 1 1 2 2 11 3 12 4 3 5 4 6 5 7 6 8 0 9 0 10 794409564 */ /* testdata3.in: 6 1 2 3 4 5 6 2 4 11 12 13 14 1 4 testdata3.out: 0 1 1 2 2 11 3 12 4 13 5 14 6 4 7 5 8 6 9 0 10 0 */ /* testdata4.in: 6 1 2 3 4 5 6 2 4 11 12 13 14 5 4 testdata4.out: 0 1 1 2 2 11 3 12 4 13 5 14 6 0 7 0 8 0 9 0 10 926115120 */ ```   我们发现,当$st=0$时,相当于直接从$a$里插入长度为$en$,$st!=0$时是覆盖$st$位插入,如$testdata3$我们本应该是在$ro[6]$的$3$被覆盖掉了。   而又如$testdata4$当覆盖的长度大于我们要加的长度的时候,原先的就会全被清除。     $substr(pos,x)$提取从$pos$开始$x$个。 --- 另外就是$rope$支持$size()$调取大小,支持$swap()$ --- 以上这些如果是$char$类型的话还会有彩蛋呢$……$但是一般这几个操作就够了(其实是本宝宝就知道这些了) 然后就…… 本文完结撒花了 吧…… 希望能对大家有所帮助。 [毫不要脸的贴上自己的blog](https://www.cnblogs.com/cn-suqingnian/p/9282360.html)