• 线性表之数组描述


    1.线性表的描述可以分为两种

    • 数组描述:StaticList和DynamicList(动态数组)
    • 链式描述

    2.数组描述

    •  数组描述方法将元素存储在一个数组中,通过一个索引以确定每个元素存储的位置
    •  所有元素依次存储在一片连续的存储空间中
    • 线性表中的每一个元素对应数组中的一个位置

    3.创建一个数组类

    要创建一个数组类必须确定数组类型和确定数组长度,所以针对以上两个问题有以下解决:

    • 模板类
    • 动态数组(数组空间不够的情况下动态增加数组长度)

     4. StaticList类实现

    • 使用原生数组作为顺序存储空间
    • 使用模板参数决定数组大小(数组固定不可以改变)
    #ifndef STATICLIST_H
    #define STATICLIST_H
    #include "Seqlist.h"
    
    namespace DataStructureLib
    {
        template <typename T, int N>
    
        class StaticList: public SeqList<T>
        {
        protected:
            T m_space[N];//顺序存储空间,N为模板的参数  (类成员m_space是一个原生的数组,原生数组的类型是T类型)在此静态的定义了一个原生数组存储空间
        public:
            StaticList()// 指定父类成员的具体值
            {
                this->m_array=m_space;
                this->m_length=0;
            }
    
            int capacity() const//int capacity()
            {
                return N;
            }
        };
    
    }
    
    #endif // STATICLIST_H

    测试

    #include <iostream>
    #include "StaticList.h"
    #include "Exception.h"
    using namespace std;
    using namespace DataStructureLib;
    
    int main()
    {
      StaticList<int,5> l;
    
      for(int  i=0;i<l.capacity(); i++)
      {
          l.insert(0,i);
      }
    
      for(int i=0;i<l.capacity();i++)
      {
          cout<<l[i]<<endl;
      }
    
      try
      {
          l[5]=9;
      }
      catch(const Exception& e)
      {
          cout<<e.message()<<endl;
          cout<<e.location()<<endl;
      }
        system("pause");
      return 0;
    }

    5.DynamicList设计要点(DynamicList 是一个类模板

    • 动态申请连续的堆空间作为顺序存储空间
    • 动态设置顺序存储空间的大小
    • 保证重置顺序存储空间时的异常安全性
    函数调用前和函数调用后
    • 不泄露任何资源
    • 不允许破坏数据
     
    函数异常安全的保证:
    如果异常被抛出:
    • 对象里面的任何成员仍能保持有效状态(即异常被抛出后该对象依然可以用)
    • 没有数据的破坏和资源的泄漏
    DynamicList.h
     1 #ifndef DYNAMICLIST_H
     2 #define DYNAMICLIST_H
     3 #include "seqlist.h"
     4 
     5 namespace DTLib
     6 {
     7     template<typename T>
     8     class DynamicList:public Seqlist<T>
     9     {
    10     private:
    11         int m_capacity ;//顺序存储空间的大小
    12     public:
    13         DynamicList(int capacity) //申请空间
    14         {
    15             this->m_array=new  T[capacity];
    16             if(m_array!=NULL)
    17             {
    18                 //、赋初始值
    19                 this->m_length=0;
    20                 this->m_capacity=capacity;
    21             }
    22             else
    23             {
    24                 THROW_EXCEPTION(NotEnoughMemoryException,"No Enough Memory to Create DynamicList...");
    25             }
    26         }
    27 
    28         int capacity() const
    29         {
    30             return this->m_capacity;
    31         }
    32 
    33         //重新设置存储空间的大小
    34         void resize(int capacity)
    35         {
    36             if(capacity!=this->m_capacity)
    37             {
    38                 T* array=new T[capacity];
    39                 if(array!=NULL)
    40                 {
    41                 int length=(this->m_capacity<capacity?this->m_capacity:capacity);//判断当前线性表里的个数
    42                 //如果this->m_capacity<capacity当前线性表里的存储的元素的个数小于新的目标大小capacity的,所有的数据元素都可以保存下来
    43                 //否则就以新的大小capacity为准
    44 
    45                 //复制 数据元素的  当前线性表中的元素复制到新申请到的堆空间
    46                 //因为需要保证数据元素不丢失
    47                 for(int i=0;i<length;i++)
    48                 {
    49                     array[i]=this->m_array[i];
    50                                            //T类在赋值时,可能产生异常!但是,即使这里发生了异常,由于
    51                                             //下列的m_array、m_length、m_capacity还没被改变。所以,仍然可以
    52                                             //保证DynamicList类是安全可用的,只是会造成array这个空间的内泄漏。
    53                                             //这里作为T类的使用者,无须替T类的设计者考虑当赋值中出现问题时是要抛
    54                                             //异常通知使用者,还是采用其它处理办法。如果T类的设计者以抛异常处理,
    55                                             //则这里可以通过try-catch捕获这个赋值异常,然后在catch语句块中将
    56                                             //array这个临时空间释放掉。
    57                 }
    58 
    59             //这里不能先delete[] this->m_array,再给m_array、m_length、m_capacity
    60             //赋值,因为delete可能会引起T调用析构函数,而如果在析构函数中抛出异常,以下对
    61             //成员变量的赋值都将无法进行,从而造成函数异常时的不安全。因此,正确的顺序应该是
    62             //先对成员变量赋值,最后再释放m_array的旧空间。
    63                 T* tmp=this->m_array;   
    64 
    65                 m_array=array;
    66                  this->m_length=length;
    67                  this->m_capacity=capacity;
    68 
    69                 delete[] tmp;//重置前的顺序存储空间
    70 
    71                 }
    72 
    73                 else
    74                 {
    75                     THROW_EXCEPTION(NotEnoughMemoryException,"No Enough Memory to Resize Create DynamicList Objesct...");
    76                 }
    77             }
    78         }
    79 
    80     ~DynamicList()
    81         {
    82             delete[] this->m_array;
    83         }
    84     };
    85 }
    86 
    87 #endif // DYNAMICLIST_H

    测试

    #include <iostream>
    #include "staticlist.h"
    #include "Exception.h"
    #include "dynamiclist.h"
    
    using namespace std;
    using namespace DTLib;
    
    int main()
    {
      DynamicList<int> l(5);
    
      for(int  i=0;i<l.capacity(); i++)
      {
          l.insert(0,i);
      }
    
      for(int i=0;i<l.capacity();i++)
      {
          cout<<l[i]<<endl;
      }
      try
      {
          l[5]=9;
      }
      catch(const Exception& e)
      {
          cout<<e.message()<<endl;
          cout<<e.location()<<endl;
      }
        l.resize(3);
        for(int i=0;i<l.capacity();i++)
        {
            cout<<l[i]<<endl;
        }
        return 0;
    }

    其他几个设计代码

    List.h 

     1 #ifndef _LIST_H_
     2 #define _LIST_H_
     3 
     4 #include "Object.h"
     5 
     6 namespace DataStructureLib {
     7 
     8     template <typename T>
     9     class List : public Object
    10     {
    11     public:
    12         virtual bool insert(int index, const T& elem) = 0;
    13         virtual bool remove(int index) = 0;
    14         virtual bool get(int index, T& elem) const = 0;
    15         virtual int length() const = 0;
    16         virtual void clear() = 0;
    17     };
    18 
    19 }
    20 
    21 #endif // _LIST_H_
    View Code

    Seqlist.h 

    #ifndef _SEQLIST_H_
    #define _SEQLIST_H_
    
    #include "list.h"
    #include "Exception.h"
    
    namespace DataStructureLib {
    
        template <typename T>
        class SeqList : public List<T>
        {
        protected:
            T* m_array;    //顺序存储空间
            int m_length;  //当前线性表长度
        public:
            //插入元素
            bool insert(int index, const T &elem)
            {
                bool ret = ((0 <= index)&&(index <= m_length));
                ret = ret && (m_length < capacity());
    
                if(ret){
                    //将index及其之后的元素向后移动一个位置
                    for(int pos=m_length-1; pos>=index; pos--){
                        m_array[pos + 1] = m_array[pos];
                    }
                    //新元素插入在index位置
                    m_array[index] = elem;
                    m_length++;
                }
    
                return ret;
            }
    
            //删除元素
            bool remove(int index)
            {
                bool ret = ((0 <= index)&&(index < m_length));
    
                if(ret){
                    for(int pos=index; pos<m_length-1; pos++){
                        m_array[pos] = m_array[pos + 1];
                    }
    
                    m_length--;
                }
    
                return ret;
            }
    
            //设置元素
            bool set(int index, const T& elem)
            {
                bool ret = ((0 <= index)&&(index < m_length));
    
                if(ret){
                    m_array[index] = elem;
                }
    
                return ret;
            }
    
            //获取元素
            bool get(int index, T &elem) const
            {
                bool ret = ((0 <= index)&&(index < m_length));
    
                if(ret){
                    elem =  m_array[index];
                }
    
                return ret;
            }
    
            //当前长度
            int length()const
            {
                return m_length;
            }
    
            //清空线性表
            void clear()
            {
                m_length = 0;
            }
    
            //顺序存储线性表的数组访问方式
            T& operator[](int index)
            {
                if((0<=index) && (index<m_length)){
                    return m_array[index];
                }else{
                    THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter index is invalid ...");
                }
            }
    
            T operator [](int index) const
            {
                return (const_cast<SeqList<T>&>(*this))[index];
            }
    
            //顺序存储空间的容量
            virtual int capacity()const = 0;
        };
    
    }
    
    #endif // _SEQLIST_H_
    View Code

    object.h

     1 #ifndef OBJECT_H
     2 #define OBJECT_H
     3 
     4 
     5 namespace DataStructureLib
     6 {
     7 
     8     class Object
     9     {
    10     public:
    11         //以下四个重载函数用于统一不同编译器new失败时的结果不同的问题。
    12         //throw()表示不抛出异常,即如果申请内请失败时,统一返回NULL而不抛异常
    13         void* operator new(size_t size) throw();
    14         void operator delete(void* p);
    15 
    16         void* operator new[](size_t size) throw();
    17         void operator delete[](void* p);
    18 
    19         virtual  ~Object()=0;
    20     };
    21 }
    22 #endif // OBJECT_H
    View Code

    object.cpp 

    #include "object.h"
    #include "cstdlib"
    #include<iostream>
    
    using namespace std;
    namespace DataStructureLib
    {
    
    void* Object::operator new(size_t size) throw()
    {
        cout<<"Object::operator new : "<< size<<endl;
        return malloc(size);//这里的size代表申请内存空间的字节数
    }
    
    void Object::operator delete(void* p) 
    {
        cout<<"Object::operator delete : "<<p<<endl;
        
        free(p);
    }
    
    void* Object::operator new[](size_t size) throw()
    {
        cout<<"Object::operator new[]"<<endl;
    
        return  malloc(size);//此时的size代表申请对象的数量
    }
    
    void Object::operator delete[](void* p)
    {
        cout<<"Object::operator delete[]:"<<p<<endl;
        
        free(p);
    }
    
    Object::~Object()
    {
    
    }
    }
    View Code

    SmartPointer.h

    #ifndef _SMARTPOINTER_H_
    #define _SMARTPOINTER_H_ 
    #include<stdio.h >
    #include"object.h"
    namespace DataStructureLib
    {
    
    template<typename T>
    class SmartPointer:public Object
    {
        T* m_pointer;
    public:
        SmartPointer(T* pointer= NULL)
        {
            m_pointer=pointer;
        }
    
        SmartPointer(const SmartPointer<T>& obj)
        {
            m_pointer=obj.m_pointer;
            const_cast<SmartPointer<T>&>(obj).m_pointer=NULL;
        }
    
        SmartPointer& operator=(const SmartPointer<T>& obj)
        {
            if (m_pointer!=obj.m_pointer)
            {
                m_pointer=obj.m_pointer;
                const_cast<SmartPointer<T>&>(obj).m_pointer=NULL;
            }
        
            return *this;
        }
        
        T* operator ->()
        {
            return m_pointer;
        }
    
        T& operator *()
        {
            return *m_pointer;
        }
        
        bool isNull()
        {
            return (m_pointer==NULL);
        }
    
        T* get()
        {
            return m_pointer;
        }
    
        ~SmartPointer(void)
        {
            delete m_pointer;
        }
    };
    }
    #endif
    View Code

    Exception.h

    #ifndef _EXCEPTION_H_
    #define _EXCEPTION_H_ 
    #include"object.h"
    
    
    namespace DataStructureLib
    {
    #define THROW_EXCEPTION(e,m) throw e(m,__FILE__,__LINE__)
    
    class Exception:public Object
    {
    protected:
        char*  m_message;
        char*  m_location;
    protected:
        void  init(const char*,const char*,int);//由于三个构造函数中的逻辑很相似,所以可以将相似的部分统一放到一个函数init()
    public:
        Exception(const char* message); 
        Exception(const char* file,int line);
        Exception(const char* message,const char* file,int line);
    
        //涉及到堆空间即需进行深拷贝,拷贝构造函数和"="
        Exception(const Exception& e);
        Exception& operator =(const Exception& e);
    
        virtual const char* message() const;
        virtual const char* location() const;
    
        virtual ~Exception(void)= 0;
    };
    //计算异常类
    class ArithmeticException: public Exception
    {
    public:
        ArithmeticException():Exception(0){}
        ArithmeticException(const char* message):Exception(message){}
        ArithmeticException(const char*file, int line):Exception(file, line){}
        ArithmeticException(const char *message, const char* file, int line):Exception(message, file, line){}
    
        ArithmeticException(const ArithmeticException& e): Exception(e){}
        ArithmeticException& operator=(const ArithmeticException& e)
        {
            Exception::operator =(e);
    
            return *this;
        }
    };
    
    
    
    
    //空指针异常
    class NullPointerException: public Exception
    {
    public:
        NullPointerException():Exception(0){}
        NullPointerException(const char* message):Exception(message){}
        NullPointerException(const char*file, int line):Exception(file, line){}
        NullPointerException(const char *message, const char* file, int line):Exception(message, file, line){}
    
        NullPointerException(const NullPointerException& e): Exception(e){}
        NullPointerException& operator=(const NullPointerException& e)
        {
            Exception::operator =(e);
    
            return *this;
        }
    };
    
    //越界异常类
    class IndexOutOfBoundsException: public Exception
    {
    public:
        IndexOutOfBoundsException():Exception(0){}
        IndexOutOfBoundsException(const char* message):Exception(message){}
        IndexOutOfBoundsException(const char*file, int line):Exception(file, line){}
        IndexOutOfBoundsException(const char *message, const char* file, int line):Exception(message, file, line){}
    
        IndexOutOfBoundsException(const IndexOutOfBoundsException& e): Exception(e){}
        IndexOutOfBoundsException& operator=(const IndexOutOfBoundsException& e)
        {
            Exception::operator =(e);
    
            return *this;
        }
    };
    
    //内存不足异常类
    class NotEnoughMemoryException: public Exception
    {
    public:
        NotEnoughMemoryException():Exception(0){}
        NotEnoughMemoryException(const char* message):Exception(message){}
        NotEnoughMemoryException(const char*file, int line):Exception(file, line){}
        NotEnoughMemoryException(const char *message, const char* file, int line):Exception(message, file, line){}
    
        NotEnoughMemoryException(const NotEnoughMemoryException& e): Exception(e){}
        NotEnoughMemoryException& operator=(const NotEnoughMemoryException& e)
        {
            Exception::operator =(e);
    
            return *this;
        }
    };
    
    //参数错误异常类
    class InvalidParameterException: public Exception
    {
    public:
        InvalidParameterException():Exception(0){}
        InvalidParameterException(const char* message):Exception(message){}
        InvalidParameterException(const char*file, int line):Exception(file, line){}
        InvalidParameterException(const char *message, const char* file, int line):Exception(message, file, line){}
    
        InvalidParameterException(const InvalidParameterException& e): Exception(e){}
        InvalidParameterException& operator=(const InvalidParameterException& e)
        {
            Exception::operator =(e);
    
            return *this;
        }
    };
    
    }
    #endif
    View Code

     Exception.cpp

    #include "Exception.h"
    
    #include <cstring>
    #include <cstdlib>
    
    namespace DataStructureLib
    {
    void Exception::init(const char* message,const char* file,int line)
    {
        m_message=strdup(message);//这里不能直接使用m_message=message,
                                //因为message指针指向的数据有可能会在栈、堆、全局区,如果是在栈上,局部变量可能会消失,如果直接使用m_message=message就会不安全    
        if(file!=NULL)
        {
            char sl[16]={0};
            itoa(line,sl,10);//将line转为char类型 10代表十进制
    
            m_location=static_cast<char* >(malloc(strlen(file)+strlen(sl)+2));//加2表示后面的":"和结束符即“/0”
            m_location=strcpy(m_location,file);
            m_location=strcat(m_location,":");
            m_location=strcat(m_location,sl);
        }
    }
    
    Exception::    Exception(const char* message)
    {
        init(message,NULL,0);
    }
    
    Exception::Exception(const char* file,int line)
    {
        init(NULL,file,line);
    }
    
    Exception::Exception(const char* message,const char* file,int line)
    {
        init(message,file,line);
    }
    
    Exception::~Exception(void)
    {
        
        free(m_message);
        free(m_location);
    }
    
    const char* Exception::message() const
    {
        return m_message;
    }
    
    const char* Exception::location() const
    {
        return m_location;
    }
    
    Exception::Exception(const Exception& e)
    {
        m_message=strdup(e.m_message);
        m_location=strdup(e.m_location);
    }
    
    Exception& Exception::operator =(const Exception& e)
    {
        if (this!=&e)
        {
            free(m_message);
            free(m_location);
    
            m_message=strdup(e.m_message);
            m_location=strdup(e.m_location);
        }
        return *this;
    }
    
    }
    View Code
  • 相关阅读:
    day21
    day19
    【淘淘商城项目】jsonp解决ajax跨域问题
    【淘淘商城项目】商品规格参数的表结构设计
    打印日志的时机
    【javascript】call和apply的区别
    MySQL timestamp自动更新时间
    spring管理属性配置文件properties——PropertiesFactoryBean和PropertyPlaceholderConfigurer的区别
    【Maven】修改nexus默认的工作目录
    URIEncoding和UseBodyEncodingForURI的解释
  • 原文地址:https://www.cnblogs.com/zhaobinyouth/p/9568941.html
Copyright © 2020-2023  润新知