14、静态数据结构和动态数据结构

线性表(list)的表现形式:零个或多个数据元素组成的集合,数据元素在位置上是有序列的,数据元素的个数是有限的,数据元素的类型必须相同。

线性表的抽象定义:线性表是具有相同类型的n个数据元素的有限序列,每一个叫表项,n是表长度

纯虚函数的作用:为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。在很多情况下,基类本身生成对象是不合理的,例如,动物作为一个基类派生出老虎狮子等,但动物本身生成对象不合理。为了解决上述问题,引入纯虚函数的概念,将函数定义为纯虚函数,则编译器要求再派生类中必须予以重写以实现多态性,同时含有纯虚函数的类称为抽象类,它不能生成对象。这样就很好的解决了上述两个问题。

//模板的方式描述线性表,不要List.cpp
#ifndef LIST_H_
#define LIST_H_
#include "Wobject.h"
namespace WSlib
{
template <typename T>
class List:public Wobject
{
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)=0;
virtual int length()const =0;
virtual void clear()=0;
};
}
#endif
//线性表是数据元素的有序并且有限的集合,线性表中的数据元素必须是类型相同的,可用于描述排队关系的问题
//线性表在c++中表现为一个抽象类
//线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表中的数据元素
//可以用一维数组来实现顺序存储结构,存储空间:T* m_array: 当前长度:int m_length;
//顺序存储结构的元素获取操作:判断目标位置是否合法,将目标位置作为数组下标获取元素
//顺序表的插入操作:1、判断目标位置是否合法2、将目标位置之后的所有元素后移一个位置3、将新元素插入目标位置4、线性表长度加1
//顺序存储结构的元素删除操作:1、判断目标位置是否合法2、将目标位置后的所有元素前移一个位置3、将线性表长度减一
//完成顺序存储结构线性表SeqList的抽象实现,设计要点:

//抽象类模板,存储空间的位置和大小由子类完成,实现顺序存储结构线性表的关键操作(增,删,查),提供数组操作符,快速访问数据

#ifndef SEQLIST_H_
#define SEQLIST_H_
#include "List.h"
#include "Exception.h"
namespace WSlib
{
template<typename T>
class SeqList:public List<T>
{
protected:
T* m_array;  //顺序存储空间
T m_length;  //当前线性表长度
public:
bool insert(int i,const T& e)
{
bool ret=((0<=i)&&(i<=m_length)); //注意这里是《=  而之后的是<
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++;
}
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=((i>=0)&&(i<m_length));
if(ret)
{
m_array[i]=e;
}
return ret;
}
bool get(int i,T& e)
{
bool ret=((i>=0)&&(i<m_length));
if(ret)
{
e=m_array[i];
}
return ret;
}
    int length()const 
{
return m_length;
}


    void clear()
{
m_length=0;
}
//顺序存储线性表的数组访问方式
T& operator[](int i)
{
if((0<=i)&&(i<m_length))   //没有等于 mmp
{
return m_array[i];
}
else
{
THROW_EXCEPTION(IndexOutOfBoundsException, "parameter is invald....");
}
}


/* T& operator[](int i) const
{
return (const_cast<SeqList<T>&>(*this))[i];
//return (*this)[i];
}*/
//顺序存储空间的容量
virtual int capacity()const=0;  //获取最大容量,纯虚函数交给子类完成
};
}
#endif
/********************************************************************************
#include<iostream>
#include"SeqList.h"
using namespace std;
using namespace WSlib;

int main()
{
SeqList<int>* l;

return 0;
}

**********************************************************************************/

//SeqList仅仅把关键的操作实现了,顺序存储空间的指定在它的子类实现
//思考StaticList和Dynaminlist如何实现,差异在哪里?
//StaticList设计要点:类模板,使用原生数组作为顺序存储空间,使用模板参数决定数组大小
#ifndef STATICLIST_H_
#define STATICLIST_H_
#include "SeqList.h"
namespace WSlib
{
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_array=m_space;
this->m_length=0;      //this->m_length=0;
}
int capacity() const   //成员函数需要考虑一下是否是const属性
{
return N;
}
};
}
#endif
/*************************************************************************
#include<iostream>
#include"StaticList.h"
using namespace std;
using namespace WSlib;

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(const Exception&e)
{
cout<<e.message()<<endl;
cout<<e.location()<<endl;
}
return 0;
}

*************************************************************************/

/*
设计要点:类模板
申请连续堆空间作为顺序存储空间,动态设置顺序存储空间的大小,保证重置顺序存储空间时的异常安全性
函数异常安全的概念:不泄漏任何资源,不允许破坏数据。
函数异常安全的基本保证:如果异常被抛出,对象内的任何成员任然能保持有效状态,没有数据的破坏及资源泄漏
*/
#ifndef DYNAMICLIST_H_
#define DYNAMICLIST_H_
#include "SeqList.h"
namespace WSlib
{
template <typename T>
class DynamicList:public SeqList<T>
{
protected:
int m_capacity; //顺序存储空间的大小
public:
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...");
}

}
int capacity() const
{
return m_capacity;
}
//重新设置顺序存储空间的大小
void resize(int capacity)
{
if(m_capacity!=capacity)
{
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;
this->m_array=array;
this->m_length=length;
this->m_capacity=capacity;
delete[] temp;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"no memory to create dynamiclist object");
}
}
/*我们要重置空间大小,但是之前的数据不能丢失,如果之前是5,resize为3,前三个数据要保留下来,
m_array指向之前的空间,delete的时候可能调用析构函数的调用,因为泛指类型,如果是类类型抛出一个异常,
函数异常返回,则下面的赋值操作无法执行,不是异常安全的,先用temp指向之前的空间,3条赋值语句不会发生异常,
然后在delete,即使发生异常,赋值已经完成,还是可以用的,for循环里边的赋值操作有可能发生异常,泛指类型T导致的,交由第三方工程师处理*/
}
~DynamicList() //归还空间
{
delete[] this->m_array;
}
};
}

#endif

/*************************************************************************************************************
#include<iostream>
#include"DynamicList.h"
using namespace std;
using namespace WSlib;
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(const 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;
}
//是否可以将dynamiclist作为staticlist的子类实现,不能,反之也不能,两个类对顺序存储空间的指定是截然不同的,
//没有关系,所以在类层次结构的地位是平等的。staticlist通过模板参数定义顺序存储空间,
//dynamiclist通过动态内存申请定义顺序存储空间,支持动态重置顺序存储空间的大小,resize的实现需要保证异常安全
*************************************************************************************************************/

静态数据结构,例如数组在内存中是连续的存储区域,缺点是长度是固定的,新增或删除某一数据花费的时间比较多。优点可以直接访问各个数据,各个数据的地址都可以根据首地址得到,访问时间复杂度O(1)。

动态数据结构,例如链表在内存中不是连续的存储区域,每一个节点包含节点数据和下一个节点的指针。缺点是不利于节点的随机访问。访问节点花费时间比较多,为O(n)。优点是能够动态的调整容量,插入或者删除数据方便。


  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值