C/C++必须了解的小知识(32)

105 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

1.4.12 说说 vector 和 list 的区别,分别适用于什么场景?

参考回答

​ vector和list区别在于底层实现机理不同,因而特性和适用场景也有所不同。

​ vector:一维数组

​ 特点:元素在内存连续存放,动态数组,在堆中分配内存,元素连续存放,有保留内存,如果减少大小后内存也不会释放。

​ 优点:和数组类似开辟一段连续的空间,并且支持随机访问,所以它的查找效率高其时间复杂度O(1)。

​ 缺点:由于开辟一段连续的空间,所以插入删除会需要对数据进行移动比较麻烦,时间复杂度O(n),另外当空间不足时还需要进行扩容。

​ list:双向链表

​ 特点:元素在堆中存放,每个元素都是存放在一块内存中,它的内存空间可以是不连续的,通过指针来进行数据的访问。

​ 优点:底层实现是循环双链表,当对大量数据进行插入删除时,其时间复杂度O(1)。

​ 缺点:底层没有连续的空间,只能通过指针来访问,所以查找数据需要遍历其时间复杂度O(n),没有提供[]操作符的重载。

应用场景

​ vector拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随即访问,而不在乎插入和删除的效率,使用vector。

​ list拥有一段不连续的内存空间,如果需要高效的插入和删除,而不关心随机访问,则应使用list。

1.4.13 简述 vector 的实现原理

参考回答

​ vector底层实现原理为一维数组(元素在空间连续存放)。

  1. 新增元素

    ​ Vector通过一个连续的数组存放元素,如果集合已满,在新增数据的时候,就要分配一块更大的内存,将原来的数据复制过来,释放之前的内存,在插入新增的元素。插入新的数据分在最后插入push_back和通过迭代器在任何位置插入,这里说一下通过迭代器插入,通过迭代器与第一个元素的距离知道要插入的位置,即int index=iter-begin()。这个元素后面的所有元素都向后移动一个位置,在空出来的位置上存入新增的元素。

    //新增元素 
    void insert(const_iterator iter,const T& t )
        {  
            int index=iter-begin();
            if (index<size_)
           {
               if (size_==capacity_)
               {
                    int capa=calculateCapacity();
                  newCapacity(capa);
               }
               memmove(buf+index+1,buf+index,(size_-index)*sizeof(T)); 
               buf[index]=t;
               size_++;
           } 
       }
    
  2. 删除元素

    ​ 删除和新增差不多,也分两种,删除最后一个元素pop_back和通过迭代器删除任意一个元素erase(iter)。通过迭代器删除还是先找到要删除元素的位置,即int index=iter-begin();这个位置后面的每个元素都想前移动一个元素的位置。同时我们知道erase不释放内存只初始化成默认值。

    ​ 删除全部元素clear:只是循环调用了erase,所以删除全部元素的时候,不释放内存。内存是在析构函数中释放的。

    //删除元素 
    iterator erase(const_iterator iter)
            {
                int index=iter-begin(); 
                if (index<size_ && size_>0)
                {
                    memmove(buf+index ,buf+index+1,(size_-index)*sizeof(T)); 
                    buf[--size_]=T();
                } 
                return iterator(iter); 
            }
    
  3. 迭代器iteraotr

    迭代器iteraotr是STL的一个重要组成部分,通过iterator可以很方便的存储集合中的元素.STL为每个集合都写了一个迭代器, 迭代器其实是对一个指针的包装,实现一些常用的方法,如++,--,!=,==,*,->等, 通过这些方法可以找到当前元素或是别的元素. vector是STL集合中比较特殊的一个,因为vector中的每个元素都是连续的,所以在自己实现vector的时候可以用指针代替。

    //迭代器的实现
    template<class _Category,
        class _Ty,
        class _Diff = ptrdiff_t,
        class _Pointer = _Ty *,
        class _Reference = _Ty&>
        struct iterator
        {    // base type for all iterator classes
               typedef _Category iterator_category;
               typedef _Ty value_type;
               typedef _Diff difference_type;
               typedef _Diff distance_type;    // retained
               typedef _Pointer pointer;
               typedef _Reference reference;
        };
    
  4. vector实现源码

    #ifndef _CVECTOR_H_
    #define _CVECTOR_H_
    
    namespace cth
    {
        class NoCopy
        {
        public: 
            inline NoCopy(){}
            NoCopy(const NoCopy&);
            NoCopy& operator=(const NoCopy&); 
        };
    
        template<typename T>
        class viterator:public std::iterator<std::forward_iterator_tag,T>
        {
        public: 
            viterator()
            {
                t=NULL;
            }
            viterator(T* t_)
            {
                t=t_;
            }
            viterator(const viterator& other)
            {
                t=other.t;
            }
            viterator& operator=(const viterator& other)
            {
                t=other.t;
                return *this;
            }
    
            viterator& operator++()
            {
                t++;
                return *this;
            } 
            viterator operator++(int)
            {
                viterator iter=*this;
                t++;
                return iter;
            } 
            viterator operator+(int count)
            {
                viterator iter=*this;
                iter.t+=count;
                return iter;
            } 
            viterator& operator--()
            {
                t--;
                return *this;
            } 
            viterator operator--(int)
            {
                viterator iter=*this;
                t--;
                return iter;
            } 
            viterator operator-(int count)
            {
                viterator iter=*this;
                iter.t-=count;
                return iter;
            }
    
            int operator-(const viterator& other)
            { 
                return t-other.t;
            } 
            int operator-(const viterator& other)const
            { 
                return t-other.t;
            }
    
            T& operator*()
            {
                return *t;
            } 
            const T& operator*() const
            {
                return *t;
            }
    
            T* operator->()
            {
                return t;
            }
            const T* operator->() const
            {
                return t;
            }
    
            inline bool operator!=(const viterator& other)
            {
                return t!=other.t;
            }
            inline bool operator!=(const viterator& other)const
            {
                return t!=other.t;
            }
    
            inline bool operator==(const viterator& other)
            {
                return t==other.t;
            }
            inline bool operator==(const viterator& other)const
            {
                return t==other.t;
            }
    
            inline bool operator<(const viterator& other)
            {
                return t<other.t;
            }
            inline bool operator<(const viterator& other)const
            {
                return t<other.t;
            }
    
            inline bool operator<=(const viterator& other)
            {
                return t<=other.t;
            }
            inline bool operator<=(const viterator& other)const
            {
                return t<=other.t;
            }
    
            inline bool operator>(const viterator& other)
            {
                return t>other.t;
            }
            inline bool operator>(const viterator& other)const
            {
                return t>other.t;
            }
    
            inline bool operator>=(const viterator& other)
            {
                return t>=other.t;
            } 
            inline bool operator>=(const viterator& other)const
            {
                return t>=other.t;
            } 
        private: 
            T* t;
        };
    
   template<typename T>
   class cvector:public NoCopy
   {
   public: 
       typedef viterator<T> iterator;//viterator<T>就是对一个指针的包装,所以完全可以用T*代替viterator <T>
       typedef const viterator<T> const_iterator;

       //typedef T* iterator;
       //typedef const T* const_iterator;
       cvector()
       {
           initData(0);
       } 
       cvector(int capa,const T& val=T())
       { 
           initData(capa);
           newCapacity(capacity_);
           for (int i=0;i<size_;i++) 
               buf[i]=val; 
       } 
       cvector(const_iterator first,const_iterator last)
       {  
           initData(last-first);
           newCapacity(capacity_);
           iterator iter=iterator(first); 
           int index=0;
           while(iter!=last)
               buf[index++]=*iter++;
       }

       ~cvector()
       {
           if (buf)
           {
               delete[] buf;
               buf=NULL;
           }
           size_=capacity_=0;
       }
       void clear()
       {
           if (buf)
               erase(begin(),end());
       }

       void push_back(const T& t)
       {
           if (size_==capacity_)
           {
               int capa=calculateCapacity();
               newCapacity(capa);
           }
           buf[size_++]=t;
       }
       void pop_back()
       { 
           if (!empty())
               erase(end() - 1); 
       }

       int insert(const_iterator iter,const T& t )
       {  
           int index=iter-begin();
           if (index<=size_)
           {
               if (size_==capacity_)
               {
                   int capa=calculateCapacity();
                   newCapacity(capa);
               }
               memmove(buf+index+1,buf+index,(size_-index)*sizeof(T)); 
               buf[index]=t;
               size_++;
           } 
           return index;
       }
       iterator erase(const_iterator iter)
       {
           int index=iter-begin(); 
           if (index<size_ && size_>0)
           {
               memmove(buf+index ,buf+index+1,(size_-index)*sizeof(T)); 
               buf[--size_]=T();
           } 
           return iterator(iter); 
       }

       iterator erase(const_iterator first,const_iterator last)
       { 
           iterator first_=iterator(first);
           iterator last_=iterator(last); 
           while(first_<=last_--) 
               erase(first_);  
           return iterator(first_);
       }

       T& front()
       { 
           assert(size_>0);
           return buf[0];
       }
       T& back()
       { 
           assert(size_>0);
           return buf[size_-1];
       }
       T& at(int index)
       { 
           assert(size_>0);
           return buf[index];
       }
       T& operator[](int index)
       { 
           assert(size_>0 && index>=0 && index<size_);
           return buf[index];
       }

       bool empty() const
       {
           return size_==0; 
       }
       int size() const
       {
           return size_;
       }
       int capacity() const
       {
           return capacity_;
       }

       iterator begin()
       {  
           return iterator(&buf[0]); 
       } 
       iterator end()
       {  
           return iterator(&buf[size_]); 
       }

   private: 
       void newCapacity(int capa)
       { 
           capacity_=capa;
           T* newBuf=new T[capacity_];
           if (buf)
           {
               memcpy(newBuf,buf,size_*sizeof(T)); 
               delete [] buf;
           } 
           buf=newBuf;
       }

       inline int calculateCapacity()
       {
           return capacity_*3/2+1 ;
       }

       inline void initData(int capa)
       {
           buf=NULL;
           size_=capacity_=capa>0?capa:0;
       }
       int size_; 
       int capacity_ ;
       T* buf; 
   };



   struct Point
   {
       Point(int x_=0,int y_=0):x(x_),y(y_){}
       int x,y;
   };

   bool operator<(const Point& p1,const Point& p2)
   {
       if(p1.x<p2.x)
       {
           return true;
       }else if(p1.x>p2.x)
       {
           return false;
       }
       return p1.y<p2.y;
   }

   void cvectorTest()
   {
       cvector<Point> vect;
       for (int i=0;i<10;i++)
       {
           Point p(i,i); 
           vect.push_back(p);
       }

       cvector<Point>::iterator iter=vect.begin(); 
       while (iter!=vect.end())
       {
           cout<< "[" << iter->x << " " << iter->y <<"], ";
           ++iter;
       }
       iter=vect.begin()+5; 
       vect.insert(iter,Point(55,55)); 
       iter=vect.end()-3; 
       vect.insert(iter,Point(77,77));
       cout<<endl<<endl<<"插入两个元素后:"<<endl;
       iter=vect.begin(); 
       while (iter!=vect.end())
       {
           cout<< "[" << iter->x << " " << iter->y <<"], ";
           ++iter;
       }
       std::sort(vect.begin(),vect.end());
       cout<<endl<<endl<<"排序后:"<<endl;
       iter=vect.begin(); 
       while (iter!=vect.end())
       {
           cout<< "[" << iter->x << " " << iter->y <<"], ";
           ++iter;
       }
       vect.erase(vect.begin()+10);
       vect.erase(vect.begin()+10);
       cout<<endl<<endl<<"删除之前新增的两个元素"<<endl;
       iter=vect.begin(); 
       while (iter!=vect.end())
       {
           cout<< "[" << iter->x << " " << iter->y <<"], ";
           ++iter;
       }
       vect.clear();
       cout<<endl<<endl<<"执行clear之后"<<endl;
       cout<<"size="<<vect.size()<<",capacity="<<vect.capacity();

       cvector<Point> vect1;
       for (int i=10;i<20;i++)
       {
           Point p(i,i); 
           vect1.push_back(p);
       }
       cout<<endl<<endl<<"从别的cvector复制数据:"<<endl;

       cvector<Point> vect2(vect1.begin(),vect1.end());
       vect2.pop_back();
       vect2.pop_back();
       for(int i=0;i<vect2.size();i++)
       {
           cout<<"["<<vect2[i].x<<","<<vect2[i].y<<"], ";
       }

       cout<<endl; 
   }

}

   ```c++
   //实例代码级运行结果
   struct Point
       {
           Point(int x_=0,int y_=0):x(x_),y(y_){}
           int x,y;
       };

       bool operator<(const Point& p1,const Point& p2)
       {
           if(p1.x<p2.x)
           {
               return true;
           }else if(p1.x>p2.x)
           {
               return false;
           }
           return p1.y<p2.y;
       }

       void cvectorTest()
       {
           cvector<Point> vect;
           for (int i=0;i<10;i++)
           {
               Point p(i,i); 
               vect.push_back(p);
           }

           cvector<Point>::iterator iter=vect.begin(); 
           while (iter!=vect.end())
           {
               cout<< "[" << iter->x << " " << iter->y <<"], ";
               ++iter;
           }
           iter=vect.begin()+5; 
           vect.insert(iter,Point(55,55)); 
           iter=vect.end()-3; 
           vect.insert(iter,Point(77,77));
           cout<<endl<<endl<<"插入两个元素后:"<<endl;
           iter=vect.begin(); 
           while (iter!=vect.end())
           {
               cout<< "[" << iter->x << " " << iter->y <<"], ";
               ++iter;
           }
           std::sort(vect.begin(),vect.end());
           cout<<endl<<endl<<"排序后:"<<endl;
           iter=vect.begin(); 
           while (iter!=vect.end())
           {
               cout<< "[" << iter->x << " " << iter->y <<"], ";
               ++iter;
           }
           vect.erase(vect.begin()+10);
           vect.erase(vect.begin()+10);
           cout<<endl<<endl<<"删除之前新增的两个元素"<<endl;
           iter=vect.begin(); 
           while (iter!=vect.end())
           {
               cout<< "[" << iter->x << " " << iter->y <<"], ";
               ++iter;
           }
           vect.clear();
           cout<<endl<<endl<<"执行clear之后"<<endl;
           cout<<"size="<<vect.size()<<",capacity="<<vect.capacity();

           cvector<Point> vect1;
           for (int i=10;i<20;i++)
           {
               Point p(i,i); 
               vect1.push_back(p);
           }
           cout<<endl<<endl<<"从别的cvector复制数据:"<<endl;

           cvector<Point> vect2(vect1.begin(),vect1.end());
           vect2.pop_back();
           vect2.pop_back();
           for(int i=0;i<vect2.size();i++)
           {
               cout<<"["<<vect2[i].x<<","<<vect2[i].y<<"], ";
           }

           cout<<endl; 
       }