• 数据结构开发(4):数组类的创建


    0.目录

    1.Array

    2.StaticArray

    3.DynamicArray

    4.小结

    1.Array

    本节目标:

    • 完成 Array 类的具体实现

    需求分析:

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

    Array 设计要点:

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

    Array 类的声明:

    (在StLib中实现Array.h)

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

    2.StaticArray

    本节目标:

    • 完成 StaticArray 类的具体实现

    StaticArray 设计要点

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

    StaticArray 类的声明:

    (在StLib中实现StaticArray.h)

    #ifndef STATICARRAY_H
    #define STATICARRAY_H
    
    #include "Array.h"
    
    namespace StLib
    {
    
    template <typename T, int N>
    class StaticArray : public Array<T>
    {
    protected:
        T m_space[N];
    public:
        StaticArray()
        {
            this->m_array = m_space;
        }
    
        // 拷贝构造和赋值操作
        StaticArray(const StaticArray<T, N>& obj)
        {
            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)
        {
            if( this != &obj )
            {
                for(int i=0; i<N; i++)
                {
                    m_space[i] = obj.m_space[i];
                }
            }
    
            return *this;
        }
    
        int length() const
        {
            return N;
        }
    };
    
    }
    
    #endif // STATICARRAY_H
    

    main.cpp测试

    #include <iostream>
    #include "StaticArray.h"
    
    using namespace std;
    using namespace StLib;
    
    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;
        }
        cout << endl;
    
        StaticArray<int, 5> s2;
    
        s2 = s1;
    
        for(int i=0; i<s2.length(); i++)
        {
            cout << s2[i] << endl;
        }
    
        return 0;
    }
    

    运行结果为:

    0
    1
    4
    9
    16
    
    0
    1
    4
    9
    16
    

    3.DynamicArray

    本节目标:

    • 完成 DynamicArray 类的具体实现

    DynamicArray 设计要点

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

    DynamicArray 类的声明:

    (在StLib中实现DynamicArray.h)

    #ifndef DYNAMICARRAY_H
    #define DYNAMICARRAY_H
    
    #include "Array.h"
    #include "Exception.h"
    
    namespace StLib
    {
    
    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.m_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 ...");
                }
            }
        }
    
        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;
        }
    };
    
    }
    
    #endif // DYNAMICARRAY_H
    

    main.cpp测试

    #include <iostream>
    #include "DynamicArray.h"
    
    using namespace std;
    using namespace StLib;
    
    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;
        }
        cout << endl;
    
        DynamicArray<int> s2(10);
    
        s2 = s1;
    
        s2.resize(3);
    
        for(int i=0; i<s2.length(); i++)
        {
            cout << s2[i] << endl;
        }
    
        return 0;
    }
    

    运行结果为:

    0
    1
    4
    9
    16
    
    0
    1
    4
    

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

    重复代码逻辑的抽象

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

    动态数组的优化(DynamicArray.h):
    优化DynamicArray.h

    #ifndef DYNAMICARRAY_H
    #define DYNAMICARRAY_H
    
    #include "Array.h"
    #include "Exception.h"
    
    namespace StLib
    {
    
    template <typename T>
    class DynamicArray : public Array<T>
    {
    protected:
        int m_length;
    
        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)
        {
            init(copy(obj.m_array, obj.m_length, obj.m_length), obj.m_length);
        }
    
        DynamicArray<T>& operator= (const DynamicArray<T>& obj)
        {
            if( this != &obj )
            {
                update(copy(obj.m_array, obj.m_length, obj.m_length), obj.m_length);
            }
    
            return *this;
        }
    
        int length() const
        {
            return m_length;
        }
    
        void resize(int length) // 动态重置数组的长度
        {
            if( length != m_length )
            {
                update(copy(this->m_array, m_length, length), length);
            }
        }
    
        ~DynamicArray()
        {
            delete[] this->m_array;
        }
    };
    
    }
    
    #endif // DYNAMICARRAY_H
    

    4.小结

    • StaticArray 通过封装原生数组的方式实现数组类
    • DynamicArray 动态申请堆空间,使得数组长度动态可变
    • 数组对象能够代替原生数组,并且使用上更安全
    • 代码优化是项目开发过程中不可或缺的环节
  • 相关阅读:
    android studio学习---怎么创建一个新的module并且再次运行起来(在当前的project里面)
    你真的了解WebSocket吗?
    vue学习(十二)vue全家桶 Vue-router&Vuex
    GoJs的使用
    vue学习(十一)vue-cli3开发单文件组件
    vue学习(十)mixin 偷懒
    vue学习(九)对象变更检测注意事项
    vue学习(八)nextTick[异步更新队列]的使用和应用
    django的url 传不传参
    vue学习(七)refs的使用
  • 原文地址:https://www.cnblogs.com/PyLearn/p/10114618.html
Copyright © 2020-2023  润新知