欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

list

程序员文章站 2022-07-14 08:57:27
...

1.双向循环链表list的原理:

    list是双向循环链表,每个元素都知道前面一个元素和后面一个元素。在STL中,list和vector一样是俩个常用的容器。和vector不一样的是:list不支持对元素的任意存取。list中提供的成员函数与vector类似,不过list提供对首元素的操作push_front,pop_front,这个vector不具备的。和vector另一点不同的是,list的迭代器不会存在失效的情况,它不像vector会保留备份空间,在超过容量额度时会重新全部分配内存,导致迭代器失效;list没有备份空间的概念,出入一个元素就申请一个元素的空间,所以它的迭代器不会失效。

例如:

int data[6]={3,5,7,9,2,4};
    list<int>l(data,data+6);
    l.push_back(6);

list初始化时,申请的空间大小为6,存放了data中的6个元素,当向l中插入第七个元素“6”时,list申请新的节点单元,插入list链表中。

如图:

list

 

        list每次增加一个元素,不存在重新申请内存的情况,它的成本是恒定的。而vector没当增加关键元素的时候,都需要重新申请新的更大的内存空间,会调用元素的自身的复制构造函数,存在构造成本。在销毁旧内存的时候,会调用析构函数,存在析构成本。所以存储复杂类型和大量元素的情况下,list比vector更有优势。
        list是一个双向链表,双向链表既可以向前又可以向后链接其他元素。

       list将元素按顺序储存在链表中,与向量(vector)相比,它允许快速的插入和删除,但是随机访问却比较慢。

 

2.list的初始化:

 

list<int>li();              //申请一个空列表;
list<int>li(n);            //声明一个有n个元素的列表,每个元素都有其默认构造函数T()构造出来的;
list<int>li(n,val);       //声明一个由n个元素的列表,每个元素都是由其复制构造函数T(val)而来
list<int>li(first,last); //声明一个列表,其元素的初始值来源由区间所指定的序列中的元素
    

 

 

3.list的函数:

a:

crbegin/crend
cbegin/cend

这个4个是c++11新增的四个函数,在set那篇博客有详细的解释。

 

b:begin()和end()

通过调用list容器的成员函数begin()得到一个指向容器起始位置的iterator,可以调用list容器的 end() 函数来得到list末端下一位置,相当于:int a[n]中的第n+1个位置,实际上是不存在的,不能访问,经常作为循环结束判断结束条件使用。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[]={1,2,3,4};
    list<int>l(a,a+4);
    for(list<int>::iterator it=l.begin();it!=l.end();++it){
        cout<<*it<<" ";
    }
    cout<<endl;


    for(auto &it:l){
        cout<<it<<endl;
    }


    return 0;
}

list

 

 

 

c:push_back() 和push_front()

使用list的成员函数push_back和push_front插入一个元素到list中。其中push_back()从list的末端插入,而 push_front()实现的从list的头部插入。

d:front()和back()

 通过front()可以获得list容器中的头部元素,通过back()可以获得list容器的最后一个元素。但是有一点要注意,就是list中元素是空的时候,这时候调用front()和back()会发生什么呢?实际上会发生不能正常读取数据的情况,但是这并不报错,那我们编程序时就要注意了,个人觉得在使用之前最好先调用empty()函数判断list是否为空。

e:pop_back和pop_front()

通过删除最后一个元素,通过pop_front()删除第一个元素;序列必须不为空,如果当list为空的时候调用pop_back()和pop_front()会使程序崩掉。

f: empty()

利用empty() 判断list是否为空。

g:clear()

清空list中的所有元素。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    list<int>p(2,0);
    p.push_back(2);
    p.push_front(1);
    int len=p.size();
    cout<<"p的长度="<<len<<endl;
    for(auto &it:p){
        cout<<it<<" ";
    }
    cout<<endl;


    cout<<"头部元素="<<p.front()<<endl;
    cout<<"尾部元素="<<p.back()<<endl;


    p.pop_back();
    p.pop_front();
    for(auto &it:p){
        cout<<it<<" ";
    }
    cout<<endl;


    if(!p.empty()) cout<<"容器p不为空"<<endl;
    p.clear();
    if(p.empty()) cout<<"容器p为空"<<endl;





    return 0;
}

list

 

 

h:resize()

 如果调用resize(n)将list的长度改为只容纳n个元素,超出的元素将被删除,如果需要扩展那么调用默认构造函数T()将元素加到list末端。如果调用resize(n,val),则扩展元素要调用构造函数T(val)函数进行元素构造,其余部分相同。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    list<int>p;
    for(int i=1;i<10;i++) p.push_back(i);

    p.resize(5);
    p.resize(8,100);
    p.resize(12);
    for(auto &it:p) cout<<it<<" ";
    return 0;
}

1 2 3 4 5 100 100 100 0 0 0 0

 

 

i:assign()

具体和vector中的操作类似,也是有两种情况,第一种是:l1.assign(n,val)将 l1中元素变为n个T(val)。第二种情况是:l1.assign(l2.begin(),l2.end())将l2中的从l2.begin()到l2.end()之间的数值赋值给l1。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    list<int>first;
    list<int>second;
    first.assign(7,100);
    for(auto &it:first) cout<<it<<" ";
    cout<<endl;


    second.assign(first.begin(),first.end());
    for(auto &it:second) cout<<it<<" ";
    cout<<endl;

    int a[]={1,2,3};
    first.assign(a,a+3);
    for(auto &it:first) cout<<it<<" ";
    cout<<endl;

    return 0;
}

list

 

 

 

 j:reverse():

   通过reverse()完成list的逆置。

k:swap()

交换两个链表(两个重载),一个是l1.swap(l2); 另外一个是swap(l1,l2),都可能完成连个链表的交换。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    list<int>first;
    list<int>second;
    first.assign(7,100);
    second.assign(2,200);
    first.swap(second);
    for(auto &it:first) cout<<it<<" ";
    cout<<endl;

    for(auto &it:second) cout<<it<<" ";
    cout<<endl;

    return 0;
}

list

 

 

l: merge()

合并两个链表并使之默认升序(也可改),l1.merge(l2); 调用结束后l2变为空,l1中元素包含原来l1 和 l2中的元素,并且排好序,升序。

 

 

 

 

m: insert()  在指定位置插入一个或多个元素(三个重载):

l1.insert(l1.begin(),100); 在l1的开始位置插入100。

l1.insert(l1.begin(),2,200); 在l1的开始位置插入2个100。

l1.insert(l1.begin(),l2.begin(),l2.end());在l1的开始位置插入l2的从开始到结束的所有位置的元素。

#include <iostream>
#include <list>
#include<bits/stdc++.h>
using namespace std;

int main()
{
    list<int>p(2,100);
    p.insert(p.begin(),200);
    p.insert(p.begin(),3,50);
    list<int>l(3,666);
    p.insert(p.begin(),l.begin(),l.end());
    for(auto &it:p) cout<<it<<" ";
    return 0;
}

list

 

 

n:erase() 删除一个元素或一个区域的元素(两个重载)

l1.erase(l1.begin()); 将l1的第一个元素删除。

l1.erase(l1.begin(),l1.end()); 将l1的从begin()到end()之间的元素删除。

 

 

remove from list
#include <iostream>
#include <list>

int main ()
{
  int myints[]= {17,89,7,14};
  std::list<int> mylist (myints,myints+4);

  mylist.remove(89);

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

  return 0;
}
Edit & Run

 这个删除的是值不是迭代器指向的指针

mylist contains: 17 7 14