课程目标

完成 DynamicArray 类的具体实现

image.png

DynamicArray 设计要点

  • 类模板

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

DynamicArray 类的声明

template <typename T>
clas DynamicArray : public Arrray<T>
{
public:
    DynamicArray(int length);
    DynamicArray(const DynamicArray<T> &obj);
    DynamicArray<T> &operator= (const DynamicArray<T> &obj);
    
    int length() const;
    void resize(int length);

protected:
    int m_length;
};

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

#ifndef DYNAMICARRAY_H
#define DYNAMICARRAY_H

#include "Array.h"
#include "Exception.h"

namespace DTLib
{

template <typename T>
class DynamicArray : public Array<T>
{
public:
    DynamicArray(int length = 0)  // O(1)
    {
        this->m_array = new T[length];

        if (this->m_array != nullptr)
        {
            this->m_length = length;
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create DynamicArray object ...");
        }
    }

    DynamicArray(const DynamicArray<T> &obj)  // O(n)
    {
        this->m_array = new T[obj.m_length];

        if (this->m_array != nullptr)
        {
            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)  // O(n)
    {
        if (this != &obj)
        {
            T *array = new T[obj.m_length];

            if (array != nullptr)
            {
                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 DynamicArray object ...");
            }
        }

        return *this;
    }

    int length() const  // O(1)
    {
        return m_length;
    }

    void resize(int length)  // O(n)
    {
        if (length != m_length)
        {
            T *array = new T[length];

            if (array != nullptr)
            {
                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 DynamicArray object...");
            }
        }
    }
    
    ~DynamicArray()  // O(1)
    {
        delete []  this->m_array;
    }

protected:
    int m_length = 0;
};

}

#endif // DYNAMICARRAY_H

文件:main.cpp

#include <iostream>
#include "DynamicArray.h"

using namespace std;
using namespace DTLib;

int main()
{
    cout << "main begin" << endl;

    DynamicArray<int> d(5);

    for (int i=0; i<d.length(); ++i)
    {
        d[i] = i * i;
    }

    for (int i=0; i<d.length(); ++i)
    {
        cout << d[i] << endl;
    }

    cout << "---------" << endl;

    DynamicArray<int> d1;

    d1 = d;

    d1.resize(3);

    for (int i=0; i<d1.length(); ++i)
    {
        cout << d1[i] << endl;
    }

    cout << "main end" << endl;

    return 0;
}

输出:

main begin
0
1
4
9
16
---------
0
1
4
main end

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

重复代码逻辑的抽象

  • init

    • 对象构造时的初始化操作
  • copy

    • 在堆空间中申请新的内存,并执行拷贝操作
  • update

    • 将指定的堆空间作为内存存储数组使用

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

#ifndef DYNAMICARRAY_H
#define DYNAMICARRAY_H

#include "Array.h"
#include "Exception.h"

namespace DTLib
{

template <typename T>
class DynamicArray : public Array<T>
{
public:
    DynamicArray(int length = 0)  // O(1)
    {
        init(new T[length], length);
    }

    DynamicArray(const DynamicArray<T> &obj)  // O(n)
    {
        init(copy(obj.m_array, obj.m_length, obj.m_length), obj.m_length);
    }

    DynamicArray<T> &operator= (const DynamicArray<T> &obj)  // O(n)
    {
        if (this != &obj)
        {
            update(copy(obj.m_array, obj.m_length, obj.m_length), obj.m_length);
        }

        return *this;
    }

    int length() const  // O(1)
    {
        return m_length;
    }

    void resize(int length)  // O(n)
    {
        if (length != m_length)
        {
            update(copy(this->m_array, this->m_length, length), length);
        }
    }

    ~DynamicArray()  // O(1)
    {
        delete []  this->m_array;
    }

protected:
    int m_length = 0;

    T *copy(T *array, int length, int newLength)  // O(n)
    {
        T *ret = new T[newLength];

        if (ret != nullptr)
        {
            int size = (length < newLength) ? length : newLength;
            for (int i=0; i<size; ++i)
            {
                ret[i] = array[i];
            }
        }

        return ret;
    }

    void update(T *array, int length)  // O(1)
    {
        if (array != nullptr)
        {
            T *temp = this->m_array;
            this->m_array = array;
            this->m_length = length;
            delete [] temp;
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to update DynmicArray object ...");
        }
    }

    void init(T *array, int length)  // O(1)
    {
        if (array != nullptr)
        {
            this->m_array = array;
            this->m_length = length;
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No enough to init DynamicArray object ...");
        }
    }
};

}

#endif // DYNAMICARRAY_H

小结

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

以上内容整理于狄泰软件学院系列课程,请大家保护原创!


TianSong
734 声望138 粉丝

阿里山神木的种子在3000年前已经埋下,今天不过是看到当年注定的结果,为了未来的自己,今天就埋下一颗好种子吧