数据对象和数据结构
数据对象
数据对象是一组实例值,例如:
boollean={false,true}
digit={1,2,3,4,5,6,7,8,9}
letter={A,B,C,D,E,F,G,H,I,…,Z}
boollean,digit,letter这些都是数据对象,在每个数据对象中,比如在boollean中有true和false两个实例;而0,1,2,…,9是digit的实例。数据对象的实例要么是一个不可再分的“原子”要么是另一个数据对象的实例作为成员符合而成。对于后一种情景,用元素来表示这些成员。
比如数据对象string是由所有可能的串实例组成的集合。每一个实例都由字符组成。例如:good,a trip to Hawaii,going down hill,abcdouwcoadc都是串实例。第一个串由4个元素组成,每一个元素都是数据对象letter的实例。
数据结构
数据结构是一个数据对象,同时,这个对象的实例以及构成实例的元素都存在着联系,而且这些联系由相关的函数来规定。。
研究数据结构,关心的是数据对象(实际上是实例)的描述以及相关函数的具体实现。数据对象描述的好,函数的实现救回高效。
常用的数据对象以及操作都在C++中最为基本数据类型而实现,如整数对象(int)、布尔对象(bool)等。
线性表数据结构
线性表,也称有序表,它的每一个实例都是元素的一个有序集合。每一个实例的形式为(e0,e1,e2,e3…,en-1)其中n为又穷的自然数,ei是线性表的元素,i是元素ei的索引,n是线性表的长度和大小。元素可以被看作原子,他们本身的结构和线性表的结构无关。当n等于0的时候线性表为空;n>0的时候,e0是线性表的第0个元素或首元素,en-1是线性表的最后一个元素。可以认为e0先于e1…除了这种先后关系,线性表不再有其它关系。
对于一个线性表,我们要设计一些函数完成对线性表和线性表中元素的操作。下面列举一些线性表操作:
A 创建一个线性表
B 撤销一个线性表
C 确定线性表是否为空
D 确定线性表长度
E 按一个给定的索引查找一个元素
F 安一个元素查找其索引
G 安一个给定的索引删除一个元素
H 从左至右输出线性表元素
抽象数据类型
一个线性表可以用一个抽象数据类型来说明,既说明他的实例也说明对它的操作。
#include<iostream>
using namespace std;
teemplate<class T>
class linearList
{
public:
virtual ~linearList(){ };
virtual bool empty() const = 0;//返回true线性表为空
virtual int size() const = 0;//返回线性表元素个数
virtual T& get(int theIndex) const = 0;//返回索引为theIndex的元素
virtual int indexOf(const T& theElement) const = 0;//返回theElement第一次出现时的索引
virtual void erase(int theIndex) = 0;//删除索引为theIndex的元素
virtual void insert(int theIndex,const T& theElement) = 0;//把 theElement插入到线性表中索引为theIndex的位置上
virtual void output(ostream& out) const = 0;//把线性表插入到输出流
};
数组描述
描述
在数组描述中,用数组来储存线性表中的元素。我们用一个数组来储存一个数据对象的实例。
因此,我们需要一个映射使线性表的一个元素对应数组的一个位置。
location(i)=i;
上面公式:第i个线性表的元素在数组中储存的位置是i,(把线性表的一个位置i 带入到location函数中,算出线性表中这个元素在数组中所在的位置。)
location(i)=(location(0)+i)%arrayLength ;
上面公式表示的是线性表中的第i个元素带入到location函数中生成元素在数组中所在的位置。
比如:arrayLength为10, location(0)=7,
location(i)=(7+i)%10,所以线性表中第零号元素在数组中为第七号元素。(由这个公式可以生成一个首尾相接的环形数组)
变长一维数组
#include<iostream>
using namespace std;
void changeLength(T*& a,int oldLength,int newLength)
{
if(newLength<0)
{
cerr<<"new length must >= 0 "<<endl;
}
T* temp = new T[newLength];
int number = min(oldLength,newLength);
copy(a,a+oldLength,temp);
delete [] a;
a=temp;
}
上面代码需要注意的是在函数定义中:T*&是指针引用类型,必须要用该类型,否则在函数中改变的数组不会继承到原数组中(关于这个问题我会单独写一篇博文进行解释)。其他的都还比较好理解。
类arrayList
我们定义一个抽象类linearList的派生类ArrayList,它利用公式实现抽象数据类型linearList。所以ArrayList中必须包含实现抽象类linearList的全部办法。不仅如此,它还应该包含基类linearList没有声明的方法,例如capacity,checkIndex。方法checkIndex是给出数字当前额长度,而方法checkIndex是确定元素在范围内的索引。
下面展示一些 内联代码片
。
#include<iostream>
using namespace std;
template<class T>
class arrayList:public linearList<T>
{
public:
arrayList(int initialCapacity = 10);
arrayList(const arrayList<T> &);//复制构造函数
~arrayList() {delete [] Element;}
//ADT方法
bool empty() const {return listSize == 0;}
int size() const{return listSize;}
T& get(int theIndex) const;
int indexOf(const T& theElement) const;
void erase(int theIndex);
void insert(int theIndex,const T& theElement);
void output(ostream& out) const;
int capacity() const {return arrayLength;}
protected :
void checkIndex(int theIndex) const;
//若索引无效,则抛出异常
T* Element;//储存线性表的一维数组
int arrayLength;//一维数组容量
int listSize; //线性表的元素个数
};
类arrayList 的构造函数和复制构造函数
template<class T>
arrayList<T>::arrayList(int initialCapacity)
{//构造函数
if(initialCapacity<1)
{
ostringstream s;
s<<"Initial capacity = "<<initialCapacity<<"Must be > 0";
throw illegalParameterValue(s.str());
}
arrayLength = initialCapacity;
Element = new T[arrayLength] ;
listSize = 0;
}
template <class T>
arrayList<T>::arrayList(const arrayList<T>& theList)
{//复制构造函数
arrayList = theList.arrayLength;
listSize = theList.listSize;
Element = new T[arrayList];
copy(theList.Element,theList.Element+listSize,Element);
}
arrayList 的实例化
用数组描述的线性表需要使用下面的语句来创建
linearList *x=(linearList)new arrayList<int>(100);
或者
arrayList<double> y(100);
//利用容量的缺省值创建一个线性表
arrayList<char> z;
//利用线性表y,复制创建一个线性表
arrayList<double> w(y);
arrayList的基本方法
checkIndex:确定索引在【0,listSize-1】之间
get:返回索引值为theIndex的元素
indexOf:返回元素theElement第一次出现的索引值。
下面展示一些 内联代码片
。
template<class T>
void arrayList<T>::checkIndex(int theIndex) const
{//确定索引 theIndex在0和listSize-1之间
if(theIndex < 0||theIndex >= listSize)
{
cout<<"the Index is not leagal"<<endl;
}
}
template<class T>
T& arrayList<T>::get(int theIndex) const
{//返回索引值为theIndex的元素
checkIndex(theIndex);
return Element[theIndex];
}
template<class T>
int arrayList<T>::indexOf(const T& theElement) const
{
//返回元素第一次出现时的索引
//若元素不存在,则返回-1;
//查找元素theElement;
int theIndex = (int)(find(element,element+listSize,theElement)-Element);
if (theElement == listSize) return -1;
else return theIndex;
}
删除一个元素或插入一个元素
#include<iostream>
using namespace std;
template<class T>
void arrayList<T>::erase(int theIndex)
{
checkIndex(theIndex);
copy(Element+theIndex+1,Element+listSize,Element + theIndex);
Element[--listSize].~T();
}
#include<iostream>
using namespace std;
template <class T>
void arrayList<T>::(int theIndex,const T& theElement)
{
if(theIndex < 0||theIndex > listSize)
{
cout<<"error";
}
if(listSize == arrayLength)
{
changeLength1D(Element,arrayLength,2*listSize);
arrayLength *=2;
}
copy_backward(Element + theIndex,Element + listSize,Element + listSize + 1);
Element[theIndex] = theIndex;
listSize++;
}';
把一个线性表插入输出流
下面展示一些 内联代码片
。
#include<iostream>
using namespace std;
template <class T>
void arrayList<T>::output(cout->out) const
{
copy(Element,Element+listSize,ostream_iterator<T>(cout," "));
}
//重载<<
template <class T>
ostream& operator<<(ostream& out,const arrayList<T>& x)
{
x.output(out);return out;
}
c++迭代器
一个迭代器是一个指针,指向对象的一个元素。顾名思义,一个迭代器可以用来逐个访问对象的所有元素。
#include<iostream>
using namespace std;
int main()
{
int a[3]={2,3,4};
for(int* p=a;p!=a+3;p++){
cout<<(*p)<<" ";
}
return 0 ;
}