zoukankan      html  css  js  c++  java
  • C++ Primer 学习笔记_29_STL实践与分析(3) --操作步骤集装箱(下一个)

    STL实践与分析

    --顺序容器的操作()



    六、訪问元素

        假设容器非空,那么容器类型的frontback成员将返回容器的第一个和最后一个元素的引用。

    【与beginend的对照:】

        1beginend返回容器类型的迭代器,而不是引用;

        2end返回容器最后一个元素的下一个位置的迭代器,而back返回容器的最后一个元素的引用!

    	/*
    	*必须保证该list容器非空!
    	*假设容器为空,则if语句内的全部操作都是没有定义的!

    */ if (!iList.empty()) { list<int>::reference bVal1 = *iList.begin(); list<int>::reference bVal2 = iList.front(); list<int>::reference eVal1 = *--iList.end(); list<int>::reference eVal2 = iList.back(); cout << "Begin:" << endl; cout << bVal1 << endl; cout << bVal2 << endl; cout << endl << "End:" << endl; cout << eVal1 << endl; cout << eVal2 << endl; }



    訪问顺序容器内元素的操作

    c.back()

    返回容器c最后一个元素的引用。假设c为空,则该操作没有定义

    c.front()

    返回容器c第一个元素的引用。假设c为空,则该操作没有定义

    c[n]

    返回下标n的元素的引用,假设n<0n>=c.size(),则该操作没有定义

    仅仅适用于vectordeque容器

    c.at(n)

    返回下标为n的元素的引用,假设下标越界。则该操作没有定义

    仅仅适用于vectordeque容器

        使用下标运算的一个可选方案是使用at成员函数,尽管这个函数的行为和下标运算相似。可是假设程序给出的下标无效,at函数会抛出out_of_range异常。

        vector<string> strVec;
    
        cout << strVec[0] << endl;		//run-time error
        cout << strVec.at(0) << endl;	//throw out_of_range
    

    //P280 习题9.24
    int main()
    {
        vector<string> strVec;
        strVec.push_back("o(∩∩)o...");
        if (!strVec.empty())
        {
            cout << strVec.front() << endl;
            cout << *strVec.begin() << endl;
            string tmp = strVec.at(0);
            cout << tmp << endl;
            tmp = strVec[0];
            cout << tmp << endl;
        }
    }
    

    七、删除元素

    删除顺序容器内元素的操作

    c.erase(p)

    删除迭代器p所指向的元素

    返回一个迭代器,它指向被删除元素后面的元素

    假设p指向容器内的最后一个元素,则返回的迭代器指向容器的超出末端的下一位置。假设p本身就是指向超出末端的下一位置的迭代器,则该函数没有定义

    c.erase(b,e)

    删除迭代器be所标记的范围内全部的元素

    返回一个迭代器,它指向被删除元素段后面的元素假设e本身就是指向超出末端的下一位置的迭代器,则返回的迭代器也指向容器的超出末端的下一位置

    c.clear()

    删除容器c内的全部元素。返回void

    c.pop_back()

    删除容器c的最后一个元素。返回void

    假设c为空容器, 则该函数没有定义

    c.pop_front()

    删除容器c的第一个元素。返回void。假设c为空容器,则该函数没有定义

    仅仅适用于listdeque容器



    1、删除第一个/最后一个元素

        pop_front操作通常与front操作配套使用。实现以栈的方式处理容器:

    	while (!iDeq.empty())
    	{
    		proccess(iDeq.front());
    		iDeq.pop_front();
    	}
    

    【注意:】

        pop_frontpop_back函数的返回值并非删除的元素值,而是void

    要获取删除的元素值,则必须在删除元素之前调用frontback函数。


    2、删除容器内的一个/一段元素

        erase的两种形式都返回一个迭代器,它指向被删除元素或元素段后面的元素。

    也就是说,假设元素j恰好紧跟在元素i后面,则将元素i从容器中删除后,删除操作返回指向j的迭代器。

        如同其它操作一样,erase操作也不会检查它的參数。程序猿必须确保用作參数的迭代器或迭代器范围是有效的。因此。在删除元素之前。必须确保迭代器不是end迭代器,假设恰巧是end迭代器,则erase的操作没有定义。

    void printVec(const vector<string> &strVec)
    {
    	for (vector<string>::const_iterator iter = strVec.begin(); iter != strVec.end(); ++iter)
    	{
    		cout << *iter << endl;
    	}
    }
    int main()
    {
    //	freopen("input","r",stdin);
    	vector<string> strVec;
    	string val;
    	while (cin >> val)
    	{
    		strVec.push_back(val);
    	}
    	printVec(strVec);
    
    	string searchVal("Quasimodo");
    	vector<string>::iterator iter = find(strVec.begin(),strVec.end(),searchVal);
    
    	if (iter != strVec.end())
    	{
    		strVec.erase(iter);
    	}
    	printVec(strVec);
    } 
    

    3、删除容器内的全部元素

    	strVec.clear();
    	strVec.erase(strVec.begin(),strVec.end());

        同一时候,erase函数的迭代器版本号也提供了删除部分元素的功能:

    	string searchVal("Quasimodo");
    	vector<string>::iterator iter = find(strVec.begin(),strVec.end(),searchVal);
    	strVec.erase(strVec.begin(),iter);	//不会包括iter指向的元素
    	printVec(strVec);
    

        假设删除时,两个迭代器指向的元素是同一个元素。则不会删除不论什么元素。假设两个迭代器指向的元素有一个或两个不存在。则会发生执行时错误:

        strVec.erase(strVec.begin(),strVec.begin());
        printVec(strVec);
    
        strVec.erase(strVec.begin(),strVec.end()+1);
        printVec(strVec);
    

    【小心地雷o(∩∩)o...P282

        erasepop_frontpop_back函数使指向被删除元素的全部迭代器失效对于vector容器,指向删除点后面的元素的迭代器通常也会失效。而对于deque容器,假设删除时不包括第一个元素或最后一个元素,那么该deque容器相关的全部迭代器都会失效

    //P282 习题9.26
    void printVecInt(const vector<int> &strVec)
    {
        for (vector<int>::const_iterator iter = strVec.begin(); iter != strVec.end(); ++iter)
        {
            cout << *iter << '	';
        }
        cout << endl;
    }
    
    void printlistInt(const list<int> &strVec)
    {
        for (list<int>::const_iterator iter = strVec.begin(); iter != strVec.end(); ++iter)
        {
            cout << *iter << '	';
        }
        cout << endl;
    }
    
    int main()
    {
        int ia[] = {0,1,1,2,3,5,8,13,21,55,89};
        vector<int> iVec(ia,ia+sizeof(ia)/sizeof(*ia));
        list<int> iList(ia,ia+sizeof(ia)/sizeof(*ia));
    //    printlistInt(iList);
    //    printVecInt(iVec);
    
        for (vector<int>::iterator iter = iVec.begin(); iter != iVec.end(); ++iter)
        {
            if (!(*iter % 2))
            {
                iter =  iVec.erase(iter);
                -- iter;
            }
        }
        printVecInt(iVec);
    
        for (list<int>::iterator iter = iList.begin(); iter != iList.end(); ++iter)
        {
            if (*iter % 2)
            {
                iter = iList.erase(iter);
                -- iter;
            }
        }
        printlistInt(iList);
    }

    //习题9.27
    int main()
    {
    //	freopen("input","r",stdin);
        list<string> strList;
        string val;
    
        while (cin >> val)
        {
            strList.push_back(val);
        }
    
        string searchVal("dream");
        for (list<string>::iterator iter = strList.begin(); iter != strList.end(); ++iter)
        {
            if (*iter == searchVal)
            {
                strList.erase(iter);
                --iter;
            }
        }
        for (list<string>::iterator iter = strList.begin(); iter != strList.end(); ++iter)
        {
            cout << *iter << '	';
        }
        cout << endl;
    }
    

    八、赋值与swap

    顺序容器的赋值与swap操作

    c1= c2

    删除容器c1的全部元素,然后将c2的元素复制给c1

    c1c2的类型(包含容器类型和元素类型)必须同样

    c.assign(b,e)

    又一次设置c的元素:将迭代器be标记的范围内全部的元素拷贝到c中。

    be必须不是指向c中元素的迭代器

    c.assign(n,t)

    将容器c又一次设置为存储n个值为t的元素

    c1.swap(c2)

    交换内容:调用完该函数后,c1中存放的是c2原来的元素,c2中存放的则是c1原来的元素。

    c1c2的类型必须同样。

    该函数的运行速度通常要比将c2拷贝到c1的操作快


        与赋值相关的操作符都作用于整个容器。除了swap外,其它操作都能够通过eraseinsert来替代。

    赋值操作符首先删除其左操作数容器的全部元素,然后将右操作数容器的全部元素插入到左边容器中:

    	vec1 = vec2;
    	//等效于
    	vec1.erase(vec1.begin(),vec1.end());
    	vec1.insert(vec1.begin(),vec2.begin(),vec2.end());

        虽然赋值前两个容器的长度可能不相等。可是赋值后两个容器的长度都等于右边容器的长度!

    【小心地雷:】

        赋值和assign操作使左操作容器的全部迭代器失效,swap操作则不会使迭代器失效。完毕swap操作后,虽然被交换的元素已经存放在还有一容器中,但迭代器仍然指向同样的元素


    1、使用assign

        1)带有一对迭代器參数的assign操作同意我们将一个容器的元素赋给还有一个不同类型的容器。

    可是两种容器类型与元素类型必须相互兼容!

    	sList.assign(sVec.begin(),sVec.end());

        2assign运算的第二个版本号须要一个整型数值和一个元素值做參数,它将容器重置为存储指定数量的元素,而且每一个元素的值都为指定值

    	sList.assign(10,"o(∩∩)o...");
    

    2、使用swap操作以节省删除元素的成本

        swap操作实现交换两个容器内全部元素的功能。要交换的容器的类型必须匹配:操作数必须是同样类型的容器,并且所存储的元素类型也必须同样。

    调用了swap函数后,右操作数原来存储的元素被存放在左操作数中,反之亦然。

    void printListStr(const list<string> &sList)
    {
        for (list<string>::const_iterator iter = sList.begin(); iter != sList.end(); ++iter)
        {
            cout << *iter << endl;
        }
    }
    
    int main()
    {
        list<string> sList1(3,"o(∩∩)o...");
        list<string> sList2(4,"(*^__^*)");
    
        cout << "sList1:" << endl;
        printListStr(sList1);
        cout << "sList2:" << endl;
        printListStr(sList2);
    
        sList1.swap(sList2);
        cout << "sList1:" << endl;
        printListStr(sList1);
        cout << "sList2:" << endl;
        printListStr(sList2);
    }
    

        关于swap的一个重要问题在于:该操作不会删除或插入不论什么元素,并且保证在常量时间内实现交换

    因为容器内没有移动不论什么元素,因此迭代器不会失效

        没有移动元素这个事实意味着迭代器不会失效。它们指向同一元素,就像没作swap运算之前一样。尽管,swap运算后,这些元素已经被存储在不同的容器之中了。比如,在做 swap运算之前,有一个迭代器iter指向 svec1[3]字符串;实现swap运算后,该迭代器则指向svec2[3]字符串(这是同一个字符串,仅仅是存储在不同的容器之中而已)

        vector<string> sVec1(4,"o(∩∩)o...");
        vector<string> sVec2(3,"(*^__^*)");
    
        vector<string>::iterator iter = sVec1.end() - 1;
        cout << *iter << endl;
        sVec1.swap(sVec2);
        cout << *iter << endl;
    

    //P284 习题9.28
    void printListStr(const list<string> &sList)
    {
        for (list<string>::const_iterator iter = sList.begin(); iter != sList.end(); ++iter)
        {
            cout << *iter << endl;
        }
    }

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    [CSP-S模拟测试]:军训队列(DP+乱搞)
    [CSP-S模拟测试]:stone(结论+桶+前缀和+差分)
    [CSP-S模拟测试]:bird(线段树优化DP)
    [CSP-S模拟测试]:maze(二分答案+最短路)
    [CSP-S模拟测试]:优化(贪心+DP)
    uoj132/BZOJ4200/洛谷P2304 [Noi2015]小园丁与老司机 【dp + 带上下界网络流】
    Miiler-Robin素数测试与Pollard-Rho大数分解法
    hdu4336 Card Collector 【最值反演】
    loj2542 「PKUWC2018」随机游走 【树形dp + 状压dp + 数学】
    loj2540 「PKUWC2018」随机算法 【状压dp】
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4845448.html
Copyright © 2011-2022 走看看