zoukankan      html  css  js  c++  java
  • 《深入实践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、由于迭代器独立于容器之外,用户可以一次性生成多个迭代器对容器内数据进行操作。这样就会产生冲突。
  • 相关阅读:
    如何开始学习编程? 这 3 步很重要
    php正则表达式验证手机/固定电话/邮箱/身份证/银行卡自定义函数
    【经验分享】-PHP程序员的技能图谱
    PHP程序员的技能图谱
    PHP程序员要掌握的技能
    冒泡排序
    文件下载方法
    加密,解密方法
    获取真实IP
    二维数组根据某个字段排序
  • 原文地址:https://www.cnblogs.com/predator-wang/p/11509831.html
Copyright © 2011-2022 走看看