zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C++ list总结

C++List 总结
2023-09-14 09:05:45 时间

目录

介绍   

常用函数

函数使用举例

创建list并赋值

遍历和查找

删除元素

清空列表

向list中插入元素

使用assign给容器增加新元素

两个list交换

使用resize改变list的大小。

使用splice函数操作list

删除重复的元素

合并list

排序

list和vector的区别


介绍   

list是线性双向链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。它无需分配指定的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,并且由指针将有序的元素链接起来。由于其结构的原因,list 随机检索的性能非常的不好,因为它不像vector 那样直接找到元素的地址,而是要从头一个一个的顺序查找,这样目标元素越靠后,它的检索时间就越长。检索时间与目标元素的位置成正比。虽然随机检索的速度不够快,但是它可以迅速地在任何节点进行插入和删除操作。因为list 的每个节点保存着它在链表中的位置,插入或删除一个元素仅对最多三个元素有所影响,不像vector 会对操作点之后的所有元素的存储地址都有所影响,这一点是vector 不可比拟的。

https://images2015.cnblogs.com/blog/849009/201602/849009-20160203142350538-1403083351.png

list 的特点

(1) 不使用连续的内存空间,这样可以随意地进行动态操作;
(2) 可以在内部任何位置快速地插入或删除,当然也可以在两端进行push 和pop 。
(3) 不能进行内部的随机访问,即不支持[ ] 操作符和vector.at() ;
(4) 相对于verctor 占用更多的内存。

常用函数

List的构造函数和析构函数

list<Elem> c

产生一个空list,其中没有任何元素

list<Elem> c1(c2)

产生另一个同型list的副本(所有的元素都被拷贝)

list<Elem> c(n)

利用元素的default构造函数产生一个大小为n的list

list<Elem> c(n,elem)

产生一个大小为n的list,每个元素值都是elem

list<Elem> c(beg, end)

产生一个list,以区间[beg, end)做为元素初值

c.~list<Elem>()        

销毁所有元素,并释放内存

list的非变动性操作

size()

返回容器的大小

empty()   

判断容器是否为空,等价于size()==0,但可能更快

max_size()

返回容器最大的可以存储的元素

reserve()

如果容量不足,扩大之

c1 == c2

判断c1 是否等于c2

c1 != c2

判断c1是否不等于c2

c1 < c2

判断c1 是否小于c2

c1 > c2

判断c1 是否大于c2

c1 <= c2  

判断c1是否小于等于c2

c1 >= c2  

判断c1是否大于等于c2

list的赋值操作

c1 = c2     

将c2的全部元素赋值给c1

assign(n, elem)

复制n个elem,复制给c

assign(beg, end)     

将区间[beg;end)内的元素赋值给c

c1.swap(c2)

将c1和c2元素互换

swap(c1,c2)

同上,此为全局函数

元素访问

front        

返回第一个元素,不检查元素存在与否

back

返回最后一个元素,不检查元素存在与否

迭代器相关函数

begin()

返回一个双向迭代器,指向第一个元素

end()

返回一个双向迭代器,指向最后一个元素的下一个位置

rbegin()   

返回一个逆向迭代器,指向逆向迭代的第一个元素

end()

返回一个逆向迭代器,指向逆向迭代的最后一个元素的下一个位置

list安插、移除操作函数

 

insert(pos, elem)

在迭代器pos所指位置上安插一个elem副本,并返回新元素的位置

insert(pos,n,elem)

在pos位置上插入n个elem副本,无返回值

insert(pos,beg,end)

在pos位置上插入区间[beg,end)内的所有元素的副本,没有返回值

push_back(elem)

在尾部添加一个elem副本

pop_back()

移除最后一个元素,无返回值

push_front()    

在头部添加一个elem副本

pop_front()      

移除第一个元素,但不返回

remove(val)

移除所有其值为val的元素

remove_if()

删除一个链表中所有满足条件的元素

erase(pos)

移除pos位置上的元素,返回下一个元素的位置

erase(beg, end)

移除[beg, end)区间内的所有元素,返回下一个元素的位置

resize(num)

将元素数量改为num(如果size()变大了,多出来的新元素都需以default构造函数完成)

resize(num,elem)   

将元素数量改为num(如果size()变大了,多出来的新元素都elem的副本)

clear()      

移除所有元素,将容器清空

备注:安插和移除元素,都会使“作用点”之后的各个元素的iterator等失效,若发生内存重新分配,该容器身上的所有iterator等都会失效

List的特殊变动性操作

unique()

如果存在若干相邻而数值相等的元素,就移除重复元素,

之留下一个    

unique(op)       

如果存在若干相邻元素,都使op()的结果为ture,

则移除重复元素,只留下一个。

c1.splice(pos, c2)

将c2内的所有元素转移到c1之内,迭代器pos之前

c1.splice(pos, c2, c2pos)     

将c2内的c2pos所指元素转移到c1之内的pos所指位置上

(c1,c2可相同)

c1.splice(pos, c2,c2beg,c2end)  

将c2内的[c2beg,c2end)区间内所有元素转移到

c1内的pos之前(c1,c2可相同)

sort()

以operator<为准则,对所有元素排序

sort(op)

以op()为准则,对所有元素排序

c1.merge(c2)  

假设c1和c2容器都包含已序(相同的排序方式)元素,将c2的全部元素转移到c1,并保证合并后的list还是已序。

c1.merge(c2,op)

假设c1和c2容器都包含op()原则下的已序(相同的排序方式)元素,将c2的全部元素转移到c1,并保证合并后的list在op()原则仍是已序。

 

reverse()

将所有元素反序

函数使用举例

创建list并赋值

#include <iostream>

#include <list>

using namespace std;

int main() {

    //第一种,通过构造函数

    int myints[] = { 44,77,22,11,12 };

    list<int> mylist1(myints, myints + 5);

    list<int> mylist2(2, 100);         // 2个值为100的元素

    //第二种,用push_back,或push_front

    for (int i = 1; i <= 5; ++i) mylist1.push_back(i);

    mylist2.push_front(20);

    mylist2.push_front(30);

    //第三种,用assign

    list<int> first;

    list<int> second;

    first.assign(7, 10);                       // 给first添加7个值为10的元素

    second.assign(first.begin(), first.end()); // 复制first给second

    int myints1[] = { 32, 8, 4 };

    first.assign(myints1, myints1 + 3);         // 将数组myints的内容添加给first

    return 0;

}

遍历和查找

#include <iostream>

#include <list>

using namespace std;

int main() {

    //第一种,通过构造函数

    int myints[] = { 44,77,22,11,12};

    list<int> myList(myints, myints + 5);

    cout << "mylist contains:";

    //遍历

    for (list<int>::iterator it = myList.begin(); it != myList.end(); ++it)

    {

        cout << " " << *it;

    }

    cout << "\n";

    //查找

    for (list<int>::iterator it = myList.begin(); it != myList.end(); ++it)

    {

        if (*it == 22)

        {

            cout << "存在22";

        }

    }

    cout << "\n";

    //追加

    for (int i = 1; i <= 5; ++i)

        myList.push_back(i);

    //逆序遍历

    for (list<int>::reverse_iterator rit = myList.rbegin(); rit != myList.rend(); ++rit)

          cout << ' ' << *rit;

    return 0;

}

删除元素

 

// 创建实例以及赋值

#include <iostream>

#include <list>

using namespace std;

bool single_digit(const int& value) { return (value < 20); }

struct is_odd {

    //重载操作符 ()

    bool operator() (const int& value) { return (value % 2) == 1; }

};

int main() {

    //第一种,通过构造函数

    int myints[] = { 44,77,22,11,12 };

    list<int> myList(myints, myints + 5);

    cout << "mylist contains:";

    //遍历

    for (list<int>::iterator it = myList.begin(); it != myList.end(); ++it)

    {

        cout << " " << *it;

    }

    cout << "\n";

    //remove和remove_if删除元素

    myList.remove(22);

    myList.remove_if(single_digit);

    myList.remove_if(is_odd());

    //遍历

    for (list<int>::iterator it = myList.begin(); it != myList.end(); it++)

    {

        cout << " " << *it;

    }

    cout << "\n";

    //追加

    myList.push_back(22);

    for (list<int>::iterator it = myList.begin(); it != myList.end(); it++) {

        cout << " " << *it;

    }

    cout << "\n";

    //遍历删除,这是一种错误的写法。

    /*for (auto it = myList.begin(); it != myList.end(); it++)

    {

        if (*it == 11) {

             myList.erase(it);

        }

    }*/

    //第一种写法

    for (auto it = myList.begin(); it != myList.end();)

    {

        if (*it == 22) {

            myList.erase(it++);

        }

        else

        {

            cout << " " << *it;

            it++;

        }

    }

    //第二种写法

    for (auto it = myList.begin(); it != myList.end();)

    {

        if (*it == 22) {

            it=myList.erase(it);

        }

        else

        {

            cout << " " << *it;

            it++;

        }

    }

    return 0;

}

清空列表

#include <iostream>

#include <list>

using namespace std;

int main() {

    list<int> mylist;

    list<int>::iterator it;

    mylist.push_back(10);

    mylist.push_back(20);

    mylist.push_back(30);

    cout << "mylist contains:";

    for (it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    mylist.clear();

    mylist.push_back(2121);

    mylist.push_back(3232);

    cout << "mylist contains:";

    for (it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    return 0;

}

向list中插入元素

#include <iostream>

#include <list>

#include <vector>

using namespace std;

int main() {

    list<int> mylist;

    list<int>::iterator it;

    // 初始化

    for (int i = 1; i <= 5; ++i) mylist.push_back(i); // 1 2 3 4 5

    it = mylist.begin();

    ++it;       // 迭代器it现在指向数字2                      ^

    //在i0t指向的位置出插入元素10

    mylist.insert(it, 10);  // 1 10 2 3 4 5

    // "it" 仍然指向数字2                                   ^

    //在it指向的位置出插入两个元素20

    mylist.insert(it, 2, 20); // 1 10 20 20 2 3 4 5

    --it;       // 现在it指向数字20                             ^

    vector<int> myvector(2, 30); //创建vector容器,并初始化为含有2个值为30的元素

    //将vector容器的值插入list中

    mylist.insert(it, myvector.begin(), myvector.end());

    // 1 10 20 30 30 20 2 3 4 5

//it仍然指向数字20                            //               ^

    cout << "mylist contains:";

    for (it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    return 0;

}

使用assign给容器增加新元素

#include <iostream>

#include <list>

using namespace std;

int main() {

    list<int> first;

    list<int> second;

    first.assign(7, 10);// 给first添加7个值为10的元素

    second.assign(first.begin(), first.end()); // 复制first给second

    int myints[] = { 22, 33, 44 };

    first.assign(myints, myints + 3);  // 将数组myints的内容添加给first

    cout << "Size of first: " << int(first.size()) << '\n';

    cout << "Size of second: " << int(second.size()) << '\n';

    return 0;

}

两个list交换

// swap lists

#include <iostream>

#include <list>

using namespace std;

int main() {

    list<int> first(3, 100);   // 三个值为100的元素

    list<int> second(5, 200);  // 五个值为200的元素

    first.swap(second);

    cout << "first contains:";

    for (list<int>::iterator it = first.begin(); it != first.end(); it++)

        cout << ' ' << *it;

    cout << '\n';

    cout << "second contains:";

    for (list<int>::iterator it = second.begin(); it != second.end(); it++)

        cout << ' ' << *it;

    cout << '\n';

    return 0;

}

使用resize改变list的大小。

// resizing list

#include <iostream>

#include <list>

using namespace std;

int main() {

    list<int> mylist;

    // 初始化

    for (int i = 1; i < 10; ++i) mylist.push_back(i);//list为0 1 2 3 4 5 6 7 8 9

    mylist.resize(5);//list的长度变为5,元素为:0 1 2 3 4

    mylist.resize(8, 100);//list的长度变为8,超过5的部分变为100,元素为:0 1 2 3 4 100 100 100

    mylist.resize(12);//list的长度变为12,超过5的部分赋默认值0,元素为:0 1 2 3 4 100 100 100 0 0 0 0

    cout << "mylist contains:";

    for (list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    return 0;

}

使用splice函数操作list

// splicing lists

#include <iostream>

#include <list>

using namespace std;

int main() {

    list<int> mylist1, mylist2;

    list<int>::iterator it;

    // 初始化

    for (int i = 1; i <= 10; ++i)

        mylist1.push_back(i);      // mylist1: 1 2 3 4 5 6 7 8 9

    for (int i = 1; i <= 3; ++i)

        mylist2.push_back(i * 10);   // mylist2: 10 20 30

    it = mylist1.begin();

    ++it;                         // 指向数字2

    mylist1.splice(it, mylist2); // mylist1: 1 10 20 30 2 3 4

                                  // mylist2 (empty)

                                  // "it" 仍然指向数字2

    mylist2.splice(mylist2.begin(), mylist1, it);

    // mylist1: 1 10 20 30 3 4

    // mylist2: 2

    // "it" 此时已经无效了

    it = mylist1.begin();

    advance(it, 3);           // "it" 指向数字30

    mylist1.splice(mylist1.begin(), mylist1, it, mylist1.end());

    // mylist1: 30 3 4 1 10 20

    cout << "mylist1 contains:";

    for (it = mylist1.begin(); it != mylist1.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    cout << "mylist2 contains:";

    for (it = mylist2.begin(); it != mylist2.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    return 0;

}

 

删除重复的元素

// list::unique

#include <iostream>

#include <cmath>

#include <list>

using namespace std;

// a binary predicate implemented as a function:

bool same_integral_part(double first, double second) { return (int(first) == int(second)); }

 

// a binary predicate implemented as a class:

struct is_near {

    bool operator() (double first, double second) { return (fabs(first - second) < 5.0); }

};

 

int main() {

    double mydoubles[] = { 12.15, 2.72, 73.0, 12.77, 3.14,

                       12.77, 73.35, 72.25, 15.3, 72.25 };

    list<double> mylist(mydoubles, mydoubles + 10);

    cout << "mylist contains:";

    for (list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    mylist.unique();

    cout << "mylist contains:";

    for (list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    mylist.sort();             //  2.72,  3.14, 12.15, 12.77, 12.77,

                             // 15.3,  72.25, 72.25, 73.0,  73.35

    mylist.unique();           //  2.72,  3.14, 12.15, 12.77

                             // 15.3,  72.25, 73.0,  73.35

    cout << "mylist contains:";

    for (list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    mylist.unique(same_integral_part);  //  2.72,  3.14, 12.15                                 // 15.3,  72.25, 73.0

    cout << "mylist contains:";

    for (list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    mylist.unique(is_near());           //  2.72, 12.15, 72.25

    cout << "mylist contains:";

    for (list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    return 0;

}

合并list

#include <iostream>

#include <list>

using namespace std;

bool mycomparison(double first, double second) { return ((first) < (second)); }

int main() {

    list<double> first, second;

 

    first.push_back(3.1);

    first.push_back(2.2);

    first.push_back(2.9);

 

    second.push_back(3.7);

    second.push_back(7.1);

    second.push_back(1.4);

 

    first.sort();

    second.sort();

 

    first.merge(second);

    cout << "first contains:";

    for (list<double>::iterator it = first.begin(); it != first.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    // (second 现在为空)

    second.push_back(1.1);

    second.push_back(2.1);

    second.push_back(2.5);

   

    first.merge(second, mycomparison);

    cout << "first contains:";

    for (list<double>::iterator it = first.begin(); it != first.end(); it++)

        cout << ' ' << *it;

    cout << '\n';

    return 0;

}

排序

// list::sort

#include <iostream>

#include <list>

#include <string>

#include <cctype>

using namespace std;

// comparison, not case sensitive.

bool compare_nocase(const string& first, const string& second) {

    unsigned int i = 0;

    while ((i < first.length()) && (i < second.length())) {

        //将大写字母转为小写字母

        if (tolower(first[i]) < tolower(second[i])) return true;

        else if (tolower(first[i]) > tolower(second[i])) return false;

        ++i;

    }

    return (first.length() < second.length());

}

 

int main() {

    list<string> mylist;

    list<string>::iterator it;

    mylist.push_back("one");

    mylist.push_back("two");

    mylist.push_back("Three");

    mylist.push_back("Four");

    mylist.push_back("Five");

    mylist.push_back("Six");

    mylist.sort();

    cout << "mylist contains:";

    for (it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    mylist.sort(compare_nocase);

    cout << "mylist contains:";

    for (it = mylist.begin(); it != mylist.end(); ++it)

        cout << ' ' << *it;

    cout << '\n';

    return 0;

}

list和vector的区别

  1. vector数据结构
    vector和数组类似,拥有一段连续的内存空间,并且起始地址不变。
    因此能高效的进行随机存取,时间复杂度为o(1);
    但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内存块的拷贝,时间复杂度为o(n)
    另外,当数组中内存空间不够时,会重新申请一块内存空间并进行内存拷贝。

vector拥有一段连续的内存空间,能很好的支持随机存取,
因此vector<int>::iterator支持“+”“+=”“<”等操作符。

  1. list数据结构
    list是由双向链表实现的,因此内存空间是不连续的。
    只能通过指针访问数据,所以list的随机存取非常没有效率,时间复杂度为o(n);
    但由于链表的特点,能高效地进行插入和删除。

list的内存空间可以是不连续,它不支持随机访问,
因此list<int>::iterator则不支持“+”“+=”“<”

vector<int>::iteratorlist<int>::iterator都重载了“++”运算符。

总之,如果需要高效的随机存取,而不在乎插入和删除的效率,使用vector;
如果需要大量的插入和删除,而不关心随机存取,则应使用list

参考:

1、https://www.cnblogs.com/wj0816/p/6568630.html