• 《深入实践C++模板编程》之五——容器与迭代器


    1、容器的定义
    容器:专门用于某种形式组织及存储数据的类称为“容器”。
     
    2、容器与迭代器
    迭代器:封装了对容器虚拟数据序列的操作并按约定提供统一界面以遍历容器内容的代理类即为迭代器。
     
    举例理解:
    template<typename T> class list;
    
    template<typename T>
    struct list_node
    {
        typedef T value_type;
        typedef T& reference_type;
        typedef const T const_reference_type;
    
        T value;
        list_node *prev;
        list_node *next;
    
        list_node(T const &value, list_node *prev, list_node *next) :
            value(value), prev(prev), next(next){}
    };
    
    template<typename N> 
    class list_iterator
    {
        N *pos;
        template<typename T> friend class list;
    
    public:
        typedef typename N::value_type value_type;
        typedef typename N::reference_type reference_type;
        typedef typename N::const_reference_type const_reference_type;
        typedef list_iterator<N> self_type;
    
        list_iterator() :pos(0){}
        list_iterator(N *pos) :pos(pos){}
    
        bool operator != (self_type const &right) const{
            return pos != right.pos;
        }
    
        bool operator == (self_type const &right) const{
            return pos != right.pos;
        }
    
        self_type& operator++(){
            if (pos) pos = pos->next;
            return *this;
        }
    
        reference_type operator * () throw (std::runtime_error){
            if (pos) return pos->value;
            else throw (std::runtime_error("null iterator!
    "));
        }
    };
    
    template<typename T>
    class list
    {
        typedef list_node<T> node_type;
        node_type *head;
    
    public:
        typedef T value_type;
        typedef list_iterator<node_type> iterator;
    
        list() :head(){}
        ~list(){
            while (head)
            {
                node_type *n = head;
                head = head->next;
                delete n;
            }
        }
    
        void push_front(T const &v)
        {
            head = new node_type(v, 0, head);
            if (head->next)
            {
                head->next->prev = head;
            }
        }
    
        void pop_front(T const &v)
        {
            if (head)
            {
                node_type *n = head;
                head = head->next;
                head->prev = 0;
                delete n;
            }
        }
    
        void insert(iterator it, T const &v)
        {
            node_type *n = it.pos;
            if (n)
            {
                node_type *new_node = new node_type(v, n, n->next);
                new_node->next->prev = new_node;
                n->next = new_node;
            }
        }
    
        void erase(iterator &it)
        {
            node_type *n = it.pos;
            ++it;
            if (n)
            {
                if (n->next)
                {
                    n->next->prev = n->prev;
                }
                if (n->prev)
                {
                    n->prev->next = n->next;
                }
                if (head == n)
                {
                    head = n->next;
                }
                delete n;
            }
        }
    
        bool is_empty() const { return head == 0; }
        iterator begin(){ return iterator(head); }
        iterator end(){ return iterator(); }
    };
    针对树形结构节点类型的迭代器:
    template<typename T>
    struct tree_node
    {
        typedef T value_type;
        typedef T& reference_type;
        typedef const T& const_reference_type;
    
        T value;
        tree_node *parent;
        tree_node *left;
        tree_node *right;
    
        tree_node(T const &value,
            tree_node *parent,
            tree_node *left, 
            tree_node *right):
            value(value),
                parent(parent),
                left(left),
                right(right){}
    
            ~tree_node()
            {
                if (left) delete left;
                if (right) delete right;
            }
    };
    
    template<typename N>
    class tree_iterator
    {
        const N *pos;
    public:
        typedef typename N::value_type value_type;
        typedef typename N::const_reference_type const_reference_type;
        typedef tree_iterator<N> self_type;
    
        tree_iterator() :pos(0){}
        tree_iterator(const N *pos) :pos(pos){}
    
        bool operator == (self_type const &right) const{
            return pos == right.pos;
        }
    
        self_type& operator ++ (){
            if (pos){
                if (pos->right){
                    pos = pos->right;
                    while (pos->left)
                    {
                        pos = pos->left;
                    }
                }
                else
                {
                    while (pos->parent && (pos->parent->right == pos))
                    {
                        pos = pos->parent;
                    }
                    pos = pos->parent;
                }
            }
            return *this;
        }
    
        const_reference_type operator * () const throw(std::runtime_error)
        {
            if (pos)
            {
                return pos->value;
            }
            else
            {
                throw std::runtime_error("Null iterator!
    ");
            }
        }
    };
    
    template<typename T>
    class set
    {
        typedef tree_node<T> node_type;
        node_type *root;
    public:
        typedef T value_type;
        typedef tree_iterator<node_type> const_iterator;
    
        set() :root(){}
        ~set(){ if (root) delete root; }
    
        bool insert(T const &v)
        {
            node_type **n = &root;
            node_type *p = 0;
            while (*n)
            {
                if (v == (*n)->value)
                {
                    return false;
                }
                else
                {
                    p = *n;
                    n = v < (*n)->value ? &((*n)->left) : &((*n)->right);
                }
            }
            *n = new node_type(v, p, 0, 0);
            return true;
        }
    
        bool has(T const &v)
        {
            node_type *n = root;
            while (n)
            {
                if (v == n->value)
                    return true;
                n = v < n->value ? n->left : n->right;
            }
            return false;
        }
    
        bool is_empty() const { return root == 0; }
    
        const_iterator begin() const{
            node_type *n = root;
            while (n->left) n = n->left;
            return const_iterator(n);
        }
    
        const_iterator end() const { return const_iterator(); }
    };
    尽管容器内部的数据结构类型不同(set是一个树形结构,而list是链表结构),但是提供给用户的操作界面iterator的所有操作都是相同的,所以底层数据结构对用户来说是透明的。
    这也算是一种设计思路。
     
    3、迭代器和算法
    利用迭代器求和:
    template<typename C>
    typename C::value_type
    sum(C &c)
    {
        typedef typename C::value_type value_type;
        typedef typename C::iterator iterator;
        value_type sum(0);
    
        for (iterator i = c.begin(); i != c.end(); ++i)
        {
            sum += *i;
        }
        return sum;
    }
    不足1:只能求所有元素之和,不能求部分元素之和。可以将一个迭代器改为两个迭代器来弥补这里的不足。
    template<typename I>
    typename I::value_type
    sum(I begin, I end)
    {
        typedef typename I::value_type value_type;
    
        value_type sum(0);
        for (; begin != end; ++begin)
        {
            sum += *begin;
        }
        return sum;
    }
    不足2:要兼容最原始的容器——数组。
    这里的I都是某种类型的迭代器,你可以通过I::value_type获取迭代器所指的对象的类型。但是数组的指针是一个普通的指针,是没有value_type成员的。借助另外一个类模板及模板特例功能来统一描述迭代器指针的特性。
     
    再进行一层封装,使得普通的指针也有了value_type:
    template<typename I>
    struct iterator_traits
    {
        typedef typename I::value_type value_type;
    };
    
    template<typename P>
    struct iterator_traits<P*>
    {
        typedef P value_type;
    };
    改进后:
    template<typename I>
    typename iterator_traits<I>::value_type
    sum(I begin, I end)
    {
        typedef typename iterator_traits<I>::value_type value_type;
    
        value_type sum(0);
        for (; begin != end; ++begin)
        {
            sum += *begin;
        }
        return sum;
    }
    4、迭代器的陷阱
    a、容器中通常有迭代器为参数对指定位置进行操作的成员函数,调用此类函数有个隐含要求,即迭代器所指数据来自该容器,否则后果无法预测。
    b、由于迭代器独立于容器之外,用户可以一次性生成多个迭代器对容器内数据进行操作。这样就会产生冲突。
  • 相关阅读:
    MySQL基础之第9章 触发器
    Windows系统安装————windows7 企业版 无法安装 NET.framework4.52-4.6版本在WIN7下解决办法
    流媒体技术学习笔记之(十二)Linux(Ubuntu)环境运行EasyDarwin
    流媒体服务器之————EasyDarwin开源流媒体服务器:编译、配置、部署
    流媒体技术学习笔记之(十一)Windows环境运行EasyDarwin
    流媒体技术学习笔记之(十)HLS协议直播延时优化(35s到10S)
    流媒体技术学习笔记之(九)减少VLC 延迟的方法
    流媒体技术学习笔记之(八)海康、大华IpCamera RTSP地址和格式
    流媒体技术学习笔记之(七)进阶教程OBS参数与清晰度流畅度的关系
    Phalcon框架之———— 2.0升级到3.0 问题Model验证问题解决
  • 原文地址:https://www.cnblogs.com/predator-wang/p/11509831.html
Copyright © 2020-2023  润新知