C/C++容器和迭代器理解

为什么要有容器?

   我知道有数组,但数组有一个弊端,它是固定的,不可变。这个经常会导致出现数组越界导常的错误。并且还需要事先知道这个数组的长度才可以定义。 但很多时候,我们并不知道未来将会发生什么,所以我们创造了容器,它是不固定的,可变的,可以根据元素的增加而增加,每次增加原数组的1.5倍。为什么是1.5倍呢,因为2倍太大了,1倍太小,所以为了保证效率,择中选1.5倍。

数组与容器的区别?
数组能存基础数据类型,也可以存引用数据类型;容器只能存引用数据类型 数组的长度是固定的,容器的长度可以根据元素的增加而增加

为什么会有迭代器?
数组有的功能,容器大部分都会有。数组存放数据可能是有序的,也可能是无序的。所以容器也具备同样的功能,容器英文:Collection,有序的表示为List,即链表结构,无序的表示为Set,即想在哪建立就在哪建立。问题来了,有序的List,我们可以通过索引来遍历数组。但无序的Set怎么办?
用一句话总结:Iterator类的访问方式就是把不同集合类的访问逻辑抽象出来,使得不用暴露集合内部的结构而达到循环遍历集合的效果。
(附上C++容器和迭代器 ppt

在学习c++ STL的时候,整天碰到迭代器,也整天用,但是,到底它是个什么东西,很多人没有一个认识。这里我通过几个小的DEMO,来看看迭代器。首先我实现了一个十分简陋的vector类:
template <class T>  
    class vector {  
    private:  
        T* pbegin;  
        int n; //当前大小  
    public:  
        vector() {  
            pbegin = new T[100]; //暂时先固定大小  
            n = 0;  
        }  
          
        T* begin() {  
            return pbegin;  
        }  
        void insert(T d){  
            pbegin[n++] = d;  
        }  
        typedef T* iterator; //vector的迭代器就是基础指针类型  
    };  

我们知道,vector是数组实现的,也就是说,只要知道数组的首地址,就能知道后面每个元素的位置,所以,访问vector的迭代器,其实就是一个基础的指针类型,我们可以通过++,--等操作,来遍历访问该vector。
//测试vector  
        vector<int> a;  
        a.insert(1);  
        a.insert(2);  
        vector<int>::iterator itra;  
        itra = a.begin();  
        printf("%d/n", *itra);   
        itra++;  
        printf("%d/n", *itra);  
        itra--; //基础指针类型都支持++,--,+,-等操作符  
        printf("%d/n", *itra);  

哇~~,原来vector的迭代器那么简单,那么,我们来考虑一下List,这是链表,我们知道,链表每个元素都存储在不同的位置,我们一般通过指向下一个元素的next指针来找到下一个元素。那么,我们怎么样来设计一个迭代器,然后可以直接对这个迭代器进行++,--等操作二遍历访问整个链表呢:
template <class T>  
    class List{  
    private:  
        struct Node{ //链表的节点  
            T data;  
            Node* next;  
        };  
        Node* pbegin; //表头  
        class List_iterator{ //链表的迭代器  
            Node* cur; //当前指向  
        public:  
            void operator = (Node* ptr) {  
                cur = ptr;  
            }  
            void operator ++ () {  
                cur = cur->next;  
            }  
            // ...还可以重载-- + -等操作符  
            T operator * (){  
                return cur->data;  
            }  
        };  
    public :  
        List() {  
            pbegin=NULL;  
        }  
        Node* begin() {  
            return pbegin;  
        }  
        void insert(T d) {  
            Node* p=pbegin;  
            while(p && p->next) p=p->next;  
            Node* t = new Node;  
            t->data = d;  
            t->next = NULL;  
            if(pbegin==NULL)  
                pbegin = t;  
            else  
                p->next = t;  
        }  
        typedef List_iterator iterator; //List的迭代器是一个类  
    };  

为List设计的迭代器是一个类,这个类支持++操作来向后移动遍历链表:
//测试List  
        List<int> b;  
        b.insert(1);  
        b.insert(2);  
        List<int>::iterator itrb;  
        itrb = b.begin();  
        printf("%d/n", *itrb);  
        itrb++; // 该迭代器只支持++  
        printf("%d/n", *itrb);  

通过这两个例子,可以看出,迭代器是跟容器紧密结合的,不同的容器,它的迭代器不同,但是,他们有共同的目标,就是可以通过该迭代器,来遍历访问这个容器里面的元素。这样带来的好处是在STL设计算法时,可以脱离容器而设计更加通用的算法。比如,在容器中查找一个元素。查找,这个操作一般来说就是遍历整个集合,然后找到那个要找的元素,但是,如果没有迭代器,我们需要为vector和List设计两个查找算法,因为找下一个元素在vector和List中的操作不同。同样的思想却要两套代码,显然这是不优秀的。

      有了模板,我们可以将算法和特定的数据分离开来,而有了迭代器,我们可以将算法和特定的容器分离开来。

  • 10
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Casionx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值