C++基础10:STL容器list

1.基础操作

1.1 遍历+正反顺序打印

(1)C++11遍历的方法

for(auto n:l){ // (1)C++11遍历的方法
        cout << n << " ";
    }
    cout << endl;

(2)不支持下标访问

for(int i=0;i<l.size();++i){
        // cout << l[i] << " "; // (2)不支持下标访问
    }

(3)正序打印

list<int>::iterator it = l.begin();  //(3)正序打印
    while(it != l.end()){
       cout << *it << " ";
       ++it;
    }
    cout << endl;

(4)逆序打印

list<int>::reverse_iterator rit = l.rbegin();//(4)逆序打印
    while(rit != l.rend()){
       cout << *rit << " ";
       ++rit;
    }
    cout << endl;
  • 完整案例
#include <iostream>
#include <list>
#include <vector>

using namespace std;
void Travesal(const list<int>& l){
    list<int>::const_iterator it = l.cbegin();//cbegin() C++11
    while(it != l.cend()){ //cend() C++11
       cout << *it << " ";
       ++it;
    }
    cout << endl;
}
void TravesalReverse(const list<int>& l){
    list<int>::const_reverse_iterator rit = l.crbegin();
    while(rit != l.crend()){
       cout << *rit << " ";
       ++rit;
    }
    cout << endl;
}
int main()
{
     list<int> l = {1,2,3,4,5};// C++11

    for(auto n:l){ // (1)C++11遍历的方法
        cout << n << " ";
    }
    cout << endl;

    for(int i=0;i<l.size();++i){
        // cout << l[i] << " "; // (2)不支持下标访问
    }

    list<int>::iterator it = l.begin();  //(3)正序打印
    while(it != l.end()){
       cout << *it << " ";
       ++it;
    }
    cout << endl;

    list<int>::reverse_iterator rit = l.rbegin();//(4)逆序打印
    while(rit != l.rend()){
       cout << *rit << " ";
       ++rit;
    }
    cout << endl;
    Travesal(l); 
    TravesalReverse(l);

}

1.2 添加,删除

(1)尾添加

 l.push_back(6);

(2)尾删除

l.pop_back();

(3) 首添加

l.push_front(-2);

(4) 首删除

l.pop_front();
  • 完整案例
#include <iostream>
#include <list>
#include <vector>

using namespace std;
void Travesal(const list<int>& l){
    list<int>::const_iterator it = l.cbegin();//cbegin() C++11
    while(it != l.cend()){ //cend() C++11
       cout << *it << " ";
       ++it;
    }
    cout << endl;
}
void TravesalReverse(const list<int>& l){
    list<int>::const_reverse_iterator rit = l.crbegin();
    while(rit != l.crend()){
       cout << *rit << " ";
       ++rit;
    }
    cout << endl;
}
int main()
{
     list<int> l = {1,2,3,4,5};// C++11
     Travesal(l);

     // 尾添加
    l.push_back(6);
    l.push_back(7);
    l.push_back(8);
    Travesal(l);
    // 尾删除
    l.pop_back();
    l.pop_back();
    l.pop_back();
    Travesal(l);

    // 首添加
    l.push_front(-2);
    l.push_front(-1);
    l.push_front(0);
    Travesal(l);
    // 首删除
    l.pop_front();
    l.pop_front();
    l.pop_front();
    Travesal(l);

}

1.3 任意位置添加、删除

(1)insert():list的迭代器不能做算术运算,没有算术运算符重载,但是可以自增自减(左闭右开的区间)

// 插入
    auto it = l.begin();
    ++it;
    // it = it + 1; // (1)list的迭代器不能做算术运算,没有算术运算符重载,但是可以自增自减
    l.insert(it,100); //表示在begin()+1的内存插入100,内存发生改变;此时it指针指向100的后面;(左闭又开的区间)

(2) erase():想要删除100,必须指向100的内存;必须先自减

 // 删除
    --it;
    l.erase(it);  //(2)想要删除100,必须指向100的内存;必须先自减
    Travesal(l);

(3) 批量插入: 插入多个相同的元素,此时指向index=5的后面;

// 批量插入
    it = l.begin();
    ++it;
    l.insert(it,5,100); //插入多个相同的元素,此时指向index=5的后面;
    Travesal(l);

(4) 批量删除

 list<int>::iterator first = l.begin();
    ++first;
    l.erase(first,it);// 删除的部分[1,6)
    Travesal(l);

(5) 插入数组

   int arr[] = {11,12,13,14};
    l.insert(it,arr,arr+4);
    Travesal(l);

(6) 插入向量

vector<int> vec = {21,22,23,24};
l.insert(l.end(),vec.begin(),vec.end());
Travesal(l);

(7) 随机访问,只能遍历
next() :C++11,begin()往后数4个元素;ndex = 4;
prev() : 往前数三个元素,index=end()-3,即倒数第三个数,首尾的差异

auto it = next(l.begin(),4); //C++11,begin()往后数4个元素;ndex = 4;
//prev()    往前数三个元素,index=end()-3,即倒数第三个数,首尾的差异
*it = 10000;
Travesal(l);
  • 完整案例
#include <iostream>
#include <list>
#include <vector>

using namespace std;
void Travesal(const list<int>& l){
    list<int>::const_iterator it = l.cbegin();//cbegin() C++11
    while(it != l.cend()){ //cend() C++11
       cout << *it << " ";
       ++it;
    }
    cout << endl;
}
void TravesalReverse(const list<int>& l){
    list<int>::const_reverse_iterator rit = l.crbegin();
    while(rit != l.crend()){
       cout << *rit << " ";
       ++rit;
    }
    cout << endl;
}
int main()
{
     list<int> l = {1,2,3,4,5};// C++11
     Travesal(l);

  // 插入
    auto it = l.begin();
    ++it;
    // it = it + 1; // (1)list的迭代器不能做算术运算,没有算术运算符重载,但是可以自增自减
    l.insert(it,100); //表示在begin()+1的内存插入100,内存发生改变;此时it指针指向100的后面;(左闭又开的区间)
    Travesal(l);

    // 删除
    --it;
    l.erase(it);  //(2)想要删除100,必须指向100的内存;必须先自减
    Travesal(l);


    // 批量插入
    it = l.begin();
    ++it;
    l.insert(it,5,100); //插入多个相同的元素,此时指向index=5的后面;
    Travesal(l);

    // 批量删除
    list<int>::iterator first = l.begin();
    ++first;
    l.erase(first,it);// 删除的部分[1,6)
    Travesal(l);

    // 插入数组
    int arr[] = {11,12,13,14};
    l.insert(it,arr,arr+4);
    Travesal(l);

    // 插入向量
    vector<int> vec = {21,22,23,24};
    l.insert(l.end(),vec.begin(),vec.end());
    Travesal(l);
	
	auto it = next(l.begin(),4); //C++11,begin()往后数4个元素;ndex = 4;
	//prev()    往前数三个元素,index=end()-3,即倒数第三个数,首尾的差异
	*it = 10000;
	Travesal(l);

}

1.4 list特有的函数

(1) reverse: 逆序

  l.reverse();
  Travesal(l);

(2) sort:排序

  l.sort();
  Travesal(l);

(3) merge():按大小顺序插入

  list<int> l2={3,6,9,10,13};
  l.merge(l2);

(4) remove(): 删除值

  l.remove(1);
  Travesal(l);

(5) 删除某个条件的值
a.普通函数

  bool condition(int n){
    return n/10 == 1;
}
  l.remove_if(condition);1)普通函数

b. 仿函数

 Condition cond; 
    l.remove_if(cond); //(2)仿函数
     l.remove_if(Condition());

c. lamabda表达式

  l.remove_if([](int n){return n/10==1;}); //(3)lamabda表达式
  • 完整案例
#include <iostream>
#include <list>
#include <vector>

using namespace std;
void Travesal(const list<int>& l){
    list<int>::const_iterator it = l.cbegin();//cbegin() C++11
    while(it != l.cend()){ //cend() C++11
       cout << *it << " ";
       ++it;
    }
    cout << endl;
}
void TravesalReverse(const list<int>& l){
    list<int>::const_reverse_iterator rit = l.crbegin();
    while(rit != l.crend()){
       cout << *rit << " ";
       ++rit;
    }
    cout << endl;
}

bool condition(int n){
    return n/10 == 1;
}

int main()
{
     list<int> l = {1,2,3,4,5};// C++11
     Travesal(l);

  // list特有的成员函数
    // 逆序
    l.reverse();
    Travesal(l);

    // 排序
    l.sort();
    Travesal(l);

    list<int> l2={3,6,9,10,13};

    l.merge(l2);
    Travesal(l);

    // 删除值
    l.remove(1);
    Travesal(l);

    // 删除某个条件的值
    // l.remove_if(condition);(1)普通函数
    // Condition cond; 
    // l.remove_if(cond); //(2)仿函数
    // l.remove_if(Condition());
    l.remove_if([](int n){return n/10==1;}); //(3)amabda表达式
    Travesal(l);

}

(***)2 面试操作(vector.list之间的转化)

2.1 (88)合并两个有序数组

合并两个有序数组

在这里插入图片描述
(1)vector转化为list

list<int> list1(nums1.begin(),nums1.begin()+m);  //(1)vector转化为list

(2)将list2融入到list1

   list1.merge(list2);//(2)将list2融入到list1

(3)list,vector之间的转化

 nums1.assign(list1.begin(),list1.end());      //(3)list,vector之间的转化
  • 完整代码
class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {

    list<int> list1(nums1.begin(),nums1.begin()+m);  //(1)vector转化为list
    list<int> list2(nums2.begin(),nums2.begin()+n);
    list1.merge(list2);//(2)将list2融入到list1
    nums1.assign(list1.begin(),list1.end());      //(3)list,vector之间的转化
}
};

3 实现list(miniSTL)

3.1 利用链表简单的构造

(1.1) 节点初始化链表,list初始化链表

 Node(const T& val):val(val),prev(NULL),next(NULL){}  //(1.1)节点初始化链表
 list():head(NULL),tail(NULL),_size(0){}  //(1.2)list初始化链表

(1.2) 实现尾插法:

 void push_back(const T& val){  //(1.2)尾插法插入元素
        ++_size;
        Node* node = new Node(val);
        if(NULL == head){
            head = tail = node;
        }else{
            tail->next = node;
            node->prev = tail;
            tail = node;           
        }
    }

(1.3)重载 [] 运算符;

T& operator[](int index){  //(1.3)重载 [] 运算符;
        // if(index<0 || index >=_size) throw exception(string("invalid index"));
        int count = 0;
        Node* p = head;
        while(NULL != p){
            if(count++ == index) break;
            p = p->next;
        }
        return p->val;
    }

(1.4)c语言的方式进行打印

for(int i=0;i<li.size();++i){
       cout << li[i] << endl;
    }

(1.5)注意list类的大小与嵌套的struct无关;

3.2 迭代器的加入+运算符重载+通用算法

(2.1)加入迭代器

class iterator{
        Node* p;
    public:
        iterator(Node* p):p(p){}
        T& operator*(){return p->val;}
        T* operator->(){return &(p->val);}
        iterator operator++(){
            p=p->next;
            return *this;
        }
        iterator operator++(int){
            iterator tmp(*this);
            p=p->next;
            return tmp;
        }
        iterator operator--(){
            p = p->prev;
            return *this;
        }
        iterator operator--(int){
            iterator tmp(*this);
            p=p->prev;
            return tmp;
        }

        bool operator==(const iterator& it)const{
            return p == it.p;
        }
        bool operator!=(const iterator& it)const{
            return p != it.p;
        }
    };

    iterator begin(){return iterator(head);}
    iterator end(){return iterator(NULL);}
};

(2.2)通用算法(for_each()+ accumulate())

template <typename IT,typename FUNC>
void for_each(IT first,IT last,FUNC func){
    while(first!=last){
        func(*first++);
    }
}

template <typename IT,typename VAL>
VAL accumulate(IT first,IT last,VAL val){
    while(first!=last){
        val+=*first++;
    }
    return val;

}

3.3 list特有算法(首尾(插删))

(3.1)首尾插删

   //尾插法
    void push_back(const T& val){
        ++_size;
        Node* node = new Node(val);  //(1)先创建数据节点
        if(NULL == head){
            head = tail = node;     //(2)头结点判空操作
        }else{                       //(3)先考虑现在:
            tail->next = node;      //(3.1)尾节点的下一个是node;
            node->prev = tail;        //(3.2)node的上一个是尾节点
            tail = node;             //(3.3)refresh
        }
        tail -> next =NULL;
    }
//头插法
    void push_front(const T& val){
        ++_size;
        Node* node = new Node(val);  //(1)先创建数据节点;
        if(NULL == head){            //(2)头结点判空;
            head = tail = node;
        }else{                         //(3)先考虑现在:
            node->next = head;           //(3.1)数据的下一个节点是头结点;
            head->prev = node;            //(3.2)头结点的上一个节点是数据结点;
            head = node;                    //(3.3)refresh;
        }
        tail ->next =NULL;
    }
    
    //尾删法
    void pop_back(){
        --_size;
        Node* prev = tail->prev;        //(1)创建新的尾部结点(即taild的前一个结点)
        if(NULL == prev){               //(2)新的尾节点的判空操作
            head = NULL;
        }else{                           //(3)先考虑现在:
            prev->next = NULL;          //(3.1)新的尾节点的下一个节点是NULL;
        }
        delete tail;                    //(3.2)释放尾节点
        tail = prev;                    //refresh
    }
    
    
    //头删法
    void pop_front(){
        --_size;
        Node* next = head->next;   //(1)创建新的头部节点
        if(NULL == next){          //(2)新的头结点的判空操作;
            tail = NULL;
        }else{                        //(3)先考虑现在:
            next->prev = NULL;        //(3.1)清空原来的头指针   
        }
        delete head;                   //(3.2)删除原来的头指针
        head = next;                      //(3.3) refresh
    }

(3.2)注意:考虑到创建,释放内存 ,必须要有析构函数

  ~list(){
        while(NULL != head){
            Node* next = head->next;  //(1)一直析构头结点;
            delete head;             //(2)清空头结点
            head = next;             //(3)refresh
        }
        head = tail = NULL;          //(4)指针清空
        _size = 0;                    //——size归0
    }

3.4 完整代码

#include <iostream>
// #include <algorithm>
// #include <list>
#include <exception>
using namespace std;

namespace miniSTL{
template<typename T>
class list{
    struct Node{
        T val;
        Node* prev;
        Node* next;
        Node(const T& val):val(val),prev(NULL),next(NULL){}
    };
    Node* head,*tail;
    size_t _size;
public:
    list():head(NULL),tail(NULL),_size(0){}
    // 拷贝构造/赋值运算符重载函数
    ~list(){
        while(NULL != head){
            Node* next = head->next;  //(1)一直析构头结点;
            delete head;             //(2)清空头结点
            head = next;             //(3)refresh
        }
        head = tail = NULL;          //(4)指针清空
        _size = 0;                    //——size归0
    }

    //w尾插法
    void push_back(const T& val){
        ++_size;
        Node* node = new Node(val);  //(1)先创建数据节点
        if(NULL == head){
            head = tail = node;     //(2)头结点判空操作
        }else{                       //(3)先考虑现在:
            tail->next = node;      //(3.1)尾节点的下一个是node;
            node->prev = tail;        //(3.2)node的上一个是尾节点
            tail = node;             //(3.3)refresh
        }
        tail -> next =NULL;
    }
//头插法
    void push_front(const T& val){
        ++_size;
        Node* node = new Node(val);  //(1)先创建数据节点;
        if(NULL == head){            //(2)头结点判空;
            head = tail = node;
        }else{                         //(3)先考虑现在:
            node->next = head;           //(3.1)数据的下一个节点是头结点;
            head->prev = node;            //(3.2)头结点的上一个节点是数据结点;
            head = node;                    //(3.3)refresh;
        }
        tail ->next =NULL;
    }
    
    //尾删法
    void pop_back(){
        --_size;
        Node* prev = tail->prev;        //(1)创建新的尾部结点(即taild的前一个结点)
        if(NULL == prev){               //(2)新的尾节点的判空操作
            head = NULL;
        }else{                           //(3)先考虑现在:
            prev->next = NULL;          //(3.1)新的尾节点的下一个节点是NULL;
        }
        delete tail;                    //(3.2)释放尾节点
        tail = prev;                    //refresh
    }
    
    
    //头删法
    void pop_front(){
        --_size;
        Node* next = head->next;   //(1)创建新的头部节点
        if(NULL == next){          //(2)新的头结点的判空操作;
            tail = NULL;
        }else{                        //(3)先考虑现在:
            next->prev = NULL;        //(3.1)清空原来的头指针   
        }
        delete head;                   //(3.2)删除原来的头指针
        head = next;                      //(3.3) refresh
    }

    size_t size()const{
        return _size;
    }
    T& operator[](int index){
        // if(index<0 || index >=_size) throw exception(string("invalid index"));
        int count = 0;
        Node* p = head;
        while(NULL != p){
            if(count++ == index) break;
            p = p->next;
        }
        return p->val;
    }

    class iterator{
        Node* p;
    public:
        iterator(Node* p):p(p){}
        T& operator*(){return p->val;}
        T* operator->(){return &(p->val);}
        iterator operator++(){
            p=p->next;
            return *this;
        }
        iterator operator++(int){
            iterator tmp(*this);
            p=p->next;
            return tmp;
        }
        iterator operator--(){
            p = p->prev;
            return *this;
        }
        iterator operator--(int){
            iterator tmp(*this);
            p=p->prev;
            return tmp;
        }

        bool operator==(const iterator& it)const{
            return p == it.p;
        }
        bool operator!=(const iterator& it)const{
            return p != it.p;
        }
    };

    iterator begin(){return iterator(head);}
    iterator end(){return iterator(NULL);}
};

template <typename IT,typename FUNC>
void for_each(IT first,IT last,FUNC func){
    while(first!=last){
        func(*first++);
    }
}

template <typename IT,typename VAL>
VAL accumulate(IT first,IT last,VAL val){
    while(first!=last){
        val+=*first++;
    }
    return val;
}

}
using namespace miniSTL;

int main(){
    list<int> li;
    li.push_back(1);
    li.push_back(2);
    li.push_back(3);
    cout << sizeof(li) << endl;

    cout << li.size() << endl;

    for(int i=0;i<li.size();++i){
//        cout << li[i] << endl;
    }

    list<int>::iterator it = li.begin();
    while(it!=li.end()){
        cout << *it++ << endl;
        //++it;
    }
    for(auto n:li){
        cout << n << endl;
    }

    li.push_front(0);
    li.push_front(-1);
    li.push_front(-2);
    li.pop_back();
    li.pop_back();
    li.pop_back();
    li.pop_back();
    li.pop_back();
    li.pop_back();
    li.push_front(-1);
    li.push_front(-2);
    li.pop_front();
    li.pop_front();
    for_each(li.begin(),li.end(),[](int n){cout << n << endl;});

    cout<< accumulate(li.begin(),li.end(),0) << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值