数据结构之线性表—数组描述
前面我写了几节二叉树,现在想想还是回过头来吧线性表写了
概述
C++里提供了强大的STL(标准模板库),而且很多大神和相关书籍多提倡我们使用STL,切勿盲目自己写,这样反而效率更低。但是在使用STL的同时,能够了解如何实现简单的STL是很爽的。
C++程序常用的数据描述方式是数组描述和链式描述,而线性表可以用来说明这两种方法。STL容器大致相当于线性表的数组描述方式和链式描述方式,当然STL还有很多其他的方法,这里就不介绍了。
线性表
线性表也叫作有序表,它的每一个实例都是元素的一个有序集合
数组描述
当我们在写数据结构的时候我们首先想到可能是如何创建,然后是它有什么操作。
创建 : 因为是利用数组来存储元素,用的也是数组类型
当创建好一个线性表的时候,它应该有如下操作:
- 向线性表添加元素
- 销毁一个线性表
- 判断线性表是否为空
- 确定线性表的长度
- 按给定的索引查找一个元素
- 安给定的元素查找第一个出现该元素的索引
- 按给定的索引插入一个元素
- 从左到右顺序输出线性表元素
….
也有人说是不是操作过多,放在同一个类里,会不会造成代码太复杂,拥挤,这里我们不考虑这些,只是单纯的实现这些操作
类arrayList的创建
class arrayList
{
public:
arrayList(int initialCapacity = 10);
arrayList(const arrayList<T>& theList);
~arrayList() { delete[] element; element = 0;}
//ADT实现
void add(T theElement); // 向尾部添加元素
bool empty() const { return listSize == 0; } // 判断是否为空
int size() const {return listSize;}; // 返回数组中元素的个数
T& get(int theIndex) const; // 根据索引获取元素
int indexof(const T& theElemet) const; // 返回数组中第一个出现的下标
void erase(int theIndex); // 删除操作
void insert(int theIndex, T& theElemet); // 插入操作
void output() const; // 输出操作
bool equal(const arrayList<T>& theList) const; // 判断两个线性表是否相等
// 返回链表中可以放置的元素个数
int Capacity() {
return arrayLength;
}
// 倍增数组
void changeLengthlD(T* &a, int oldLength, int newLength);
private:
// 检查下标是否过界
bool CheckIndex(int theIndex)
{
if(theIndex <0 || theIndex > arrayLength)
return false;
return true;
}
T* element; // 存储一元数组的容器
int arrayLength; // 一维数组的容量
int listSize; // 线性表的元素个数
};
注:由于这里用到了模板类所以特意提醒下
《C++编程思想》里说道,模板定义很特殊。由template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。
类的具体实现
template <typename T>
arrayList<T>::arrayList(int initialCapacity)
{
if(initialCapacity < 1)
// throw "The initialCapacity must be > 0";
initialCapacity = 10; // default 10
arrayLength = initialCapacity;
element = new T[initialCapacity];
listSize = 0;
}
template <typename T>
arrayList<T>::arrayList(const arrayList<T>& theList)
{
arrayLength = theList.arrayLength;
listSize = theList.listSize;
element = new T[arrayLength];
for(int i = 0 ; i < listSize; i++)
element[i] = theList[i];
}
template <typename T>
void arrayList<T>::add(T theElement)
{
if(listSize < arrayLength)
{
element[listSize] = theElement;
listSize++;
}
else
{
changeLengthlD(element, arrayLength, 2*arrayLength);
element[listSize] = theElement;
listSize++;
}
}
template <typename T>
T& arrayList<T>::get(int theIndex) const
{
if(theIndex < 0 || theIndex > listSize)
{
return element[-1];
}
return element[theIndex];
}
template <typename T>
int arrayList<T>::indexof(const T& theElemet) const
{
for(int i = 0; i < listSize; i++)
{
if(theElemet == element[i])
return i;
}
return -1;
}
template <typename T>
void arrayList<T>::erase(int theIndex)
{
if(theIndex < 0 || theIndex > listSize)
{
return ;
}
copy(element + theIndex + 1, element + listSize, element + theIndex);
listSize--;
}
template <typename T>
void arrayList<T>::insert(int theIndex, T& theElemet)
{
if(theIndex < 0 || theIndex > listSize)
{
return;
}
if(listSize == arrayLength)
{
int newLength = 2*arrayLength;
changeLengthlD(element, arrayLength, newLength);
}
copy(element + theIndex, element + listSize, element + theIndex + 1);
element[theIndex] = theElemet;
listSize++;
}
template <typename T>
void arrayList<T>::output() const
{
for(int i = 0; i < listSize; i++)
cout << element[i] << ' ';
cout << endl;
}
template <typename T>
void arrayList<T>::changeLengthlD(T* &a, int oldLength, int newLength)
{
T* temp = new T[oldLength];
for(int i = 0; i < listSize; i++)
{
temp[i] = a[i];
}
delete[] a;
a = new T[newLength];
arrayLength = newLength;
for(int i = 0; i < listSize; i++)
{
a[i] = temp[i];
}
}
template <typename T>
bool arrayList<T>::equal(const arrayList<T>& theList) const
{
if(listSize != theList.listSize)
return false;
if(arrayLength != theList.arrayLength)
return false;
bool equal = true;
for(int i = 0; i < listSize; i++)
{
if(element[i] != theList.element[i])
{
equal = false;
break;
}
}
return equal;
}
实现的代码都是很简单的,这里主要讲下本文插入元素和删除元素中的思路,在代码中我们用到了copy函数,这里假设数组元素为: 1, 2, 3, 4, 5 ,6, 7, 8
当我们在元素’4’的后面插入一个’0’,’4’之后的每一个元素都要顺序往后面移一位,copy()在这时就简化了代码量。
( 其中copy的定义OutputIt copy( InputIt first, InputIt last, OutputIt d_first )
)
Vector简单描述
vector是STL提供的一个基于数组的类,他不仅包含了上述介绍的全部方法,还增加了很多其它的方法,有兴趣的可以自己去看文档。例如:它没有get,而与之相应的是operator[](当然还有其他的), 。
数组描述的优缺点
数组描述的优点在于令人满意的时间性能
数组描述的缺点是空间利用率低,如果造成内存不足,可能是动态数组空间分配失败或者数组长度倍增失败所致。
友情链接: 数据结构之线性表—数组描述