C++ 简单版STL list 链表(迭代器版)

最近课程开始上设计模式了。

苦于天天满课的状态,不过题目可以放到晚上去刷。

周末师大校赛挺有趣的,题目质量好高。

花了几天写LIST,一开始就想写出 跟STL用法一样的LIST,

加个迭代器然后循环着自己用。

结果发现!!!!好多坑,有C++ 模板 C++ 符号重载等等。

不过也提高了点C++ 代码能力。感觉迭代器就是对node的封装.....

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

template<typename T>
class Node {//双向链表节点
    public:
        T val;//存储节点值
        Node *next;
        Node *pre;
};

template<typename T>
struct List_iterator { //简单版迭代器
    typedef Node<T>* Node;
    Node data;

    List_iterator() {
        data = 0;
    }
    List_iterator(Node other) {
        data = other;
    }
    List_iterator(const List_iterator &rhs) {
        data = rhs.data;
    }
    List_iterator& operator ++ () { //重载前置自增符号
        data = data->next;
        return *this;
    }
    T& operator * () {
        return data->val;
    }
    bool operator != (const List_iterator& rhs) {
        return (rhs.data != data);
    }
    bool operator == (const List_iterator& rhs) {
        return (rhs.data == data);
    }
};

/*
    head<->Node1<->Node2(tail)->NULL
*/

template<typename T>
class List { //双向链表
    public:
        typedef Node<T> Node;
        typedef Node* pNode;
        typedef List_iterator<T> iteratorL;
    private:
        pNode head;                    //指向头节节(头节点不放元素)
        pNode tail;                    //指向尾节点
        int _size;                     //当前链表长度
    private:
        void init();                //构造初始化函数
    public:
        List();                        //默认构造函数
        List(const List &);            //拷贝函数
        ~List();                    //析构函数
        iteratorL begin();            //获取第一个节点
        iteratorL end();            //获取最后一个节点的下一位置
        T front();                    //返回第一个节点的值
        T back();                    //返回最后一个节点的值
        int size() const;            //返回链表长度
        bool empty();                //判断链表是否为空,空则返回true
        void push_back(T val);        //插入值为val的节点到链表末尾
        void pop_back();            //删除链表末尾节点
        void push_front(T val);        //插入值为val的节点到链表头部
        void pop_front();            //删除链表头节点
        iteratorL insert(iteratorL pos,T val);//在指定位置插入值为val的节点
        void erase(iteratorL pos);    //删除指定位置的值
        //[first,last)区间中查找值为val的节点,并且返回该位置迭代器,找不到则返回 end()
        iteratorL find(const iteratorL first,const iteratorL last,const T val);
        void remove(T val);            //删除具有值为val的节点
        void sort();                //按照从小到大进行排序
        void swap(iteratorL first,iteratorL second);//交换两节点内容
        void clear();                                //清空链表内容
};

template<typename T>
void List<T>::init() {
    tail = head = new Node;
    head->next = 0;
    head->pre = 0;
    head->val = 0;
    _size = 0;
}

template<typename T>
List<T>::List() {
    init();
}

template<typename T>
List<T>::List(const List &other) {
    init();
    Node *p = other.head->next;
    while(p != 0) {
        push_back(p->val);
        p = p->next;
    }
}

template<typename T>
List<T>::~List() {
    clear();
    delete head;
}

template<typename T>
typename List<T>::iteratorL List<T>::begin() {
    return iteratorL(head->next);
}

template<typename T>
typename List<T>::iteratorL List<T>::end() {
    return iteratorL(tail->next);
}

template<typename T>
T List<T>::front() {
    if(!empty())
        return head->next->val;
}

template<typename T>
T List<T>::back() {
    return tail->val;
}

template<typename T>
int List<T>::size() const {
    return _size;
}

template<typename T>
bool List<T>::empty() {
    return (_size == 0);
}

template<typename T>
void List<T>::push_back(T val) {
    insert(end(),val);
}

template<typename T>
void List<T>::pop_back() {
    erase(iteratorL(tail));
}

template<typename T>
void List<T>::push_front(T val) {
    insert(begin(),val);
}

template<typename T>
void List<T>::pop_front() {
    erase(begin());
}

template<typename T>
typename List<T>::iteratorL
List<T>::insert(iteratorL pos,T val) {//在Pos位置插入值为Val的节点
    pNode addN = new Node;
    ++_size;
    addN->val = val;
    if(pos != end()) {
        pNode p = pos.data;
        pNode preN = p->pre;
        addN->pre = p->pre;
        addN->next = p;
        if(preN)
            preN->next = addN;
        p->pre = addN;
    } else { //插入末尾
        tail->next = addN;
        addN->pre = tail;
        addN->next = 0;
        tail = addN;
    }
    return iteratorL(addN);
}

template<typename T>
void List<T>::erase(iteratorL pos) {
    if(pos != end()) {
        pNode p = pos.data;

        pNode preN = p->pre;
        pNode nextN = p->next;
        preN->next = nextN;
        if(p == tail)//删除尾节点特判
            tail = preN;
        if(nextN != 0)
            nextN->pre = preN;
        delete p;
        --_size;
    }
}

template<typename T>
typename List<T>::iteratorL
List<T>::find(const iteratorL first,const iteratorL last,const T val) {
    iteratorL it = first;
    while(it != last) {
        if(*it == val)
            return it;
        ++it;
    }
    return end();//找不到返回 end()
}

template<typename T>
void List<T>::remove(T val) {
    iteratorL it = find(begin(),end(),val);
    if(it!=end()) {
        erase(it);
    }
}

template<typename T>
void List<T>::clear() {
    while(empty() == false) {
        pop_back();
    }
}

template<typename T>
void List<T>:: swap(iteratorL first,iteratorL second)//使用选择排序
{
    if(first == end() || second == end())//避免空指针
        return;
    T tmp = first.data->val;
    first.data->val = second.data->val;
    second.data->val = tmp;
}

template<typename T>
void List<T>:: sort()//使用选择排序
{
    if(empty() == false){
        iteratorL minI;
        for(iteratorL it = begin();it!=end();++it)
        {
            minI = it;//最小值初始化
            for(iteratorL it2 = it;it2!=end();++it2)
            {
                if(minI.data->val > it2.data->val){
                    minI = it2;
                }
            }
            swap(minI,it);//交换两迭代器所指位置的内容
        }
    }
}

//打印输出List
template<typename T>
void print(List<T> q) {
    for(List<int>::iteratorL it = q.begin(); it!=q.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
}

int main() {
    //测试 添加 删除
    List<int> q;
    q.push_back(1);
    q.push_back(2);
    q.push_back(3);
    print(q);

    q.pop_back();
    q.push_front(3);
    q.push_front(4);
    q.pop_front();
    print(q);

    q.clear();
    print(q);

    q.push_back(1);
    List<int>::iteratorL it = q.begin();
    *it = 2;
    print(q);

    q.insert(q.begin(),3);
    print(q);

    //查找元素3
    if(q.find(q.begin(),q.end(),3) != q.end()){
        printf("find 3\n");
    }

    //移除remove测试
    q.remove(3);
    if(q.find(q.begin(),q.end(),3) != q.end()){
        printf("find 3\n");
    }

    //测试从小到大排序
    q.clear();
    srand(static_cast<int>( time(0) ) );
    for(int i=0;i<20;++i){
        q.push_back(rand()%20);
    }
    print(q);
    q.sort();
    print(q);
    return 0;
}

原文地址:https://www.cnblogs.com/--zz/p/10712502.html

时间: 2024-08-28 16:43:57

C++ 简单版STL list 链表(迭代器版)的相关文章

C语言实现单链表-03版

在C语言实现单链表-02版中我们只是简单的更新一下链表的组织方式: 它没有更多的更新功能,因此我们这个版本将要完成如下功能: Problem 1,搜索相关节点: 2,前插节点: 3,后追加节点: 4,一个专门遍历数据的功能: Solution 我们的数据结构体定义如下,和上一个版本稍微有所不同: 例如,我们把人这个结构体添加一个name域,前几个版本没有名字的节点: 我们叫起来很尴尬,都是第几个第几个节点,好啦!现在有名字啦! #include <stdio.h> #include <s

C语言实现单链表-02版

我们在C语言实现单链表-01版中实现的链表非常简单: 但是它对于理解单链表是非常有帮助的,至少我就是这样认为的: 简单的不能再简单的东西没那么实用,所以我们接下来要大规模的修改啦: Problem 1,要是数据很多怎么办,100000个节点,这个main函数得写多长啊... 2,这个连接的方式也太土啦吧!万一某个节点忘记连接下一个怎么办... 3,要是我想知道这个节点到底有多长,难道每次都要从头到尾数一遍嘛... 4,要是我想在尾部添加一个节点,是不是爬也要爬到尾部去啊... 这个是简单版中提出

一步一步认识C++STL中的迭代器

一步一步认识C++STL中的迭代器 "指针"对所有C/C++的程序员来说,一点都不陌生.在接触到C语言中的malloc函数和C++中的new函数后,我们也知道这两个函数返回的都是一个指针,该指针指向我们所申请的一个"堆".提到"堆",就不得不想到"栈",从C/C++程序设计的角度思考,"堆"和"栈"最大的区别是"栈"由系统自动分配并且自动回收,而"堆&quo

STL list链表的用法详解(转)

本文以List容器为例子,介绍了STL的基本内容,从容器到迭代器,再到普通函数,而且例子丰富,通俗易懂.不失为STL的入门文章,新手不容错过! 0 前言 1 定义一个list 2 使用list的成员函数push_back和push_front插入一个元素到list中 3 list的成员函数empty() 4 用for循环来处理list中的元素 5 用STL的通用算法for_each来处理list中的元素 6 用STL的通用算法count_if()来统计list中的元素个数 7 使用count_i

XAMPP 的 Linux 版 (x86 兼容处理器版)安装配置使用详细介绍,教你建好一个LAMPP站!

XAMPP 的 Linux 版 (x86 兼容处理器版) 以前被称作 LAMPP,但为了避免误解,将其重名命为 ?XAMPP 的 Linux 版?.所以,如果您在寻找 LAMPP下载.安装.配置.使用方法,您就来对地方了. 安装过程仅 4 个步骤 步骤 1:下载 只需点击下面的链接.下载最新版总是好主意.:)完整的下载列表(老版本)可在 SourceForge 找到. 详细的 XAMPP 各版本更新记录可在 发布说明 中找到. XAMPP Linux 1.8.2 107 MB Apache 2.

解决iphone5,5s有锁版(AU,SB,S版等等)ios7越狱后+86、FT、IM等一切问题

最近无聊,给大家发一个关于完美解决iphone5,5c.5s有锁版本机号码.+86.短信.facetime.imessage等问题.是ios7系统哦!(本人亲测iphone5 SB版 双模卡解锁)相当完美!!!1.先越狱!必须的!!2.打开cydia,增加源(cydia.china3gpp.com)3.增加源后,进入,点(iphone5s/5c/5 ios7 gpp),安装.4.完工! 也许有其他方法解决此问题,比如修改系统文件覆盖此类的,看着都头疼,但这个是最简单的哦! 解决iphone5,5

Android Studio获取开发版SHA1值和发布版SHA1值,详细过程

转自原文 Android Studio获取开发版SHA1值和发布版SHA1值的史上最详细方法 前言: 今天我想把百度地图的定位集成到项目中来,想写个小小的案例,实现一下,但在集成百度地图时首先要申请秘钥,申请秘钥要用到SHA1值,所以今天就来总结一下怎样去获取这个值吧,希望对大家有帮助. 正常情况下: 一.获取开发版SHA1: 在此我直接用Android Studio提供的命令控制台了,毕竟做Android开发几乎都是用Android Studio了. 1.打开android studio 找到

跨云应用部署第一步:使用IPSEC VPN连接AWS中国版和Windows Azure中国版

随着公有云的普及,越来越多的客户将关键应用迁移到云端.但是事实证明,没有哪家云服务提供商可以提供100%的SLA,无论是例行维护还是意外中断服务,对于客户的关键应用而言,都会受到不同程度的影响.此外,不同的云服务提供商,其提供的云服务也存在较大的差异化,包括云服务和产品的功能.质量.收费模式等方面.客户选择多样化的.最适合的.性价比最高的云服务和产品来满足自己的业务需求是必然的趋势.公有云应用占比越高的客户,其跨云应用部署的需求也越大——都不想把鸡蛋放在一个篮子里,或者是被某个云服务提供商绑架.

PC网页版、移动客户端、Wap版 有什么不同

测试周期中,可能会涉及到版本说明的词汇,比如:PC版.网页版.Web客户端.PC客户端.移动端.移动客户端.Wap版.H5. 关于"PC网页版"- 因为之前,基本没有PC终端业务,所以我们在通常的沟通过程中提到的“PC版”就是指“PC网页版”(即:“电脑网页版”),或称为“Web版”. 那么,为什么通常我们不叫“Web版”呢?可能是因为“Web”和“Wap”的发音容易混淆,于是我们常常把“Web版”叫做“PC网页版”. 为了省事儿,也会把“PC网页版”称为“PC版”,把“Wap版”称为“H5”.