线性表的数据结构
线性表应该实施下列操作:
- 创建一个线性表
- 撤销一个线性表
- 确定线性表是否为空
- 确定线性表的长度
- 按一个给定的索引查找一个元素
- 按一个给定的元素查找其索引
- 按一个给定的索引删除一个元素
- 按一个给定的索引插入一个元素
- 从左至右顺序输出线性表元素
线性表的抽象类
template<class T>
class linearList
{
public:
virtual ~linearList(){};
//判断线性表是否为空
virtual bool empty() const = 0;
//计算线性表元素个数
virtual int size() const = 0;
//返回索引为theIndex的元素
virtual T& get(int theIndex) const = 0;
//返回元素theElement第一次出现时的索引
virtual int indexOf(const T& theElement) const = 0;
//删除索引为theIndex的元素
virtual void erase(int theIndex) = 0;
//把元素theElement插入到索引为theIndex的位置
virtual void insert(const T& theElement,int theIndex) = 0;
//把线性表插入输出流out
virtual void output(ostream out) const = 0;
}
数组描述
要创建一个数组类。以实现抽象数据类型linearList,必须首先选择数组element的类型和数组长度。
解决第一个问题可以通过使用模板类。
解决第二个问题可以使用动态数组。首先估计一个初始数组长度,然后在数组空间不足的情况下,动态的增加数组长度。
当数组满而需要增大数组长度时,数组长度常常是要加倍的。这个过程称为数组倍增。(array doubling)。数组倍增的时间,从渐进意义上考量,不会大于元素插入的总时间。
//变长数组实现
template<class T>
void changeLength1D(T*& a,int oldLength,int newLength)
{
if(newLength<0)
cout<<"the length should > 0"<<endl;
T* temp = new T[newLength];
int number = min(oldLength,newLength);//需要复制的元素个数
copy(a,a+number,temp);
delete [] a;//释放老数组的内存空间
a = temp;
}
.定义一个C++抽象类linearList的派生类arrayList。arrayList是一个具体的类,实现了抽象类linearList的所有方法,并且还有arrayList中没有的方法,比如capacity()和checkindex()。
//具体类arrayList的实现
template<class T>
class arrayList:public linearList<T>//尖括号中的类型规定了linearList只能
//保存T类型的数据
{
public:
arrayList(int initialCapacity = 10);//构造函数
arrayList(const arrayList<T>&);//复制构造函数
~arrayList(){delete [] element;}//析构函数
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;
//若索引theIndex无效,则抛出异常
T* element;//存储线性表元素的一维数组
int arrayLength;//一维数组的容量
int listSize;//线性表的元素个数
}
下面是具体类中函数的具体实现:
//arrayList的构造函数
template<class T>
arrayList<T>::arrayList(int initialCapacity)
{
if(initialCapacity < 1)
cout<<"数组为空"<<endl;
arrayLength = initialCapacity;
element = new T[arrayLength];
listSize = 0;
}
//复制构造函数
template<class T>
arrayList::arrayList(const arrayList<T>& theList)
{
arrayLength = theList.arrayLength;
element = new T[arrayLength];
copy(theList.element,theList.element+listSize,element);
}
//erase()函数的实现
template<class T>
void arrayList::erase(int theIndex)
{
checkIndex(theIndex);//先判断元素是否存在
//移动索引theIndex之后的所有元素
copy(element+theIndex+1,element+listSize,element+theIndex);
element[--listSize].~T();//调用析构函数
}
//在索引为theIndex的位置插入元素theElement
template<class T>
void arrayList::insert(int theIndex,T& theElement)
{
if(theIndex < 0 || theIndex > listSize)
cout<<"元素索引不在合理范围内!"<<endl;
//索引有效,确定数组是否已满
if(listSize ==arrayLength)
changeLength1D(element,arrayLength,2*arrayLength);
arrayLength *= 2;
copy_backward(element+theIndex,element+theList,element+listSize+1);
element(theIndex) = theElement;
listSize++;
}
//checkIndex()方法实现
template<class T>
void arrayList<T>::checkIndex(int theIndex) const
{
if(theIndex < 0 || theIndex >= listSize)
cout<<"提供的索引不在合理范围内!"<<endl;
}
//get()方法实现
template<class T>
T& arrayList<T>::get(int theIndex) const
{
checkIndex(theIndex);
return element[theIndex];
}
//indexOf()函数实现
template<class T>
int arrayList<T>::indexOf(const T& theElement) const
{
//查找元素theElement
int theIndex = (int)(find(element,element+listSize,theElement)-element);
//确定元素theElement是否找到
if(theIndex == listSize)
return -1;
else
return theIndex;
}
//erase()函数的实现
template<class T>
void arrayList::erase(int indexOf)
{
checkIndex(theIndex);
copy(element+theIndex+1,element+listSize,element+theIndex);
element[--listSize].~T();
}
//insert()函数的实现
void arrayLength::insert(int theIndex,const T& theElement)
{
if(theIndex < 0 || theIndex >= listSize)
cout<<"索引范围不合法"<<endl;
if(listSize == arrayLength)
{
changeLength1D(element,arrayLength,2*arrayLength);
arrayLength*=2;
}
copy_backward(element+theIndex,element+listSize,element+listSize+1);
element[theIndex] = theElement;
listSize++;
}
以下是可以在Qt5.1中成功运行的完整代码(windows平台):
在Mac平台报错:linker command line with exit code 1(use -v to see invocation)
Mac中的这种报错,网上有很多教程,我试了几种,都没有用。by the way,我在Mac上的使用clang编译。先放着吧,这问题以后再解决:
#include<iostream>
#include<stdlib.h>
#include<algorithm>
using namespace std;
//改变一个一维数组的长度
template<class T>
void changeLength1D(T*& a,int oldLength,int newLength)
{
if(newLength >= 0)
{
T* temp = new T[newLength];
int number = min(oldLength,newLength);//需要复制的元素个数
copy(a,a+number,temp);
delete [] a;//释放老数组的内存空间
a = temp;
}
}
int min(int a,int b)
{
if(a >= b)
return b;
else
return a;
}
/*
* 一个线性表的抽象类
*/
template<class T>
class linearList
{
public:
virtual ~linearList(){};
virtual bool empty() const = 0;
virtual int size() const = 0;
virtual T& get(int theIndex) const = 0;
virtual int indexOf(const T& theElement) const = 0;
virtual void erase(int theIndex) = 0;
virtual void insert(int theIndex,const T& theElement) = 0;
virtual void output(ostream& out) const = 0;
};
/*
* 线性表具体类的定义
* 类名:arrayList
*/
template<class T>
class arrayList : public linearList<T>
{
public:
//构造函数
arrayList(int initialCapacity = 10);
//复制构造函数
arrayList(const arrayList<T>&);
//析构函数
~arrayList();
//具体函数声明
bool empty() const;
int size() const;
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;
protected:
bool checkIndex(int theIndex) const;
T* element;
int listSize;
int arrayLength;
};
/*
* 具体类中的函数具体实现
*/
//构造函数
template<class T>
arrayList<T>::arrayList(int initiaCapacity)
{
if(checkIndex(initiaCapacity))
{
arrayLength = initiaCapacity;
element = new T[arrayLength];
listSize = 0;
}
}
//复制构造函数
template<class T>
arrayList<T>::arrayList(const arrayList<T>& theList)
{
arrayLength = theList.arrayLength;
listSize = theList.listSize;
element = new T[arrayLength];
copy(theList.element,theList.element+listSize,element);
}
//析构函数
template<class T>
arrayList<T>::~arrayList()
{
delete [] element;
}
//bool empty()
template<class T>
bool arrayList<T>::empty()const
{
return listSize == 0;
}
//int size()
template<class T>
int arrayList<T>::size() const
{
return listSize;
}
//T& get()
template<class T>
T& arrayList<T>::get(int theIndex) const
{
if(checkIndex(theIndex))
{
return element[theIndex];
}
}
//int indexOf()
template<class T>
int arrayList<T>::indexOf(const T &theElement) const
{
int theIndex = (int)(find(element,element+listSize,theElement)-element);
if(theIndex == listSize)
return -1;
else
return theIndex;
}
//void erase()
template<class T>
void arrayList<T>::erase(int theIndex)
{
if(checkIndex(theIndex))
{
copy(element+theIndex+1,element+listSize,element+theIndex);
element[--listSize].~T();//调用析构函数
}
}
//void insert()
template<class T>
void arrayList<T>::insert(int theIndex, const T &theElement)
{
if(checkIndex(theIndex))
{
if(listSize == arrayLength)
{
//数组空间已满,数组长度倍增
changeLength1D(element,arrayLength,2*arrayLength);
arrayLength *= 2;
}
//把数组向右移动一个位置
copy_backward(element+theIndex,element+listSize,element+listSize+1);
element[theIndex] = theElement;
listSize++;
}
}
//核对元素索引是否合法
template<class T>
bool arrayList<T>::checkIndex(int theIndex) const
{
if(theIndex<0 || theIndex >= listSize)
return false;
else
return true;
}
//output(ostream& out)
template<class T>
void arrayList<T>::output(ostream &out) const
{
for(int i = 0;i<listSize;i++)
out<<element[i]<<" ";
}
//重载<<
template<class T>
ostream& operator<<(ostream& out,const arrayList<T>& x)
{
x.output(out);
return out;
}
//int capacity() const;
template<class T>
int arrayList<T>::capacity()const
{
return arrayLength;
}
int main(void)
{
// test constructor
linearList<double> *x = new arrayList<double>(20);
arrayList<int> y(2), z;
// test capacity
cout << "Capacity of x, y and z = "
<< ((arrayList<double>*) x)->capacity() << ", "
<< y.capacity() << ", "
<< z.capacity() << endl;
// test size
cout << "Initial size of x, y, and z = "
<< x->size() << ", "
<< y.size() << ", "
<< z.size() << endl;
// test empty
if (x->empty()) cout << "x is empty" << endl;
else cout << "x is not empty" << endl;
if (y.empty()) cout << "y is empty" << endl;
else cout << "y is not empty" << endl;
// test insert
y.insert(0, 2);
y.insert(1, 6);
y.insert(0, 1);
y.insert(2, 4);
y.insert(3, 5);
y.insert(2, 3);
cout << "Inserted 6 integers, list y should be 1 2 3 4 5 6" << endl;
cout << "Size of y = " << y.size() << endl;
cout << "Capacity of y = " << y.capacity() << endl;
if (y.empty()) cout << "y is empty" << endl;
else cout << "y is not empty" << endl;
y.output(cout);
cout << endl << "Testing overloaded <<" << endl;
cout << y << endl;
// test indexOf
int index = y.indexOf(4);
if (index < 0) cout << "4 not found" << endl;
else cout << "The index of 4 is " << index << endl;
index = y.indexOf(7);
if (index < 0) cout << "7 not found" << endl;
else cout << "The index of 7 is " << index << endl;
// test get
cout << "Element with index 0 is " << y.get(0) << endl;
cout << "Element with index 3 is " << y.get(3) << endl;
// test erase
y.erase(1);
cout << "Element 1 erased" << endl;
cout << "The list is " << y << endl;
y.erase(2);
cout << "Element 2 erased" << endl;
cout << "The list is " << y << endl;
cout << "Size of y = " << y.size() << endl;
cout << "Capacity of y = " << y.capacity() << endl;
if (y.empty()) cout << "y is empty" << endl;
else cout << "y is not empty" << endl;
// test copy constructor
arrayList<int> w(y);
y.erase(0);
y.erase(0);
cout << "w should be old y, new y has first 2 elements removed" << endl;
cout << "w is " << w << endl;
cout << "y is " << y << endl;
// a few more inserts, just for fun
y.insert(0,4);
y.insert(0,5);
y.insert(0,6);
y.insert(0,7);
cout << "y is " << y << endl;
cout<<"Hello World!"<<endl;
return 0;
}