数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建

十四、线性表的本质和操作

1、生活中的智慧

幼儿园老师总会让小朋友以同样的排队秩序出行。

2、线性表(List)的表现形式

  • 零个多个数据元素组成的集合
  • 数据元素在位置上是有序排列的
  • 数据元素的个数是有限的
  • 数据元素的类型必须相同

3、线性表(List)的抽象定义

        数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第1张图片

4、线性表(List)的性质

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第2张图片

5、思考题

  • 下面的关系中可以用线性表描述的是
    • 班级中同学的友谊关系 (X一对多)
    • 公司中的上下级关系 (X一对多)
    • 冬天图书馆用物品排队占座 (X数据类型不同)

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第3张图片

6、问题

        线性表只是一个单纯的概念吗?如何在程序中描述和使用一个线性表?

7、线性表的一些常用操作

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

8、线性表在程序中表现为一种特殊的数据类型

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第4张图片

9、编程实验:线性表抽象类的创建

List.h

#ifndef LIST_H_
#define LIST_H_
/*******************************************************************************
 *                              Include Files                                  *
 *******************************************************************************/
#include "Object.h"
/*******************************************************************************
 *                             Type Definition                                 *
 *******************************************************************************/
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;            // 在线性表尾部插入e
    virtual bool insert(int i, const T& e) = 0;     // 在i处插入e
    virtual bool remove(int i) = 0;                 // 删除第i个元素
    virtual bool set(int i, const T& e) = 0;        // 设置第i个元素为e
    virtual bool get(int i, T& e) const = 0;        // 获取第i个元素为e
    virtual int find(const T& e) const = 0;         // 查找指定的元素
    virtual int length() const = 0;                 // 返回当前有效值的数量
    virtual void clear() = 0;                       // 清空链表

    List& self()
    {
        return *this;
    }
};

}


#endif // LIST_H_

10、小结

  • 线性表是数据元素的有序并且有限的集合
  • 线性表中的数据元素必须是类型相同的
  • 线性表可用于描述排队关系的问题
  • 线性表在程序中表现为一种特殊的数据类型
  • 线性表在C++中表现为一个抽象类

十五、线性表的顺序存储结构

1、顺序存储的定义

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

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第5张图片

2、设计思路

  • 可以用一维数组来实现顺序存储结构
    • 存储空间:T*m_array;
    • 当前长度:int m_length;

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第6张图片

3、顺序存储结构的元素获取操作

  • 判断目标位置是否合法
  • 将目标位置作为数组下标获取元素

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第7张图片

4、编程实验:图解元素获取

        通过数组下标获取元素

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第8张图片

 

5、顺序存储结构的元素插入操作

        1. 判断目标位置是否合法

        2. 将目标位置之后的所有元素后移一个位置

        3. 将新元素插入目标位置

        4. 线性表长度加1

6、顺序存储结构的元素插入示例

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第9张图片

7、编程实验:图解元素插入

        线性表长度+1 ===> 会不会越界;

        插入的位置是否合理(不能插入的位置前后都没数据)

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第10张图片

8、顺序存储结构的元素删除操作

1. 判断目标位置是否合法

2. 将目标位置后的所有元素前移一个位置

3. 线生表长度减1

9、顺序存储结构的元素删除示例

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第11张图片

10、编程实验:图解元素删除

        删除的位置是否合理(不能删除的位置没数据)

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第12张图片

 

11、实战预告

To be continued …

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第13张图片

十六、顺序存储结构的抽象实现

1、课程目标

完成顺序存储结构线性表的抽象实现

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第14张图片

2、SeqList设计要点

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

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第15张图片

3、编程实验:顺序存储线性表

SeqList.h

#ifndef SEQLIST_H_
#define SEQLIST_H_
/*******************************************************************************
 *                              Include Files                                  *
 *******************************************************************************/
#include "List.h"
#include "Exception.h"
/*******************************************************************************
 *                             Type Definition                                 *
 *******************************************************************************/
namespace DTLib
{

template < typename T >
class SeqList : public List
{
protected:
    T* m_array;                                         // 数组地址
    int m_length;                                       // 当前线性表长度
public:
/**********************************************************************
* Function:        insert()
* Description:      在i位置,插入e 
* Input:            i                   待插入的位置
*                   e                   待插入的数据
* Output:           
* Return:           bool                是否插入成功
* Others:           O(n+5) => O(n)
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    bool insert(int i, const T& e)
    {
        bool ret = ((0 <= i) && (i <= m_length));       // i的合法性 (不能插入的位置前后都没数据)

        ret = ret && (m_length < 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++;                                 // 线性表长度+1
        }

        return ret;                            
    }

/**********************************************************************
* Function:        insert()
* Description:      在线性表尾部,插入e 
* Input:            e                   待插入的数据
* Output:           
* Return:           bool                是否插入成功
* Others:           O(n)
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    bool insert(const T& e)         
    {
        return insert(m_length, e);
    }

/**********************************************************************
* Function:        remove()
* Description:      删除i位置的元素
* Input:            i                   待删除的位置
* Output:           
* Return:           bool                是否删除成功
* Others:           O(n)
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    bool remove(int i)
    {
        bool ret = ((0 <= i) && (i < m_length));            // i的合法性

        if( ret )
        {
            for(int p=i; p&>(*this))[i];
    }

/**********************************************************************
* Function:        capacity()
* Description:      顺序存储空间的容量
* Input:            
* Output:           
* Return:           int                 顺序存储空间的容量
* Others:           纯虚函数
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    virtual int capacity() const = 0;
};


}

#endif // SEQLIST_H_

4、To be continued ...

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第16张图片

十七、StaticList 和 DynamicList

1、课程目标

  • 完成StaticList类的具体实现
  • 完成DynamicList类的具体实现

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第17张图片

2、StaticList 设计要点

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

· 数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第18张图片

3、编程实验:StaticList的实现

StaticList.h

#ifndef STATICLIST_H_
#define STATICLIST_H_
/*******************************************************************************
 *                              Include _Files                                  *
 *******************************************************************************/
#include "SeqList.h"
/*******************************************************************************
 *                             Type Definition                                 *
 *******************************************************************************/
namespace DTLib
{

template < typename T, int N >
class StaticList : public SeqList
{
protected:
    T m_space[N];                       // 元素总数量
public:
    StaticList()                        // 构造函数 - 指定父类成员的具体值
    {
        this->m_array = m_space;        // 初始化元素总数量
        this->m_length = 0;             // 初始化当前线性表长度
    }

    int capacity() const                // 获取元素总数量
    {
        return N;
    }
};


}

#endif // STATICLIST_H_

4、DynamicList设计要点

  • 类模
    • 申请连续堆空间作为顺序存储空间
    • 动态设置顺序存储空间的大小
    • 保证重置顺序存储空间时的异常安全性
  • 函数异常安全的概念
    • 不泄漏任何资源
    • 不允许破坏数据
  • 函数异常安全的基本保证
    • 如果异常被抛出
      • 对象内的任何成员仍然能保持有效状态
      • 没有数据的破坏及资源泄漏

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第19张图片

5、编程实验:DynamicList的实现

DynamicList.h

#ifndef DYNAMICLIST_H_
#define DYNAMICLIST_H_
/*******************************************************************************
 *                              Include _Files                                  *
 *******************************************************************************/
#include "SeqList.h"
#include "Exception.h"
/*******************************************************************************
 *                             Type Definition                                 *
 *******************************************************************************/
namespace DTLib
{

template < typename T >
class DynamicList : public SeqList
{
protected:
    int m_capacity;                                             // 元素总数量
public:
/**********************************************************************
* Function:        DynamicList()
* Description:     构造函数
* Table Accessed: 
* Table Updated:  
* Input:            capacity            元素总数量
* Output:           
* Return:          
* Others:           
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    DynamicList(int capacity)                                   // 构造函数 - 申请空间
    {
        this->m_array = new T[capacity];                        // 申请堆空间

        if( this->m_array != NULL )
        {
            this->m_length = 0;                                 // 初始化当前线性表长度
            this->m_capacity = capacity;                        // 初始化元素总数量
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create DynamicList object ...");
        }
    }
/**********************************************************************
* Function:        capacity()
* Description:     返回元素总数量
* Table Accessed: 
* Table Updated:  
* Input:            
* Output:           
* Return:           int                 返回 元素总数量
* Others:           
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    int capacity() const
    {
        return m_capacity;
    }

/**********************************************************************
* Function:        resize()
* Description:     重新设置元素数量
* Table Accessed: 
* Table Updated:  
* Input:            capacity            新元素总数量
* Output:           
* Return:          
* Others:           
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    void resize(int capacity)
    {
        if( capacity != m_capacity )
        {
            T* array = new T[capacity];                                         // 重新申请一块符合大小的堆空间

            if( array != NULL )                                                 // 成功申请
            {
                int length = (this->m_length < capacity ? this->m_length : capacity); // 获取当前元素的数量

                for(int i=0; im_array[i];                                /* 此可能发生异常,动态链表依然可用,但是会发生内存泄漏。且无法避免。*/
                }                                                               /* T是一个泛型类型,赋值操作符可能被重载,并且重载的实现出现的异常,上层修改即可*/
                
                T* temp = this->m_array;                                        /* 此处不直接释放堆空间,防止此处抛出异常,保障动态链表异常安全性 */

                this->m_array = array;                                          // 更新 顺序存储空间
                this->m_length = length;                                        // 更新 当前线性表长度
                this->m_capacity = capacity;                                    // 更新 返回元素总数量

                delete[] temp;                                                  // 删除原来的堆空间
            }
            else
            {
                THROW_EXCEPTION(NoEnoughMemoryException, "No memory to resize DynamicList object ...");
            }
        }
    }
/**********************************************************************
* Function:        ~DynamicList()
* Description:     析构函数
* Table Accessed: 
* Table Updated:  
* Input:            
* Output:           
* Return:          
* Others:           释放堆内存空间
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    ~DynamicList()
    {
        delete[] this->m_array;
    }
};


}

#endif // DYNAMICLIST_H_

6、问题

是否可以将DynamicList 作为StaticList的子类实现?

7、小结

  • StaticList 通过模板参数定义顺序存储空间
  • DynamicList 通过动态内存申请定义顺序存储空间
  • DynamicList 支持动态重置顺序存储空间的大小
  • DynamicList 中的resize()函数实现需要保证异常安全

十八、顺序存储线性表的分析

1、效率分析

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第20张图片

2、问题

        长度相同的两个SeqList插入删除操作的平均耗时是否相同?

                要具体问题具体分析。

3、编程实验:SeqList效率分析

  • T为int和String时,字符串的拷贝更耗时。
  • 由于数据类型的不同,赋值操作的效率和耗时不同。取决于线性表里存储的数据类型。
  • 不能单纯只看时间复杂度O,只是参考指标,不是绝对指标,要根据实际情况分析。
  • 基于顺序存储结构的线性表不适合使用类类型的对象作为数据元素存储。

4、下面的代码正确吗?为什么?

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第21张图片

        数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第22张图片

拷贝使得两个对象指向同一份堆空间,导致同一个堆空间被两次。

5、分析

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

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第23张图片

6、编程实验:代码优化

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

7、下面的代码正确吗?为什么?不正确

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第24张图片

线性表必须先插入元素,才能使用操作符[]访问元素。

8、问题分析

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

9、实战预告:数组类开发

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第25张图片

10、小结

  • 顺序存储线性表的插入和删除操作存在重大效率隐患(不适合使用类类型的对象作为数据元素存储)
  • 线性表作为容器类,应该避免拷贝构造和拷贝赋值
  • 顺序存储线性表可能被当成数组误用
  • 工程开发中可以考虑使用数组类代替原生数组使用

十九、数组类的创建(上)

1、课程目标

  • 完成Array类的具体实现
  • 完成StaticArray类的具体实现

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第26张图片

2、需求分析

  • 创建数组类代替原生数组的使用
    • 数组类包含长度信息
    • 数组类能够主动发现越界访问

3、Array设计要点

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

4、Array类的声明

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第27张图片

5、编程实验:数组抽象类实现

Array.h

#ifndef ARRAY_H_
#define ARRAY_H_
/*******************************************************************************
 *                              Include Files                                  *
 *******************************************************************************/
#include "Object.h"
#include "Exception.h"
/*******************************************************************************
 *                             Type Definition                                 *
 *******************************************************************************/
namespace DTLib
{

template < typename T >
class Array : public Object
{
protected:
    T* m_array;
public:
/**********************************************************************
* Function:        set()
* Description:      设置数组下标为i的元素值为e
* Input:            i                   下标为i
*                   e                   元素值为e
* Output:           
* Return:           bool                返回是否成功
* Others:           与原生数组差异:预防下标越界
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    virtual bool set(int i, const T& e)
    {
        bool ret = ((0 <= i) && (i < length()));

        if( ret )
        {
            m_array[i] = e;
        }

        return ret;
    }

/**********************************************************************
* Function:        get()
* Description:      获取数组下标为i的元素值
* Input:            i                   下标为i
*                   e                   元素值为e
* Return:           bool                返回是否成功
* Others:           与原生数组差异:预防下标越界
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    virtual bool get(int i, T& e) const
    {
        bool ret = ((0 <= i) && (i < length()));

        if( ret )
        {
            e = m_array[i];
        }

        return ret;
    }

/**********************************************************************
* Function:        operator[]()
* Description:      []操作符重载函数
* Input:            i                   数组下标i的元素
* Output:           
* Return:           T                   返回元素的值
* Others:           下标越界,抛出异常
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    virtual T& operator[] (int i)
    {
        if((0 <= i) && (i < length()))
        {
            return m_array[i];
        }
        else
        {
            THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter i is invalid ...");
        }
    }

/**********************************************************************
* Function:        operator[]()
* Description:      []操作符重载函数(传入const)
* Input:            i                   数组下标i的元素
* Output:           
* Return:           T                   返回元素的值
* Others:           下标越界,抛出异常
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    virtual T operator[] (int i) const
    {
        return (const_cast&>(*this))[i];
    }

/**********************************************************************
* Function:        array()
* Description:      返回数组的地址
* Input:            
* Output:           
* Return:           T                   返回数组的地址
* Others:           
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    T* array() const
    {
        return m_array;
    }

    Array& self()
    {
        return *this;
    }

    virtual int length() const = 0;
};

}

#endif // ARRAY_H_

6、StaticArray设计要点

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

7、StaticArray类的声明

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第28张图片

8、编程实验:静态数组类的实现

StaticArray.h

#ifndef STATICARRAY_H_
#define STATICARRAY_H_
/*******************************************************************************
 *                              Include Files                                  *
 *******************************************************************************/
#include "Array.h"
/*******************************************************************************
 *                             Type Definition                                 *
 *******************************************************************************/
namespace DTLib
{

template < typename T, int N >
class StaticArray : public Array
{
protected:
    T m_space[N];
public:
    StaticArray()                                               // 构造函数
    {
        this->m_array = m_space;                                // 初始化父类成员
    }

    StaticArray(const StaticArray& obj)                   // 拷贝构造函数
    {
        this->m_array = m_space;                                // 初始化父类成员

        for(int i=0; i& operator= (const StaticArray& obj) // 赋值构造函数
    {
        if( this != &obj )                                      // 不允许自赋值
        {
            for(int i=0; i

9、实战预告

To be continued …

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第29张图片

二十、数组类的创建(下)

1、课程目标

完成DynamicArray 类的具体实现

数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第30张图片

2、DynamicArray设计要点

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

3、DynamicArray类的声明

         数据结构实战开发教程(三)线性表的本质和操作、顺序存储结构的抽象实现、顺序存储线性表的分析、数组类的创建_第31张图片

4、编程实验:动态数组的实现

5、问题

DynamicArray类中的函数实现存在重复的逻辑,如何进行代码优化?

6、重复代码逻辑的抽象

  • init
    • 对象构造时的初始化操作
  • copy
    • 在堆空间中申请新的内存,并执行拷贝操作
  • update
    • 将指定的堆空间作为内部存储数组使用

7、编程实验:动态数组的优化

DynamicArray.h

#ifndef DYNAMICARRAY_H_
#define DYNAMICARRAY_H_
/*******************************************************************************
 *                              Include _Files                                  *
 *******************************************************************************/
#include "Array.h"
#include "Exception.h"
/*******************************************************************************
 *                             Type Definition                                 *
 *******************************************************************************/
namespace DTLib
{

template < typename T >
class DynamicArray : public Array
{
protected:
    int m_length;

/**********************************************************************
* Function:        copy()
* Description:      动态调整数组大小
* Input:            array               数组类地址
*                   len                 原数组成员数量
*                   newLen              新数组成员数量
* Output:           
* Return:           bool                返回数组类地址
* Others:           O(n)
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    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; im_array;                    /* 此处不直接释放堆空间,防止此处抛出异常,保障动态数组异常安全性 */

            this->m_array = array;                      // 更新数组地址
            this->m_length = length;                    // 更新数组元素数量

            delete[] temp;
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory to update DynamicArray object ...");
        }
    }

/**********************************************************************
* Function:        init()
* Description:      初始化数组大小
* Input:            array               数组类地址
*                   length              数组元素数量
* Output:           
* Return:           
* Others:           
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    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:
/**********************************************************************
* Function:        DynamicArray()
* Description:      构造函数 - 创建数组
* Input:            length              数组元素数量
* Output:           
* Return:           
* Others:           
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    DynamicArray(int length = 0)
    {
        init(new T[length], length);
    }

/**********************************************************************
* Function:        DynamicArray()
* Description:      拷贝构造函数
* Input:            obj                 待拷贝的数组类
* Output:           
* Return:           
* Others:           先创建拷贝数组类(copy),再初始化数组地址和数组元素数量(init)
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    DynamicArray(const DynamicArray& obj)
    {
        init(copy(obj.m_array, obj.m_length, obj.m_length), obj.m_length);
    }

/**********************************************************************
* Function:        operator=()
* Description:      赋值构造函数
* Input:            obj                 待拷贝的数组类
* Output:           
* Return:           
* Others:           先创建拷贝数组类(copy),再更新数组地址和数组元素数量(update)
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    DynamicArray& operator= (const DynamicArray& obj)
    {
        if( this != &obj )                                  // 禁止自赋值
        {
            update(copy(obj.m_array, obj.m_length, obj.m_length), obj.m_length);
        }

        return *this;
    }

/**********************************************************************
* Function:        length()
* Description:      返回数组元素数量
* Input:            
* Output:           
* Return:           返回数组元素数量
* Others:           
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    int length() const
    {
        return m_length;
    }

/**********************************************************************
* Function:        resize()
* Description:      重新分配数组的元素数量
* Input:            length              重新分配的数组元素数量
* Output:           
* Return:           
* Others:           先创建拷贝数组类(copy),再更新数组地址和数组元素数量(update)
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    virtual void resize(int length)
    {
        if( length != m_length )
        {
            update(copy(this->m_array, m_length, length), length);
        }
    }

/**********************************************************************
* Function:        ~DynamicArray()
* Description:      析构函数
* Input:            
* Output:           
* Return:           
* Others:           释放数组的堆空间
* Modify   Date     Version    Author      Modification
* ------------------------------------------------------------
*       2022/03/10    1.0                         Create        
**********************************************************************/
    ~DynamicArray()
    {
        delete[] this->m_array;
    }
};


}

#endif // DYNAMICARRAY_H_

8、小结

  • StaticArray通过封装原生数组的方式实现数组类
  • DynamicArray动态申请堆空间,使得数组长度动态可变
  • 数组对象能够代替原生数组,并且使用上更安全
  • 代码优化是项目开发过程中不可或缺的环节

你可能感兴趣的:(数据结构实战开发教程,数据结构,线性表的本质和操作,顺序存储结构的抽象实现,顺序存储线性表的分析,数组类的创建)