4.lists(双向链表)

一.概述

  是一个线性链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。它无需分配指定的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,并且由指针将有序的元素链接起来。由于其结构的原因,list 随机检索的性能非常的不好,因为它不像vector 那样直接找到元素的地址,而是要从头一个一个的顺序查找,这样目标元素越靠后,它的检索时间就越长。检索时间与目标元素的位置成正比。

  虽然随机检索的速度不够快,但是它可以迅速地在任何节点进行插入和删除操作。因为list 的每个节点保存着它在链表中的位置,插入或删除一个元素仅对最多三个元素有所影响,不像vector 会对操作点之后的所有元素的存储地址都有所影响,这一点是vector 不可比拟的。

二.特点

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

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

C++标准规定:每种的容器都必须提供自己的迭代器,容器提供的一些函数以获得迭代器并以之遍历所有元素,而迭代器就是容器提供的一种遍历的方式,其本质上是一个指针。

三.常用API

assign() 给list赋值
back() 返回最后一个元素
begin() 返回指向第一个元素的迭代器
clear() 删除所有元素
empty() 如果list是空的则返回true
end() 返回末尾的迭代器
erase() 删除一个元素
front() 返回第一个元素
get_allocator() 返回list的配置器
insert() 插入一个元素到list中
max_size() 返回list能容纳的最大元素数量
merge() 合并两个list
pop_back() 删除最后一个元素
pop_front() 删除第一个元素
push_back() 在list的末尾添加一个元素
push_front() 在list的头部添加一个元素
rbegin() 返回指向第一个元素的逆向迭代器
remove() 从list删除元素
remove_if() 按指定条件删除元素
rend() 指向list末尾的逆向迭代器
resize() 改变list的大小
reverse() 把list的元素倒转
size() 返回list中的元素个数
sort() 给list排序
splice() 合并两个list
swap() 交换两个list
unique() 删除list中重复的元素

四.示例Demo

1) 使用迭代器遍历当前list元素

#include <iostream>
#include <stdlib.h>
#include <list>

using namespace std;
#pragma warning(disable:4996)

/*
const int arraysize = 10;
int ai[arraysize] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int *begin = ai;
int *end = ai + arraysize; // end指向的是9后面的空间
for (int *pi = begin; pi != end; ++pi)
{
    cout << *pi << "";
}
*/

// 使用迭代器遍历当前链表1
void printlist(list<int> &l)
{
    for (list<int>::iterator p = l.begin(); p != l.end(); ++p)
    {
        cout << "current item is: " << *p << endl;
    }
}

// 使用迭代器遍历当前链表2
void printlist2(list<int> &l)
{
    list<int>::iterator current = l.begin();                      // 返回第一个元素的迭代器,头指针,迭代器本质上就是一个指针
    while (current != l.end())                                    // l.end() 代表末尾迭代器 尾指针
    {
        cout <<"current item is: " <<*current << endl;
        current++;
    }

}

int main() {

    list<int> l;

    for (int i = 0; i < 5; i++)
    {
        l.push_back(i + 1);
    }

    cout << "current list size is: " << l.size() << endl;
    printlist(l);

    printf("----------------------------------------\n");

    list<int> s;
    for (int i = 0; i < 10; i++)
    {
        s.push_front(0);
    }

    list<int>::iterator s_iterator = s.begin();                     // 从链表中取出链表的开头,赋值给迭代器,初始位置为0
    s_iterator++;
    s_iterator++;
    s_iterator++;                                                   // 当前迭代器运行到3号位置(从0开始)
    s.insert(s_iterator, 5);                                        // 在3号位置插入

    printlist2(s);

    system("pause");
    return 0;
}

运行结果:

current list size is: 5
current item is: 1
current item is: 2
current item is: 3
current item is: 4
current item is: 5
----------------------------------------
current item is: 0
current item is: 0
current item is: 0
current item is: 5
current item is: 0
current item is: 0
current item is: 0
current item is: 0
current item is: 0
current item is: 0
current item is: 0

2) 链表元素为结构体或结构体指针

#include <iostream>
#include <stdlib.h>
#include <list>

using namespace std;
#pragma warning(disable:4996)

struct Teacher {
    char name[20];
    int age;
};

// 使用迭代器遍历当前链表
void printlist(list<Teacher*> &l)
{
    for (list<Teacher*>::iterator p = l.begin(); p != l.end(); ++p)
    {
        Teacher *teacher = *p;
        cout << "Teacher, name is: " << teacher->name << ", age is: " << teacher->age << endl;
    }
}

// 使用迭代器遍历当前链表
void printlist2(list<Teacher> &l)
{
    list<Teacher>::iterator current = l.begin();                      // 返回第一个元素的迭代器,头指针,迭代器本质上就是一个指针
    while (current != l.end())                                          // l.end() 代表末尾迭代器 尾指针
    {
        Teacher teacher = *current;
        cout << "Teacher, name is: " << teacher.name << ", age is: " << teacher.age << endl;
        current++;
    }

}

int main() {

    Teacher t1, t2, t3;
    strcpy(t1.name,"jack");
    t1.age = 11;
    strcpy(t2.name,"mike");
    t2.age = 22;
    strcpy(t3.name,"tom");
    t3.age = 33;

    list<Teacher> l;
    l.push_back(t1);
    l.push_back(t2);
    l.push_back(t3);

    printlist2(l);

    printf("------------------指针元素-------------------\n");
    list<Teacher *> m;
    m.push_back(&t1);
    m.push_back(&t2);
    m.push_back(&t3);

    printlist(m);

    system("pause");
    return 0;
}

运行结果:

Teacher, name is: jack, age is: 11
Teacher, name is: mike, age is: 22
Teacher, name is: tom, age is: 33
------------------指针元素-------------------
Teacher, name is: jack, age is: 11
Teacher, name is: mike, age is: 22
Teacher, name is: tom, age is: 33

时间: 2024-10-14 19:27:49

4.lists(双向链表)的相关文章

[LeetCode]148.Merge Two Sorted Lists

[题目] Sort a linked list in O(n log n) time using constant space complexity. [分析] 单链表适合用归并排序,双向链表适合用快速排序.本题可以复用Merge Two Sorted Lists方法 [代码] /********************************* * 日期:2015-01-12 * 作者:SJF0115 * 题目: 148.Merge Two Sorted Lists * 来源:https://

【一天一道LeetCode】#160. Intersection of Two Linked Lists

一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Write a program to find the node at which the intersection of two singly linked lists begins. For example, the following two linked lists: A: a1 → a2 c1 → c2

4、数据类型二:Lists

1.关于list的组织形式 列表数据类型(Lists)可以存储一个有序的字符串列表,常用的操作时向列表两段添加元素,或者获取列表的某一个片段.列表类型的底层实现是一个双向链表(double linked list),所以向列表两端添加元素的时间复杂度为O(1),读取两端元素也非常快.同理,元素越是靠近中间位置,其读取速度越慢. 列表数据类型的组织形式如下: 图1. list组织结构图 用双向链表(双向箭头)将许多的字符串组织成了一个list(方括号). 2.list的命令集 LPUSH key

深入浅出Redis04使用Redis数据库(lists类型)

一  lists类型及操作 List是一个链表结构,主要功能是push,pop,获取一个范围的所有值等等,操作中key理解为链表的名字. Redis的list类型其实就是一个每个子元素都是sring类型的双向链表.我们可以通过push,pop操作从链表的头部或者尾部添加删除元素,这样 list既可以作为栈,有可以作为队列. 二 lists类型的使用 1. lpush 在key对应list的头部添加字符串. redis 127.0.0.1:6379> lpush mylist1 world (in

linux内核源码“双向链表list_head”续

上篇博文<linux内核源码"双向链表list_head">中以一个实例介绍了list_head双向链表的用法,只有实例的代码,并没有list_head链表的代码,考虑到各位好学博友的强烈愿望,今天把list_head的代码即list.h头文件粘贴到此,供各位好学博友使用. 一.list.h头文件源码 [[email protected] cstudy]# cat list.h             #list.h头文件 #ifndef _LINUX_LIST_H #de

数据结构第四篇——线性表的链式存储之双向链表

?注:未经博主同意,不得转载. 前面讨论的单链表,每个结点中只有一个指针域,用来存放指向后继结点的指针,因此,从某个结点出发只能顺时针往后查找其他结点.若要查找某个结点的直接前驱,则需要从头指针开始沿链表探寻,处理起来十分不方便.为克服单链表的这一缺点,可引入双向链表. 双向链表中每一个结点含有两个指针域,一个指针指向其直接前驱结点,另一个指针指向直接后继结点.和单链表类似,双向链表一般也只有头指针唯一确定:同样也可设头结点,使得双向链表的某些操作简便一些. 双向链表结构定义如下:  双向链表是

Merge Two Sorted Lists

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. Subscribe to see which companies asked this question /** * Definition for singly-linked list. * struct ListN

LeetCode 21 Merge Two Sorted Lists

翻译 合并两个排好序的链表,并返回这个新链表. 新链表应该由这两个链表的头部拼接而成. 原文 Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. 代码 /** * Definition for singly-linked list. * struct ListNode

双向链表(一)

参考: http://blog.sina.com.cn/s/blog_7d44748b01013fsf.html    (写的太好啦) http://blog.163.com/haibianfeng_yr/blog/static/34572620201453061036702/ 双(向)链表中有两条方向不同的链,即每个结点中除next域存放后继结点地址外,还增加一个指向其直接前趋的指针域prior.双向链表在查找时更方便 特别是大量数据的遍历 注意:    ①双链表由头指针head惟一确定的.