§1 线性表
§1.1 顺序表
§1.1.1 概览
顺序表就是把线性表中的所有表项按照其逻辑顺序依次存储到一块连续的存储空间中,通常用一维数组来实现。
顺序表的特点是:
- 在顺序表中,各项的逻辑顺序与其存放的物理顺序一致,即第
i
个项即为Array[i]
。 - 在顺序表中,可以进行顺序访问(即从表的第一项开始逐个访问),也可以随机访问(即按照项的下标进行访问)。
§1.1.2 类的定义与实现
顺序表可以用静态、动态形式进行存储,在此笔者使用了动态形式的存储。
注意到这里关键内容是:
- 内存的分配与释放
- 元素的插入
- 元素的删除
- 含有模板类的输出函数重载(详见链接)
// "SeqList.hpp"
#include <iostream>
#define DEFAULT_SIZE 50
using namespace std;
// Definition
template <class T>
class SeqList {
protected:
T *data;
// Mark the maximum size of the array and the location of last one
int maxSize, lastAddr;
public:
SeqList();
SeqList(int size);
SeqList(SeqList<T>& other);
~SeqList();
// Get the size
int getMaxSize() const;
// Get the location of last one
int getLastAddr() const;
// Find the location of x
int search(T& x);
// Get the value of data[i]
T getData(int i) const;
// Set the valud of data[i]
void setData(int i, T& x);
// insert or remove data[i]
bool insert(int i, T x);
bool remove(int i);
// Determine if it is empty
bool isEmpty();
// Output
friend ostream& operator<<(ostream& out, SeqList<T>& seqList) {
out << "[";
for(int i = 0; i < seqList.getLastAddr(); i++) {
out << seqList.getData(i);
if(i != seqList.getLastAddr()-1) {
out << ", ";
}
}
out << "]" << endl;
return out;
}
};
// Implement
template <class T>
SeqList<T>::SeqList() {
data = new T[DEFAULT_SIZE];
maxSize = DEFAULT_SIZE;
lastAddr = 0;
}
template <class T>
SeqList<T>::SeqList(int size) {
data = new T[size];
maxSize = size;
lastAddr = 0;
}
template <class T>
SeqList<T>::SeqList(SeqList<T>& other) {
this->data = new T[other.getMaxSize()];
this->maxSize = other.getMaxSize();
this->lastAddr = other.getLastAddr();
for(int i = 0; i < lastAddr; i++) {
this->data[i] = other.getData(i);
}
}
template <class T>
SeqList<T>::~SeqList() {
delete[] data;
}
template <class T>
int SeqList<T>::getMaxSize() const {
return maxSize;
}
template <class T>
int SeqList<T>::getLastAddr() const {
return lastAddr;
}
template <class T>
int SeqList<T>::search(T& x) {
for(int i = 0; i <= lastAddr; i++) {
if(data[i] == x) {
return i;
}
}
return -1;
}
template <class T>
T SeqList<T>::getData(int i) const {
// Have a potential exception
return data[i];
}
template <class T>
void SeqList<T>::setData(int i, T& x) {
// Have a potential exception
data[i] = x;
}
template <class T>
bool SeqList<T>::insert(int i, T x) {
if(lastAddr == maxSize-1) {
return false;
}
if(i < 0 || i > lastAddr) {
return false;
}
// Move back in turn to make room
for(int j = lastAddr; j >= i; j--) {
data[j+1] = data[j];
}
data[i] = x;
lastAddr++;
return true;
}
template <class T>
bool SeqList<T>::remove(int i) {
if(i < 0 || i > lastAddr) {
return false;
}
for(int j = i; j < lastAddr-1; j++) {
data[j] = data[j+1];
}
lastAddr--;
return true;
}
template <class T>
bool SeqList<T>::isEmpty() {
return !lastAddr;
}
测试代码:
#include <iostream>
#include "SeqList.hpp"
int main()
{
SeqList<int>* List = new SeqList<int>(10);
for(int i = 9; i >= 0; i--) {
List->insert(0, i);
}
cout << *List;
}
测试结果:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
§1.1.3 对顺序表优缺点的分析
- 优点
- 顺序表的结构简单
- 顺序表的存储效率高,是紧凑结构,无须为表示节点间的逻辑关系而增加额外的存储空间
- 顺序表是一个直接存取结构( 随机存储结构)
- 缺点
- 在顺序表中进行插入和删除操作时,需要移动数据元素,算法效率较低。
- 对长度变化较大的线性表,或者要预先分配较大空间或者要经常扩充线性表,给操作带来不方便。
§1.1.4 对顺序表的改进
- 增添改变data数组空间大小的函数
template <class T>
void SeqList<T>::reSize(int newSize) {
if(newSize < maxSize) {
cerr << "Invalid!!" << endl;
return;
}
if(newSize != maxSize) {
T* newArray = new T[newSize];
T* temp1 = data;
T* temp2 = newArray;
for(int i = 0; i <= lastAddr; i++) {
newArray[i] = data[i];
}
delete[] data;
// Point the data to the new array
data = newArray;
maxSize = newSize;
}
}
- 添加异常处理
略