基于C++11的Forward-List容器分析

Forward-List的基本内容

  1. 此容器始于C++11,其内部实现为一个single linked list(单链表)管理元素。

  1. 想要使用此容器,必须首先包含<forward_list>头文件

  1. 在这个头文件中forwar list被定义为命名空间std内的一个class template:

namespace std{
  template<typename T,typename Allocator = allocator<T>>
     class forward_list;
  }

T可以被指定为任意元素类型,可有可无的第二个template参数定义处内存模型。默认的内存模型是allocator,由C++标准库提供

Forward-List的能力

以下是C++standard对它的描述:"我们希望forward_list和你自己手写的C-style singly linked list相比较之下没有任何时间或空间上的开销。任何性质如果与这个目标相抵触,我们就放弃该项性质"。

相较于list,forward list有以下约束:

  1. Forward list只提供向前迭代器,而不是双向迭代器。因此它也不支持反向迭代器,这意味着rbegin(),rend(),crbegin(),crend()等成员函数也不提供。

  1. Forward list不提供成员函数size()。这是遵循C++standard目标带来的必然结果。

  1. Forward list没有指向最末元素的锚点(anchor)。因而不提供处理最末元素的成员函数back(),push_back()和pop_back()。

  1. 对于所有"令元素被安插或删除于forward list的某特定位置上"的成员函数,forward list都提供特殊版本(这是基于单链表特性所导致的)。基于这个差异,这些成员函数名称都带有_after的后缀。例如insert_after()取代inert()。

  1. 基于第四点的原因,forward list提供before_begin()和cbefore_begin(),他们可以用来让"名称带有_after后缀"的算法交换第一元素。

除了这些差异,forward list就像一个list

  1. Forward list不提供随机访问。

  1. 在任何位置上安插和移除元素速度都很快。

  1. 安插和删除元素不会造成"指向其他元素"的pointer,reference和iterator失效。

  1. Forward list对待异常的态度是,几乎每一个操作要么成功,要么就不起作用。

  1. Forward list提供许多特殊成员函数用于搬移和移除元素。这些成员函数是一般算法的快速版本。

Forward-list 的操作

创建,复制,销毁(Create,Copy,and Destory)

forward list<T>c //Default构造函数,产生于一个空的forward list容器,没有任何元素
forward list<T>c(c2) //Copy构造函数,将c建立为c2的一份拷贝(所有元素都被拷贝) 
forward list<T>c=c2 //Copy构造函数,将c建立为c2的一份拷贝(所有元素都被拷贝) 
forward list<T>c(rv)//Move构造函数,取rv的内容建立一个新的forward list
forward list<T>c=rv//Move构造函数,取rv的内容建立一个新的forward list
forward list<T>c(n)//生成一个大小为n的forward list,每个元素的值都是elem
forward list<T>c(n,elem)//生成一个大小为n的forward list,每个元素的值都是elem
forward list<T>c(beg,end)//生成一个forward list,以区间[begin,end)作为元素初值
forward list<T>c(initlist)//生成一个forward list,以初始值列表的元素为初值
forward list<T>c =initlist//生成一个forward list,以初始值列表的元素为初值
c.~forward list()//销毁所有元素,释放内存

非更易型操作(Nonmodifying Operation)

与list的区别是,forward list不提供size()。原因是它不存储元素的目前数量,也无法在常量时间内将它算出来。如果你必须计算元素个数,可使用distance()辅助函数。

#include<forward list>
#include<iterator>
std::forward list<int>l;
std::cout<<"l.size()"<<std::distance(l.begin(),l.end())   
         <<std::endl;

请注意distance()具有线性复杂度

c.empty() //返回是否容器为空(相当于size()==0但也许较快)
c.max_size() //返回元素个数之最大可能量
c1==c2   //返回c1是否等于c2
c1!=c2   //返回c1是否不等于c2
c1>c2    //返回c1是否大于c2
c1<c2    //返回c1是否小于c2
c1>=c2   //返回c1是否大等于c2
c1<=c2   //返回c1是否小等于c2

赋值(Assignment)

c=c2              //将c2的全部元素赋值给c
c=rv              //将rv的所有元素都已move assign的方式给予c
c=initlist        //将初始值列表的所有元素赋值给c
c.assign(n,elem)  //赋值给list,n个元素的值都是elem值
c.assign(beg,end) //将区间[begin,end)的元素赋值给list
c.assign(initlist)//将初始值列表的元素赋值给list
c1.swap(c2)       //置换c1和c2的值
swap(c1,c2)       //置换c1和c2的值

元素访问(Element Access)

欲访问forward list的所有元素,你必须使用range-based for循环,特定的操作函数或迭代器。和list相比,你唯一能够访问的元素是第一元素。

c.front()//返回第一元素(并不检查是否存在第一元素)

迭代器相关函数(Iterator Function)

由于是向前迭代器,你无法调用reverse迭代器,无法调用需要双向或者随机迭代器的算法,如(sort)。此外还提供了before_begin()和cbefore_begin(),为了能够修改第一元素。

c.begin()      //返回一个指向首处 forward iterator
c.cbegin()     //返回一个const forward iterator
c.end()        //返回一个指向末尾下一个位置的 forward iterator
c.cend()       //返回一个指向末尾下一个位置的const forward iterator
c.before_begin()//返回一个指向首处前一个位置的 forward iterator
c.cbefore_begin()//返回一个指向首处前一个位置的const forward iterator

注意:before_begin()和cbefore_begin()并不代表forward list的任意一个有效位置;提领这些位置会导致不明确的行为。

元素的安插和移除元素素(Inserting and Removing)

c.push_front()//附加elem的拷贝于容器的首处
c.pop_front()//移除第一个元素,但是不返回它
c.insert_after(pos,elem)//在pos的后方插入elem的一个拷贝,并且返回新元素的位置
c.insert_after(pos,n,elem)//在pos的后方插入elem的n个拷贝,并且返回第一个新元素的位置
c.insert_after(pos,beg,end)//在pos的后方插入[begin,end)区间的拷贝,并且返回第一个新元素的位置
c.insert_after(pos,initlist)//在pos的后方插入初始化列表的拷贝,并且返回第一个新元素的位置
c.emplace_after(pos,args...)//在pos的后方插入以args作为初值的元素,并且返回新元素的位置
c.emplace_front(args...)//首处插入以args作为初值的元素,并且返回新元素的位置
c.erase_after(pos)//移除pos位置之后的元素,不返回任何元素
c.erase_after(beg,end)//移除[begin,end)区间内的元素,不返回任何元素
c.remove(val)//移除所有值为val的元素
c.remove_if(op)//移除所有造成op(elem)结果为true的元素
c.resize(num)//将元素数量改为num,如果size()变大,则以元素default构造函数完成初始化
c.resize(num,elem)//将元素数量改为num,如果size()变大,则以elem的拷贝作为新元素的值
c.clear()//移除所有元素,将容器清空

当使用这些成员函数,并结合before_begin(),一个典型的forward list元素访问动作如下:

std::forward list<int>fwlist{1,2,3};
fwlist.insert(fwlist.before_begin(),{77,88,99});

注意:调用_after成员函数并传入end或cend()会导致不明确的行为,因为如果要在forward list的尾端附加一个新元素,你不许传入中断元素的位置。

fwlist.insert_after(fwlist.end(),9999);
//RUNTIME ERROR:appending element after end is underfined behavior

下方有一个例子:

#include<forward_list>
using namespace std;
int main(){
    forward_list<int>list{1,2,3,4,5,97,98,99};
    auto posBefore=list.before_begin();
    for(auto pos=list.begin();pos!=list.end();++pos,++posBefore){
       if(*pos%2==0)break;
    }
    list.insert_after(posBefore,42);
    for(auto it:list)cout<<it<<" ";
}

程序输出结果为:

1 42 2 3 4 5 97 98 99

Forward-list提供的特殊更易型操作

c.unique()             //如果存在若干相邻而数值相同的元素,就移除重复元素,只留一个
c.unique()             //如果存在若干相邻都使op()的结果为true的元素,就移除重复元素,只留一个
c.splice_after(pos,c2)       //将c2的所有元素转移到c之内,迭代器pos之后
c.splice_after(pos,c2,c2pos) //将c2的c2pos所指元素转移到c内迭代器pos所指位置之后(c和c2可相同)
c.splice_after(pos,c2,c2beg,c2end) //将c2的c2beg和c2end区间(不含头尾)内元素转移到c内迭代器pos之后位置(c和c2可相同)
c.sort()          //以元素的operator <为准则对所有元素排序
c.sort(op)        //以元素的op()为准则对所有元素排序
c.merge(c2)       //假设c和c2容器都包含op()准则下的已排序元素,将c2的全部元素转移到c,并保证合并后的list仍为以排序
c.merge(c2,op)    //假设c和c2容器都包含已排序元素,将c2的全部元素转移到c,并保证合并后的list在op()准则下仍为已排序
c.reverse()       //将所有元素反序

异常处理(Exception Handing)

forward list对于异常处理的态度和保证,与list完全相同。

Forward List运用实例

#include<forward_list>
#include<iostream>
#include<algorithm>
#include<iteraotor>
#include<string>
using namespace std;

void printLists(const string&s,const forward_list<int>&l1,const forward_list<int>&l2){
        cout<<s<<endl;
        cout<<" list1: ";
        copy(l1.cbegin(),l1.cend(),ostream_iterator<int>(cout," ");
        cout<<endl<<" list2: ";
        copy(l2.cbegin(),l2.cend(),ostream_iterator<int>(cout," ");
        cout<<endl;
}

int main(){
    forward_list<int>list1{1,2,3,4};
    forward_list<int>list2{77,88,99};
    printLists("initial:",list1,list2);

    list2.insert_after(list2.before_begin(),99);
    list2.push_front(10);
    list2.insert_after(list2.before_begin(),{10,11,12,13});
    printLists("6 new elems:",list1,list2);

    list1.insert_after(list1.before_begin(),list2.begin(),list2.end());
    printLists("list2 into list1:",list1,list2);

    list2.erase_after(list1.begin());
    list2.erase_after(find(list2.begin(),list2.end()),99,list2.end());
    printLists("delete 2nd and after 99:",list1,list2);

    list1.sort();
    list2=list1;
    list2.unique();
    printLists("sorted and unique:",list1,list2);
    
    list1.merge(list2);
    printLists("merged:",list1,list2);
}

执行结果:

initial:
 list1: 1 2 3 4
 list2: 77 88 99
6 new elems:
 list1: 1 2 3 4
 list2: 10 11 12 13 10 99 77 88 99
list2 into list1:
 list1: 10 11 12 13 10 99 77 88 99 1 2 3 4
 list2: 10 11 12 13 10 99 77 88 99
delete 2nd and after 99:
 list1: 10 12 13 10 99 77 88 99 1 2 3 4
 list2: 10 11 12 13 10 99
sorted and unique:
 list1: 1 2 3 4 10 10 12 13 77 88 99 99
 list2: 1 2 3 4 10 12 13 77 88 99
merged:
 list1: 1 1 2 2 3 3 4 4 10 10 10 12 12 13 13 77 77 88 88 99 99 99
 list2:
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Reol520

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值