list容器

STL为我们提供的链表是一个双向循环链表(下图中并没有体现出来循环)。由于链表只支持顺序访问,因此list容器的迭代器只支持双向访问,属于双向跌迭代器。


链表

链表采用动态分配空间,不会造成内存的浪费和溢出;同时插入和删除也十分方便,不需要移动大量元素,修改指针即可。 相比vector容器,list容器的插入和删除都不会使得原有的迭代器失效。但在vector容器下,如果数据插满了,需要去开辟新的空间,导致原来迭代器失效。

构造函数

函数原型

list<T> lst;  //采用类模板的方式实现默认构造的形式
list<T>(begin,end);  //利用构造函数将[begin,end)区间中的元素拷贝给本身
list<T>(n,elem);   //构造函数将n个elem拷贝给本身
list<T>(const list &lit)     //拷贝构造函数
void printList(const list<int> &l)
{
    for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    list<int> l1;  //默认构造
    l1.push_back(1);
    l1.push_back(3);
    l1.push_back(2);
    l1.push_back(4);
    l1.push_back(5);
    printList(l1);   //1 3 2 4 5 

    //将[l1.begin(),l1.end())元素拷贝给自己
    list<int>l2(l1.begin(), l1.end());
    printList(l2);  // 1 3 2 4 5 

    //拷贝构造
    list<int> l3(l2);
    printList(l3);  //1 3 2 4 5

    //10个100
    list<int> l4(10, 100);
    printList(l4);  //100 100 100 100 100 100 100 100 100 100 
}

list容器迭代器不可以跳跃式访问,但是可以进行“--”和“++”操作 。

赋值和交换

函数原型

assign(begin,end);  //将[beg,end)区间上的数据拷贝给自己
assign(n,elem); //将n个elem拷贝给自己
list& operator=(const list &lst)  //重载等号运算符
swap(lst)    //将lst与本身的元素互换 
void printList(const list<int> &l)
{
    for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

//赋值
void test01()
{
    list<int> l1;  //默认构造
    l1.push_back(1);
    l1.push_back(3);
    l1.push_back(2);
    l1.push_back(4);
    l1.push_back(5);
    printList(l1);   //1 3 2 4 5 
    
    //赋值 = 
    list<int> l2;
    l2 = l1;
    printList(l2);// 1 3 2 4 5

    //assign,[l2.begin(),l2.end())区间的数据拷贝给自己
    list<int> l3;
    l3.assign(l2.begin(), l2.end());
    printList(l3); // 1 3 2 4 5

    //assign 5个100
    list<int> l4;  
    l4.assign(5, 100);  
    printList(l4); // 100 100 100 100 100
}

//交换
void test02()
{
    list<int> l1;  
    l1.push_back(1);
    l1.push_back(3);
    l1.push_back(2);
    l1.push_back(4);
    l1.push_back(5);
    list<int> l2(10, 100);

    cout << "交换前:" << endl;
    printList(l1);   //1 3 2 4 5
    printList(l2);  // 100 100 100 100 100 100 100 100 100 100

    l1.swap(l2);

    cout << "交换后:" << endl;
    printList(l1); // 100 100 100 100 100 100 100 100 100 100
    printList(l2); //1 3 2 4 5
}

大小操作

函数院原型

size();  //返回容器中元素的个数
empty();  //判断容器是否为空
resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置,如果容器短,则末尾多出的部分被删除
resize(num,elme); //如果指定容器的长度为num,若容器变长,则以elem填充新的位置。若容器变短,则末尾超出容器长度被删除
void printList(const list<int> &l)
{
    for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    list<int> l1; //默认构造
    

    l1.push_back(1);
    l1.push_back(3);
    l1.push_back(2);
    l1.push_back(4);
    l1.push_back(5);
    if (l1.empty())
    {
        cout << "l1为空!" << endl;
    }
    else
    {
        cout << "l1不为空" << endl;
        cout << "l1的大小为" << l1.size() << endl;
        printList(l1); //1 3 2 4 5
    }

    //重新指定大小
    l1.resize(10);
    cout << "大小设置为10,多出来的位置用0填充" << endl;
    printList(l1); // 1 3 2 4 5 0 0 0 0 0

    l1.resize(3);
    cout << "大小设置为3,多出来的数据删除" << endl;
    printList(l1);  // 1 3 2

    l1.resize(10, 100);
    cout << "大小设置为10,多出来的位置用100填充" << endl;
    printList(l1);  //1 3 2
}

插入和删除

函数原型

push_back(elem)   //尾插一个元素
pop_back();  //尾删一个元素
push_front();  //从容器开头插入一个元素
pop_fron(); //从容器开头删除第一个元素
insert(pos.elem); //在pos位置插入elem的拷贝,返回新数据的位置
insert(pos, n,elem);//在pos处插入elem元素的拷贝,无返回值
insert(pos,begin,end);//在pos位置插入[begin,end)区间的数据,无返回值
clear(); //移出容器的所有数据
erase(begin,end); //删除[begin,end)区间的数据,无返回值。
erase(pos); //删除pos位置的数据,返回下一个数据的位置。
remove(elem); //删除容器中所有与elem值匹配的元素
void printList(const list<int> &l)
{
    for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    list<int> l1; 

    //尾插
    l1.push_back(10);
    l1.push_back(20);
    l1.push_back(30);

    //头插
    l1.push_front(1);
    l1.push_front(2);
    l1.push_front(3);
    printList(l1); // 3 2 1 10 20 30 

    //尾删
    l1.pop_back();
    printList(l1); //3 2 1 10 20 

    //头删
    l1.pop_front();
    printList(l1);  // 2 1 10 20

    //insert插入
    l1.insert(l1.begin(), 1000); //在l1的初始位置上插入1000
    printList(l1);//1000 2 1 10 20

    //在l1的第二个位置上插入3个10
    l1.insert(++l1.begin(), 3, 10);
    printList(l1); //1000 10 10 10 2 1 10 20

    //删除起始位置的元素
    l1.erase(l1.begin());
    printList(l1);  //10 10 10 2 1 10 20 

    //删除容器内所有的10
    l1.remove(10);
    printList(l1); //2 1 20

    //清空
    l1.clear();
    cout << "大小为" << l1.size() << endl; //0
}

list比之前说过的容器多了个remove函数。和其他的成员函数不同,它的参数不是一个迭代器,而是一个元素值,可以把容器内部所有的这个值都删除。

数据存取

函数原型

front(); //返回第一个元素
back(); //返回最后一个元素
void printList(const list<int> &l)
{
    for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    list<int> l1; 

    //尾插
    l1.push_back(10);
    l1.push_back(20);
    l1.push_back(30);
    printList(l1); // 10 20 30

    cout << "第一个元素为:" << l1.front() << endl;
    cout << "最后一个元素为:" << l1.back() << endl;
}

这里也和之前说过的容器不同,list容器没有了[]和at()操作,这也很好理解,因为它的内部是一个非连续的链表结构,链表是不支持随机访问的。

反转和排序

void printList(const list<int> &l)
{
    for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

//反转
void test01()
{
    list<int> l1; 

    //尾插
    l1.push_back(10);
    l1.push_back(23);
    l1.push_back(30);
    l1.push_back(13);
    l1.push_back(6);

    cout << "反转前:" << endl;
    printList(l1); //10 23 30 13 6 

    l1.reverse();

    cout << "反转后:" << endl;
    printList(l1);//6 13 30 23 10
}

bool compare(int v1, int v2)
{
    return v1 > v2;
}

//排序
void test02()
{
    list<int> l1; 
    l1.push_back(10);
    l1.push_back(23);
    l1.push_back(30);
    l1.push_back(13);
    l1.push_back(6);

    cout << "排序前:" << endl;
    printList(l1); //10 23 30 13 6 

    l1.sort(); //默认升序排列

    cout << "排序后:" << endl;
    printList(l1);//6 10 13 23 30 

    //降序,需要一个函数,改变sort函数的排序策略为降序
    l1.sort(compare);
    cout << "降序排序后:" << endl;
    printList(l1);//30 23 13 10 6
}

这里主要说一下test02排序算法。我们并没有使用<algorithm>下的标准排序算法,因为list容器不支持随机访问迭代器,只有支持随机访问迭代器的容器才可以使用标准排序算法。但是,这些不支持随机访问迭代器的容器内部会为我们提供必要的算法。本例中list容器的排序实使用的sort算法就是一个成员函数。与标准算法一样,它默认也是升序排列,如果想要实现降序排序,就需要一个函数或者仿函数。

排序按例

案例描述:将Person自定义数据类型进行排序,属性有姓名、年龄、身高。按年龄进行升序,如果年龄相同,按身高进行降序。

class Person
{
public:
    Person(string name, int age, int height)
    {
        this->age = age;
        this->height = height;
        this->name = name;
    }
    string name; //姓名
    int age;  //年龄
    int height;  //身高
};

void printList(const list<Person> &lp)
{
    for (list<Person>::const_iterator it = lp.begin(); it != lp.end(); it++)
    {
        cout << "姓名:" << it->name << " 年龄:" << it->age << " 身高:" << it->height << endl;
    }
}

//排序规则
bool compare(Person &p1, Person &p2)
{
    if (p1.age == p2.age)
    { 
        //年龄相同,按身高降序
        return p1.height > p2.height;
    }
    else
    {
        //年龄不相同 按身年龄升序
        return p1.age < p2.age;
    }
}


void test01()
{
    list<Person> l1;
    l1.push_back(Person("刘备", 30, 170));
    l1.push_back(Person("关羽", 20, 190));
    l1.push_back(Person("张飞", 20, 180));
    l1.push_back(Person("赵云", 18, 180));
    l1.push_back(Person("马超", 18, 160));
    l1.push_back(Person("黄忠", 40, 170));
    l1.push_back(Person("魏延", 20, 170));

    //排序前
    cout << "排序前:" << endl;
    printList(l1);

    l1.sort(compare);
    cout << "排序后:" << endl;
    printList(l1);
}

本案例的核心在于compare()函数。由于使list容器里面放的是自定义数据类型,所以必须要有一个函数来制定排序规则,否则无法排序。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容

  • 使用C++中list容器时必须包含 list基本概念 list链表是一种物理存储单元上非连续的存储结构,数据元素的...
    小鱼干子阅读 567评论 0 1
  • 基本概念 list也叫链表,是连式存储,和之前的容器比空间上非连续 如上,和数组连续空间不一样,列表存储空间额外预...
    ca8519be679b阅读 199评论 0 0
  • #define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include #...
    叫我Aluo丶啦阅读 652评论 0 0
  • 1.list容器基本概念 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链...
    JustaKid_83bd阅读 130评论 0 0
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 124,978评论 2 7