• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

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

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
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!\n"));
    }
};

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!\n");
        }
    }
};

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、由于迭代器独立于容器之外,用户可以一次性生成多个迭代器对容器内数据进行操作。这样就会产生冲突。

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
c# 事件需要注意的问题发布时间:2022-07-13
下一篇:
c#Md532位加密结果少了两个0的原因发布时间:2022-07-13
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap