5 线性表的顺序存储结构:顺序表

1 线性表(List)

  • 线性表(List)是具有相同类型的 n(n ≥ 0)个数据元素的有限序列

  • 线性表的表现形式

    • 0 个或多个数据元素组成的集合
    • 数据元素在位置上是有序排列的
    • 数据元素的个数是有限的
    • 数据元素的类型必须相同
  • 线性表的常用操作

    • 将元素插入线性表
    • 将元素从线性表中删除
    • 获取目标位置处元素的值
    • 设置目标位置处元素的值
    • 获取线性表的长度
    • 清空线性表

2 线性表抽象类:List

  • 线性表在 C++ 中表现为一个抽象类,用来被继承

  • List 抽象类实现

    //List.h
    template <typename T>
    class List : public Object
    {
    public:
        virtual bool insert(int i,const T& e) = 0;
        virtual bool remove(int i) = 0;
        virtual bool set(int i,const T& e) = 0;
        virtual bool get(int i,T& e) const = 0;
        virtual int length() const = 0;
        virtual void clear() = 0;
    };
    

3 线性表的顺序存储结构:SeqList

  • 线性表的顺序存储结构(SeqList,指的是用一段地址连续的存储单元依次存储线性表中的数据元素

  • SeqList 是一个抽象类

  • 设计思路:用一维数组实现顺序存储结构

    • 存储空间:T* m_array;
    • 当前长度:int m_length;
    template <typename T>
    class SeqList : public List<T>
    {
    protected:
        T* m_array;
        int m_length;
        //////
    };
    
  • 顺序存储结构的元素获取操作

    • 判断目标位置是否合法
    • 将目标位置作为数组下标获取元素
    bool SeqList<T>::get(int i,T& e) const
    {
        bool ret = ((0 <= i) && (i < m_length));
        
        if(ret)
        {
            e = m_array[i];
        }
        
        return ret;
    }
    
  • 顺序存储结构的元素插入操作

    • 判断目标位置是否合法
    • 将目标位置之后的与所有元素后移一个位置
    • 将新元素插入目标位置
    • 线性表长度加 1
    bool SeqList<T>::inert(int i,const T& e)
    {
        //i可以是最后一个元素的下一个位置:i <= m_length
        bool ret = ((0 <= i) && (i <= m_length));
        
        ret = ret && ((m_length + 1) <= capacity());
        
        if(ret)
        {
            //将要移动的元素从后往前依次往后移动一个位置
            for(int p = m_length - 1; p >= i; p--)
            {
                m_array[p+1] = m_array[p];
            }
            m_array[i] = e;
            m_length++;
        }
        
        return ret;
    }
    
  • 顺序存储结构的元素删除操作

    • 判断目标位置是否合法
    • 将目标位置后的所有元素前移一个位置
    • 线性表长度减 1
    bool SeqList<T>::remove(int i)
    {
        bool ret = ((0 <= i) && (i < m_length));
        
        if(ret){
            //将要移动的元素从前往后依次往前移动一个位置
            for(int p = i; p < m_length - 1; p++){
                m_array[p] = m_array[p+1];
            }
            m_length--;
        }
        
        return ret;
    }
    

4 顺序存储结构(SeqList)的抽象实现

  • 顺序存储结构线性表的抽象实现:实现 SeqList 抽象类

  • SeqList 类设计要点

    • 抽象类模板,存储空间的位置和大小由子类(StaticListDynamicList)完成,不能生成具体的对象
    • 实现顺序存储结构线性表的关键操作(增,删,查等)
    • 提供数组操作符,方便快速获取元素
  • SeqList.h

    #include "Exception.h"
    
    namespace DTLib
    {
    
    template <typename T>
    class SeqList : public List<T>
    {
    protected:
        T* m_array;  //顺序存储空间
        int m_length;  //当前线性表长度
    public:
        bool insert(int i,const T& e){
            bool ret = ((0 <= i) && (i <= m_length));
            //这一步的判断很必要
            ret = ret && ((m_length + 1) <= capacity());
    
            if(ret)
            {
                for(int p = m_length - 1; p >= i; p--)
                {
                    m_array[p+1] = m_array[p];
                }
                m_array[i] = e;
                m_length++;
            }
    
            return ret;
        }
    
        bool remove(int i)
        {
            bool ret = ((0 <= i) && (i < m_length));
    
            if(ret)
            {
                for(int p = i; p < m_length - 1; p++)
                {
                    m_array[p] = m_array[p+1];
                }
                m_length--;
            }
    
            return ret;
        }
    
        bool set(int i,const T& e)
        {
            bool ret = ((0 <= i) && (i < m_length));
    
            if(ret)
            {
                m_array[i] = e;
            }
    
            return ret;
        }
    
        bool get(int i,T& e) const
        {
            bool ret = ((0 <= i) && (i < m_length));
            if(ret)
            {
                e = m_array[i];
            }
            return ret;
        }
    
        int length() const
        {
            return m_length;
        }
    
        void clear()
        {
            m_length = 0;
        }
    
        //顺序存储线性表的数组访问方式
        //非const对象
        T& operator[] (int i)
        {
            if((0 <= i) && (i < m_length))
            {
                return m_array[i];
            }
            //抛出越界异常
            else
            {
               THROW_EXCEPTION(IndexOutOfBoundsException,"Parameter i is invalid ...");
            }
        }
    
        //const对象:const对象只能调用const成员函数
        T operator[] (int i) const
        {
            return (const_cast<SeqList<T>&>(*this))[i];
        }
    
        //顺序存储空间的容量
        virtual int capacity() const = 0;  //在子类中完成
    };
    
    }
    
  • 使用

    #include "SeqList.h"
    
    using namespace std;
    
    int main()
    {
        //SeqList<int> l;  //error: cannot declare variable 'l' to be of abstract type 'DTLib::SeqList<int>'
        SeqList<int>* l;  //可以声明一个指针
        return 0;
    }
    

5 StaticList 类和 DynamicList 类

5.1 实现 Staticlist 类

  • Staticlist 类设计要点

    • 类模板
    • 使用原生数组作为顺序存储空间
  • 使用模板参数决定数组大小

  • StaticList.h

    #include "SeqList.h"
    namespace DTLib
    {
    
    //模板参数T,N:T决定线性表元素类型,N决定线性表长度
    template <typename T,int N>
    class StaticList : public SeqList<T>
    {
    protected:
        T m_space[N];  //顺序存储空间,N为模板参数
    public:
        //构造函数:指定父类成员的具体值
        StaticList(){
            this->m_array = m_space;
            this->m_length = 0;
        }
    
        int capacity() const{
            return N;
        }
    };
    
    }
    
  • 使用

    int main()
    {
        StaticList<int,5> l;
    
        for(int i = 0; i < l.capacity(); i++){
            //每次都往线性表的头部插入
            l.insert(0,i);
        }
    
        for(int i = 0; i < l.length(); i++){
            cout << l[i] << endl;
        }
    
        l[0] *= l[0];
    
        for(int i = 0; i < l.length(); i++){
            cout << l[i] << endl;
        }
    
        try
        {
            l[5] = 5;
        }
        catch(Exception& e)
        {
            cout << e.message() << endl;
            cout << e.location() << endl;
        }
        return 0;
    }
    
    //输出结果
    4
    3
    2
    1
    0
        
    16
    3
    2
    1
    0
        
    Parameter i is invalid ...
    ..\DTLib\SeqList.h:78
    

5.2 实现 DynamicList 类

  • DynamicList 类设计要点

    • 类模板
    • 申请连续堆空间作为顺序存储空间
    • 动态设置顺序存储空间的大小
    • 保证重置顺序存储空间时的异常安全性
  • 函数异常安全的概念

    • 不泄露任何资源
    • 不允许破坏数据
  • 函数异常安全的基本保证

    • 如果异常被抛出
      • 对象内的任何成员仍然能保持有效状态
      • 没有数据的破坏及资源泄露
  • DynamicList.h

    #include "SeqList.h"
    namespace DTLib
    {
    
    template <typename T>
    class DynamicList : public SeqList<T>
    {
    protected:
        int m_capcaity;  //记录顺序存储空间的大小,通过构造函数的参数来指定
    public:
        //构造函数:动态申请堆内存空间
        DynamicList(int capacity)
        {
            this->m_array = new T[capacity];
            if(this->m_array != NULL)
            {
                this->m_length = 0;
                this->m_capcaity = capacity;
            }
            else
            {
                THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create DynamicList object ...");
            }
        }
    
        int capacity() const
        {
            return m_capcaity;
        }
    
        //重新设置顺序存储空间的大小:需要考虑异常安全
        void resize(int capacity)
        {
            if(capacity != m_capcaity)
            {
                //为什么不直接操作成员变量指针m_array:防止下面的复制操作出现问题
                T* array = new T[capacity];  // 新申请的堆空间
                if(array != NULL)
                {
                    int length = this->m_length < capacity ? this->m_length : capacity;  // 判断需要复制的数据元素个数
                    //进行复制数据元素操作
                    for(int i=0;i<length;i++)
                    {
                        array[i] = this->m_array[i];
                    }
                    
                    T* temp = this->m_array;  // 利用temp指向重置前的存储空间
    
                    this->m_array = array;
                    this->m_length = length;
                    this->m_capcaity = capacity;
                    
                    delete[] temp;  // 此处才释放重置前的存储空间,防止之前释放发生异常抛出
    
                }
                else
                {
                    THROW_EXCEPTION(NoEnoughMemoryException,"No memory to resize DynamicList object ...");
                }
            }
        }
    
        //析构函数:归还空间
        ~DynamicList()
        {
            delete[] this->m_array;
        }
    };
        
    }
    
  • 使用

    int main()
    {
        DynamicList<int> l(5);
    
        for(int i = 0; i < l.capacity(); i++){
                l.insert(0,i);
            }
    
        for(int i = 0; i < l.length(); i++){
            cout << l[i] << endl;
        }
    
        l[0] *= l[0];
    
        for(int i = 0; i < l.length(); i++){
            cout << l[i] << endl;
        }
    
        try{
            l[5] = 5;
        }
        catch(Exception& e){
            cout << e.message() << endl;
            cout << e.location() << endl;
    
            l.resize(10);
    
            l.insert(5,50);
        }
    
        l[5] = 5;
    
        for(int i = 0; i < l.length(); i++){
            cout << l[i] << endl;
        }
    
        l.resize(3);
    
        for(int i = 0; i < l.length(); i++){
            cout << l[i] << endl;
        }
    
        return 0;
    }
    
    //输出
    
    

6 顺序存储线性表的分析

6.1 时间分析

  • SeqList.h 效率分析

    template <typename T>
    class SeqList: public List<T>
    {
    public:
        bool insert(int i,const T& e);  //O(n)
        bool remove(int i);  //O(n)
        bool set(int i,const T& e);  //O(1)
        bool get(int i,T& e) const;  //O(1)
        int length() const;  //O(1)
        void clear();  //O(1)
        
        T& operator[] (int i);  //O(1)
        T operator[] (int i) const;  //O(1)
        
        virtual int capacity() const = 0;
    }
    
  • 问题:长度相同的两个 SeqList插入删除操作的平均耗时是否相同?

    • 不一定相同,需要看存储的对象的类型。
    • 如都含有 5 个元素的线性表 SeqList<int> s1;SeqList<string> s2;
    • 在插入和删除操作中,for 循环的赋值操作,整型的赋值操作比字符串的赋值操作(strcpy 是一个字符一个字符赋值的)耗时要小得多

6.2 功能分析

  • 代码分析1

    • Demo

      StaticList<int*,5> s1;
      StaticList<int*,5> s2;
      
      for(int i = 0; i < s1.capacity(); ++i){
          s1.insert(0,new int(i));
      }
      
      //赋值操作
      s2 = s1;
      
      for(int i = 0; i < s1.length(); ++i){
          delete s1[i];
          delete s2[i];
      }
      
    • 分析:对于赋值操作 s2 = s1; ,会发生情况:使得链表 s1s2 中的相对应的 5 个元素都指向同一块内存。那么在下一个 for 循环中,每一个内存空间都会被释放两次

  • 代码分析2

    • Demo

      void func()
      {
          DynamicList<int> d1(5);
          //拷贝构造
          DynamicList<int> d2 = d1;
          
          for(int i=0;i<d1.capacity();++i){
              d1.insert(i,i);
              d2.insert(i,i*i);
          }
          
          for(int i=0;i<d1.length();++i){
              cout << d1[i] << endl;
          }
      }
      
    • 分析:拷贝构造时发生了什么:构造 d1 时,m_array 会指向内存中一块空间,构造 d2 时,d2m_array 同样会指向相同的一块内存,那么在随后的 insert 操作中,后进行的 insert 操作会覆盖之前的 insert 操作,同样也会有同一块内存多次释放的问题

  • 结论:对于容器类型的类,可以考虑禁用拷贝构造和赋值操作

    线性表作为容器类,应该避免拷贝构造和拷贝赋值

    template<typename T>
    class List: public Object
    {
    protected:
        List(const List&);
        List& operator= (const List&);
    public:
        List(){}
        //...
    }
    
  • 代码优化

    • 禁用拷贝构造和赋值操作

      //List.h
      #include "Object.h"
      namespace DTLib
      {
      template <typename T>
      class List : public Object
      {
      protected:
          //禁用
          List(const List&);
          List& operator= (const List&);
      public:
          List() { } //这里在添加了拷贝构造函数后,需要手动添加一个默认构造函数
          virtual bool insert(int i,const T& e) = 0;
          virtual bool remove(int i) = 0;
          virtual bool set(int i,const T& e) = 0;
          virtual bool get(int i,T& e) const = 0;
          virtual int length() const = 0;
          virtual void clear() = 0;
      };
      }
      
    • 以重载的方式添加一个默认的插入操作:往线性表尾部插入数据

      //List.h
      #ifndef LIST_H
      #define LIST_H
      
      #include "Object.h"
      namespace DTLib
      {
      template <typename T>
      class List : public Object
      {
      protected:
          List(const List&);
          List& operator= (const List&);
      public:
          List() { } //这里在添加了拷贝构造函数后,需要手动添加一个默认构造函数
          virtual bool insert(const T& e) = 0;
          virtual bool insert(int i,const T& e) = 0;
          virtual bool remove(int i) = 0;
          virtual bool set(int i,const T& e) = 0;
          virtual bool get(int i,T& e) const = 0;
          virtual int length() const = 0;
          virtual void clear() = 0;
      };
      }
      
      //SeqList.h
      #ifndef SEQLIST_H
      #define SEQLIST_H
      
      #include "Exception.h"
      
      namespace DTLib
      {
      
      template <typename T>
      class SeqList : public List<T>
      {
      protected:
          T* m_array;  //顺序存储空间
          int m_length;  //当前线性表长度
      public:
          bool insert(int i,const T& e){
              bool ret = ((0 <= i) && (i <= m_length));
              ret = ret && ((m_length + 1) <= capacity());
      
              if(ret){
                  for(int p = m_length - 1;p >= i;p--){
                      m_array[p+1] = m_array[p];
                  }
                  m_array[i] = e;
                  m_length++;
              }
      
              return ret;
          }
      
          bool insert(const T& e){
              return insert(m_length,e);
          }
      };
      }
      
  • 代码分析3

    • Demo

      int main()
      {
          StaticList<int,5> list;
          
          for(int i = 0; i < list.capacity(); ++i){
              //将线性表当作数组使用
              list[i] = i * i;  //报越界异常:Parameter i is invalid ...
              //if((0 <= i) && (i < m_length))中,i < m_length 是不满足的:m_lenght = 0
          }
          
          return 0;
      }
      
    
    
  • 问题:将线性表当作数组使用

  • 分析:线性表必须先插入元素(使用 inert,才能使用操作符[] 访问元素

    顺序存储结构线性表提供了数组操作符重载,通过重载能够快捷方便地获取目标位置处的数据元素,在具体的使用形式上类似数组 ,但是由于本质不同,不能代替数组使用

7 数组类 Array 的创建

  • 基于顺序存储的线性表的主要问题
    • 功能上的问题:链表误当作数组来使用(重载了 [] 操作符)——利用数组类解决
    • 效率上的问题:基于顺序存储的线性表插入和删除的效率较低——利用线性表的链式存储解决

7.1 抽象类 Array 设计

  • 需求分析

    • 创建数组类代替原生数组的使用
    • 数组类包含长度信息
    • 数组类能够主动发现越界访问,例如上一节的代码分析3,数组发生越界却没有报告异常
  • Array 设计要点

    • 抽象模板类,存储空间的位置和大小由子类完成
    • 重载数组操作符,判断访问下标是否合法
    • 提供数组长度的抽象访问函数
    • 提供数组对象间的复制操作
  • Array 类的声明

    template <typename T>
    class Array: public Object
    {
    protected:
        T* m_array;
    public:
        virtual bool set(int i,const T& e);
        virtual bool get(int i,T& e) const;
        virtual int length() const = 0;
        //数组访问操作符
        T& operator[] (int i);
        T operator[] (int i) const;
    }
    
  • 数组抽象类的实现

    //Array.h
    #include "Object.h"
    #include "Exception.h"
    
    namespace DTLib
    {
    template <typename T>
    class Array : public Object
    {
    protected:
        T* m_array;
    public:
        virtual bool set(int i,const T& e){  //O(1)
            bool ret = ((0 <= i) && (i < length()));
    
            if(ret){
                m_array[i] = e;
            }
            return ret;
        }
    
        virtual bool get(int i,T& e) const{  //O(1)
            bool ret = ((0 <= i) && (i < length()));
    
            if(ret){
                e = m_array[i];
            }
            return ret;
        }
    
        //数组访问操作符
        T& operator[] (int i){  //O(1)
            if((0 <= i) && (i < length())){
                return m_array[i];
            }
            else{
                THROW_EXCEPTION(IndexOutOfBoundsException,"Parameter i is invalid ...");
            }
        }
    
        T operator[] (int i) const{  //O(1)
            return (const_cast<Array<T>&>(*this)[i]);
        }
    
        virtual int length() const = 0;
    };
    }
    

7.2 子类 StaticArray 类设计

  • StaticArray 类设计要点

    • 类模板
    • 封装原生数组
    • 使用模板参数决定数组大小
    • 实现函数返回数组长度
    • 拷贝构造和赋值操作
  • StaticArray 类的声明

    template <typename T,int N>
    class StaticArray : public Array<T>
    {
    protected:
        T m_space[N];
    public:
        StaticArray();
        //拷贝和赋值操作
        StaticArray(const StaticArray<T,N>& obj);
        StaticArray<T,N>& operator= (const StaticArray<T,N>& obj);
        
        int length() const;
    };
    
  • 静态数组类的实现

    //StaticArray.h
    #include "Array.h"
    
    namespace DTLib
    {
    
    template <typename T,int N>
    class StaticArray : public Array<T>
    {
    protected:
        T m_space[N];
    public:
        StaticArray(){  //O(1)
            this->m_array = m_space;
        }
    
        //拷贝和赋值操作
        StaticArray(const StaticArray<T,N>& obj){  //O(n)
            this->m_array = m_space;
            for(int i=0;i<N;++i){
                m_space[i] = obj.m_space[i];
            }
        }
    
        StaticArray<T,N>& operator= (const StaticArray<T,N>& obj){  //O(n)
            //判断是否自赋值
            if(this != &obj){
                for(int i=0;i<N;++i){
                    m_space[i] = obj.m_space[i];
                }
            }
    
            return *this;
        }
    
        int length() const{  //O(1)
            return N;
        }
    };
    
    }
    
  • 使用

    #include "StaticArray.h"
    
    using namespace std;
    using namespace DTLib;
    
    
    int main()
    {
        StaticArray<int,5> s1;
    
        for(int i=0;i<s1.length();++i){
            s1[i] = i * i;
        }
    
        for(int i=0;i<s1.length();++i){
            cout << s1[i] << endl;
        }
    
        StaticArray<int,5> s2;
        //支持数组的相互赋值
        s2 = s1;
    
        for(int i=0;i<s2.length();++i){
            cout << s2[i] << endl;
        }
    
        s1[6] = 100;  //Array类会抛出异常 : 'DTLib::IndexOutOfBoundsException'
        
        int s3[5];  //原生数组
        s3[6] = 100;  //越界,但不报异常
    
        return 0;
    }
    

7.3 子类 DynamicArray 类设计

  • DynamicArray 类设计要点

    • 类模板
    • 动态确定内部数组空间的大小
    • 实现函数返回数组长度
    • 拷贝构造和赋值操作
  • DynamicArray 类的声明

    template <typename T>
    class DynamicArray : public Array<T>
    {
    protected:
        int m_length;
    public:
        DynamicArray(int length);
        
        DynamicArray(const DynamicArray<T>& obj);
        DynamicArray<T>& operator= (const DynamicArray<T>& obj);
        
        int length() const;
        void resize(int length);  //动态重置数组的长度
        
        ~DynamicArray();
    };
    
  • 动态数组类的实现

    //DynamicArray.h
    #include "Array.h"
    #include "Exception.h"
    
    namespace DTLib
    {
    
    template <typename T>
    class DynamicArray : public Array<T>
    {
    protected:
        int m_length;
    public:
        DynamicArray(int length){
            this->m_array = new T[length];
    
            if(this->m_array != NULL){
                this->m_length = length;
            }
            else{
                THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create DynamicArray object ...");
            }
        }
    
        DynamicArray(const DynamicArray<T>& obj){
            this->m_array = new T[obj.m_length];
    
            if(this->m_array != NULL){
                this->m_length = obj.length;
    
                for(int i=0;i<obj.m_length;++i){
                    this->m_array[i] = obj.m_array[i];
                }
             }
            else{
                THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create DynamicArray object ...");
            }
        }
    
        DynamicArray<T>& operator= (const DynamicArray<T>& obj){
            if(this != &obj){
                T* array = new T[obj.m_length];
    
                if(array != NULL){
                    for(int i=0;i<obj.m_length;++i){
                        array[i] = obj.m_array[i];
                    }
    
                    T* temp = this->m_array;
    
                    this->m_array = array;
                    this->m_length = obj.m_length;
    
                    delete[] temp;
                }
                else{
                    THROW_EXCEPTION(NoEnoughMemoryException,"No memory to copy object ...");
                }
            }
    
            return *this;
        }
    
        int length() const{
            return m_length;
        }
    
        //动态重置数组的长度
        void resize(int length){
            if(length != m_length){
                T* array = new T[length];
    
                if(array != NULL){
                    int size = (length < m_length) ? length : m_length;
    
                    for(int i=0;i<size;++i){
                        array[i] = this->m_array[i];
                    }
    
                    T* temp = this->m_array;
    
                    this->m_array = array;
                    this->m_length = length;
    
                    delete[] temp;
                }
                else {
                    THROW_EXCEPTION(NoEnoughMemoryException,"No memory to resize object ...");
                }
            }
        }
    
        ~DynamicArray(){
            delete[] this->m_array;
        }
    };
    
    }
    
  • 使用

    #include "DynamicArray.h"
    
    using namespace std;
    using namespace DTLib;
    
    
    int main()
    {
        DynamicArray<int> s1(5);
    
        for(int i=0;i<s1.length();++i){
            s1[i] = i * i;
        }
    
        for(int i=0;i<s1.length();++i){
            cout << s1[i] << endl;
        }
    
        DynamicArray<int> s2(10);
    
        s2 = s1;
        s2.resize(8);
        for(int i=0;i<s2.length();++i){
            cout << s2[i] << endl;
        }
        
        s2.resize(3);
        for(int i=0;i<s2.length();++i){
            cout << s2[i] << endl;
        }
        
        s2[4] = 100;
    
        return 0;
    }
    
  • DynamicArray 类中的函数实现存在重复的逻辑,进行代码优化

    • init :对象构造时的初始化操作
    • copy :在堆空间中申请新的内存,并执行拷贝操作
    • update :将指定的堆空间作为内部存储数组使用
    //DynamicArray.h
    #include "Array.h"
    #include "Exception.h"
    
    namespace DTLib
    {
    
    template <typename T>
    class DynamicArray : public Array<T>
    {
    protected:
      int m_length;
      //在堆空间中申请一个新的数组ret,大小为newLen,再将传入的array数组中的元素拷贝到新的数组中
      T* copy(T* array,int len,int newLen){
          T* ret = new T[newLen];
    
          if(ret != NULL){
              //数据元素的拷贝
              int size = (len < newLen) ? len : newLen;
    
              for(int i=0;i<size;++i){
                  ret[i] = array[i];
              }
          }
    
          return ret;
      }
    
      void update(T* array,int length){
          if(array != NULL){
              //异常安全
              T* temp = this->m_array;
    
              this->m_array = array;
              this->m_length = length;
    
              delete[] temp;
          }
          else{
              THROW_EXCEPTION(NoEnoughMemoryException,"No memory to update DynamicArray object ...");
          }
      }
    
      void init(T* array,int length){
          if(array != NULL){
              this->m_array = array;
              this->m_length = length;
          }
          else{
              THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create DynamicArray object ...");
          }
      }
    
    public:
      DynamicArray(int length){
          init(new T[length],length);
      }
    
      DynamicArray(const DynamicArray<T>& obj){
          T* array = copy(obj.m_array,obj.m_length,obj.m_length);
          init(array,obj.m_length);
      }
    
      DynamicArray<T>& operator= (const DynamicArray<T>& obj){
          if(this != &obj){
              T* array = copy(obj.m_array,obj.m_length,obj.m_length);
              update(array,obj.m_length);
          }
          return *this;
      }
    
      int length() const{
          return m_length;
      }
    
      //动态重置数组的长度
      void resize(int length){
          if(length != m_length){
              T* array = copy(this->m_array,m_length,length);
              update(array,length);
          }
      }
    
      ~DynamicArray(){
          delete[] this->m_array;
      }
    };
    
    }
    
posted @ 2020-10-15 16:32  nxgy  阅读(227)  评论(0编辑  收藏  举报