C/C++之vector和list详解

目录

0、总结

1、 vector

1.1 vector 说明

1.2 vector对象的常用内置函数使用(举例说明)

1.3. 顺序访问vector的几种方式,举例说明

1.3.1. 对向量a添加元素的几种方式

1.3.2从向量中读取元素

1.4.其它几种常用的函数

2、 list

2.1.list 说明

2.2.list 定义和初始化

2.3.list 函数介绍

2.4.函数使用举例


0、总结

Vector:顺序表

优点:和数组类似开辟一段连续的空间,并且支持随机访问,所以它的查找效率高其时间复杂度O(1)。 
缺点:由于开辟一段连续的空间,所以插入删除会需要对数据进行移动比较麻烦,时间复杂度O(n),另外当空间不足时还需要进行扩容。

List:链表

优点:底层实现是循环双链表,当对大量数据进行插入删除时,其时间复杂度O(1) 
缺点:底层没有连续的空间,只能通过指针来访问,所以查找数据需要遍历其时间复杂度O(n),没有提供[]操作符的重载。

应用场景

vector拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随即访问,而不在乎插入和删除的效率,使用vector。list拥有一段不连续的内存空间,如果需要高效的插入和删除,而不关心随机访问,则应使用list。
 

1、 vector

1.1 vector 说明

vector是向量类型,可以容纳许多类型的数据,因此也被称为容器
(可以理解为动态数组,是封装好了的类)
进行vector操作前应添加头文件#include <vector>
1.2 vector初始化:
方式1.

//定义具有10个整型元素的向量(尖括号为元素类型名,它可以是任何合法的数据类型),不具有初值,其值不确定
vector<int>a(10);

方式2.

//定义具有10个整型元素的向量,且给出的每个元素初值为1
vector<int>a(10,1);

方式3.

//用向量b给向量a赋值,a的值完全等价于b的值
vector<int>a(b);

方式4.

//将向量b中从0-2(共三个)的元素赋值给a,a的类型为int型
vector<int>a(b.begin(),b.begin+3);

方式5.

 //从数组中获得初值
int b[7]={1,2,3,4,5,6,7};
vector<int> a(b,b+7);

 

1.2 vector对象的常用内置函数使用(举例说明)

#include<vector>
vector<int> a,b;
//b为向量,将b的0-2个元素赋值给向量a
a.assign(b.begin(),b.begin()+3);
//a含有4个值为2的元素
a.assign(4,2);
//返回a的最后一个元素
a.back();
//返回a的第一个元素
a.front();
//返回a的第i元素,当且仅当a存在
a[i];
//清空a中的元素
a.clear();
//判断a是否为空,空则返回true,非空则返回false
a.empty();
//删除a向量的最后一个元素
a.pop_back();
//删除a中第一个(从第0个算起)到第二个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)结束
a.erase(a.begin()+1,a.begin()+3);
//在a的最后一个向量后插入一个元素,其值为5
a.push_back(5);
//在a的第一个元素(从第0个算起)位置插入数值5,
a.insert(a.begin()+1,5);
//在a的第一个元素(从第0个算起)位置插入3个数,其值都为5
a.insert(a.begin()+1,3,5);
//b为数组,在a的第一个元素(从第0个元素算起)的位置插入b的第三个元素到第5个元素(不包括b+6)
a.insert(a.begin()+1,b+3,b+6);
//返回a中元素的个数
a.size();
//返回a在内存中总共可以容纳的元素个数
a.capacity();
//将a的现有元素个数调整至10个,多则删,少则补,其值随机
a.resize(10);
//将a的现有元素个数调整至10个,多则删,少则补,其值为2
a.resize(10,2);
//将a的容量扩充至100,
a.reserve(100);
//b为向量,将a中的元素和b中的元素整体交换
a.swap(b);
//b为向量,向量的比较操作还有 != >= > <= <
a==b;

 

1.3. 顺序访问vector的几种方式,举例说明

1.3.1. 对向量a添加元素的几种方式

方式一.向向量a中添加元素

vector<int>a;
for(int i=0;i<10;++i){a.push_back(i);}

方式二.从数组中选择元素向向量中添加

int a[6]={1,2,3,4,5,6};
vector<int> b;
for(int i=0;i<=4;++i){b.push_back(a[i]);}

方式三.从现有向量中选择元素向向量中添加

int a[6]={1,2,3,4,5,6};
vector<int>b;
vector<int>c(a,a+4);
for(vector<int>::iterator it=c.begin();it<c.end();++it)
{
    b.push_back(*it);
}

方式四.从文件中读取元素向向量中添加ifstream in("data.txt");

vector<int>a;
for(int i;in>>i){a.push_back(i);}

 

1.3.2从向量中读取元素

方式一.通过下标方式获取

int a[6]={1,2,3,4,5,6};
vector<int>b(a,a+4);
for(int i=0;i<=b.size()-1;++i){cout<<b[i]<<endl;}

方式二.通过迭代器方式读取

 int a[6]={1,2,3,4,5,6};
 vector<int>b(a,a+4);
 for(vector<int>::iterator it=b.begin();it!=b.end();it++){cout<<*it<<"  ";}

方式三.常见错误赋值方式

vector<int>a;
for(int i=0;i<10;++i){a[i]=i;}//下标只能用来获取已经存在的元素

 

1.4.其它几种常用的函数

#include<algorithm>
 //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
 sort(a.begin(),a.end());
 //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
 reverse(a.begin(),a.end());
  //把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素
 copy(a.begin(),a.end(),b.begin()+1);
 //在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
  find(a.begin(),a.end(),10);

 

2、 list

2.1.list 说明

list 容器是由双向链表实现的,因此不能使用下标运算符 [] 访问其中的元素。

使用 list 的时候得加上 #include <list> 头文件以及得在 std 名字空间中使用。

 

2.2.list 定义和初始化

只需要简单的 list<TYPE> my_list; 就可以完成对一个 list 的定义了。不需要 new。

初始化的话就要用到 list 的构造函数。
一个简单的例子是:

 int myints[] = {75,23,65,42,13};
  list<int> mylist (myints, myints+5);

当然我们仍然可以使用一些函数对 list 增加删除元素。

 

2.3.list 函数介绍

这里介绍一些我觉得可能比较常用的函数。

迭代器:

函数名 作用
begin 将迭代器定位到开头
end 将迭代器定位到最后
rbegin 将逆向迭代器定位到最后
rend 将逆向迭代器定位到开头

C++ 11 标准又新增 cbegin, cend, crbegin 和 crend 这四个函数,返回的都是 const_iterator。

容量:

函数名  作用
empty  检查容器是否为空
size  返回当前容器内元素个数
max_size 返回当前容器能容纳的最大元素数量


元素访问:
 

函数名 作用
front 访问第一个元素
back 访问最后一个元素


更改 list:

函数名 作用
assign 为list分配新内容
push_front 将元素插入到开头
pop_front 删除第一个元素
push_back 将元素插入到最后
pop_back 删除最后一个元素
insert 插入元素
erase 删除元素
swap 交换两个 list 内容
resize 改变容器大小
clear 删除容器所有内容

C++ 11 标准又增加了 emplace_front, emplace_back, emplace 这三个函数

操作:

函数名 作用
splice 合并两个 list
remove 根据值删除元素
remove_if 删除满足条件的元素
unique 删除重复的值
merge 合并两个 list并排序
sort 对容器内的元素排序
reverse 将元素反序


2.4.函数使用举例

这里介绍一些函数的使用例子,加深理解。函数的排序按字典序排的,方便从目录查找跳转。

1)assign()

#include <iostream>
#include <list>
using namespace std;

template <class T>
void print_list(list<T> my_list)
{
    for (typename list<T>::iterator it = my_list.begin(); it != my_list.end(); ++it)
        cout << ' ' << *it;

    cout << '\n';
} 

int main ()
{
    list<int> first;
    list<int> second;

    first.assign (7, 100);                      // 7 ints with value 100
    print_list(first);
    // 100 100 100 100 100 100 100

    second.assign (first.begin(),first.end()); // a copy of first
    print_list(second);
    // 100 100 100 100 100 100 100

    int myints[]= {1776, 7, 4};
    first.assign (myints, myints+3);            // assigning from array
    print_list(first);
    // 1776 7 4

    cout << "Size of first: " << int (first.size()) << '\n';
    cout << "Size of second: " << int (second.size()) << '\n';
    // Size of first: 3
    // Size of second: 7
    
    return 0
}

2)begin() —— 对 list 进行顺序遍历
end() 的代码和这个一模一样。

#include <iostream>
#include <list>
using namespace std;

int main ()
{
    int myints[] = {75,23,65,42,13};
    list<int> mylist (myints,myints+5);

    cout << "mylist contains:";
    for (list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
        std::cout << ' ' << *it;

    cout << '\n';
    // mylist contains: 75 23 65 42 13
    return 0;
}

3)erase()——动态删除
#include <iostream>
#include <list>
using namespace std;

int main ()
{
    list<int> mylist;
    list<int>::iterator it1,it2;

    // set some values:
    for (int i=1; i<10; ++i) mylist.push_back(i*10);

                                // 10 20 30 40 50 60 70 80 90
    it1 = it2 = mylist.begin(); // ^^
    advance (it2,6);            // ^                 ^
    ++it1;                      //    ^              ^

    it1 = mylist.erase (it1);   // 10 30 40 50 60 70 80 90
                                //    ^           ^

    it2 = mylist.erase (it2);   // 10 30 40 50 60 80 90
                                //    ^           ^

    ++it1;                      //       ^        ^
    --it2;                      //       ^     ^

    mylist.erase (it1,it2);     // 10 30 60 80 90
                                //        ^

    cout << "mylist contains:";
    for (it1=mylist.begin(); it1!=mylist.end(); ++it1)
        cout << ' ' << *it1;
    cout << '\n';

    return 0;
}

使用 erase() 函数,我们可以实现动态的删除。

int main ()
{
    list<int> mylist;
    
    // set some values:
    for (int i=1; i<5; ++i) mylist.push_back(i*10);
    // 10 20 30 40

    cout << "mylist contains:";
    for (list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    {
        if (*it == 30)
            it = mylist.erase(it);
        cout << ' ' << *it;
    }
    cout << '\n';
    // mylist contains: 10 20 40
    
    return 0;
}

4)insert()——插入元素
insert 的参数还是到官网上查比较好,上面的表格里给出了链接。
下面的 ^ 表示当前的迭代器指向哪个元素。

#include <iostream>
#include <list>
#include <vector>
using namespace std;

int main ()
{
    list<int> mylist;
    list<int>::iterator it;

    // set some initial values:
    for (int i=1; i<=5; ++i) mylist.push_back(i); // 1 2 3 4 5

    it = mylist.begin();
    ++it;       // it points now to number 2           ^

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

    // "it" still points to number 2                      ^
    mylist.insert (it,2,20);                      // 1 10 20 20 2 3 4 5

    --it;       // it points now to the second 20            ^

    vector<int> myvector (2,30);
    mylist.insert (it,myvector.begin(),myvector.end());
    // 1 10 20 30 30 20 2 3 4 5
    //               ^
    cout << "mylist contains:";
    for (it=mylist.begin(); it!=mylist.end(); ++it)
        cout << ' ' << *it;
    cout << '\n';
    // mylist contains: 1 10 20 30 30 20 2 3 4 5
    
    return 0;
}

5)merge() —— 合并两个 list

#include <iostream>
#include <list>
using namespace std;

// compare only integral part:
bool mycomparison (double first, double second)
{
    return ( int(first)<int(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();  // 2.2 2.9 3.1
    second.sort(); // 1.4 3.7 7.1

    first.merge(second); // 1.4 2.2 2.9 3.1 3.7 7.1

    // (second is now empty)

    second.push_back (2.1);  // 2.1

    first.merge(second, mycomparison);

    cout << "first contains:";
    for (list<double>::iterator it=first.begin(); it!=first.end(); ++it)
        cout << ' ' << *it;
    cout << '\n';
    // first contains: 1.4 2.2 2.9 2.1 3.1 3.7 7.1
    
    return 0;
}

但是经过我的尝试,好像可以不排序合并:

int main ()
{
    list<double> first, second;

    for (int i=1; i<=5; ++i) first.push_back(i);
    for (int i=1; i<=5; ++i) second.push_back(i+10);

    first.merge(second);
    // (second is now empty)

    cout << "first contains:";
    for (list<double>::iterator it=first.begin(); it!=first.end(); ++it)
        cout << ' ' << *it;
    cout << '\n';
    // first contains: 1 2 3 4 5 11 12 13 14 15
    
    return 0;
}

6)rbegin() —— 对 list 进行逆向遍历

#include <iostream>
#include <list>
using namespace std;

int main ()
{
    list<int> mylist;
    for (int i=1; i<=5; ++i) mylist.push_back(i);

    cout << "mylist backwards:";
    for (list<int>::reverse_iterator rit=mylist.rbegin(); rit!=mylist.rend(); ++rit)
        cout << ' ' << *rit;

    cout << '\n';
    // mylist backwards: 5 4 3 2 1
    return 0;
}

利用『逆向』这个特性,我们还可以用来实现逆向排序。STL 里的 sort 默认是按自然数顺序来排序的,要想实现从大到小排序的效果,我们有三种方法:

自己写比较函数

struct greater
{
    template<class T>
    bool operator()(T const &a, T const &b) const { return a > b; }
};

std::sort(numbers.begin(), numbers.end(), greater());

指定比较规则

std::sort(numbers.begin(), numbers.end(), std::greater<int>());

使用 rbegin()

std::sort(numbers.rbegin(), numbers.rend());   // note: reverse iterators

7)remove()

#include <iostream>
#include <list>
using namespace std;

int main ()
{
    int myints[]= {17,89,7,14};
    list<int> mylist (myints,myints+4);
    // 17 89 7 14
    mylist.remove(89);
    
    cout << "mylist contains:";
    for (list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
        cout << ' ' << *it;
    cout << '\n';
    // mylist contains: 17 7 14

    return 0;
}

它会删除所有匹配的值,也就是说

    int myints[]= {17,89,7,89,14};
    list<int> mylist (myints,myints+5);
    // 17 89 7 89 14
    
    mylist.remove(89);
    // mylist contains: 17 7 14

如果你想像下面这样写的话,会出现死循环。

int main ()
{
    int myints[]= {17,89,7,14};
    list<int> mylist (myints,myints+4);
    // 17 89 7 14
    
    cout << "mylist contains:";
    for (list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it) {
        if (*it == 89) 
            mylist.remove(89);
        cout << ' ' << *it;
    }

    cout << '\n';
    // 死循环

    return 0;
}

想要达到上述的效果,可以使用 erase() 函数。具体代码见那一节。

参考文献链接:
https://blog.csdn.net/weixin_41743247/article/details/90635931

https://blog.csdn.net/sinat_41104353/article/details/84900018

发布了12 篇原创文章 · 获赞 49 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_36570733/article/details/104134881
今日推荐