线性表是一种最基本、最简单的数据结构,数据元素之间仅具有单一的前驱和后继关系。
顺序表
① 采用静态分配方式
采用C++的模板机制定义模板类SeqList。
const int MaxSize = 100; // 根据实际问题具体定义
template<typename DataType> // 定义模板类SeqList
class SeqList{
public:
SeqList(); // 建立空的顺序表
SeqList(DataType a[],int n); // 建立长度为n的顺序表
~SeqList(){} // 析构函数
int Length(); // 求线性表的长度
DataType Get(int i); // 按位查找,查找第i个元素的值
int Locate(DataType x); // 按值查找,查找值为x的元素序号
void Insert(int i,DataType x); // 插入操作,在第i个位置插入值为x的元素
DataType Delete(int i); // 删除操作,删除第i个元素
bool Empty(); // 判断线性表是否为空
void PrintList(); // 遍历操作,按序号依次输出各元素
private:
DataType data[MaxSize]; // 存放数据元素的数组
int length; // 线性表的长度
};
1.无参构造函数
template<typename DataType>
SeqList<DataType>::SeqList(){
length = 0;
}
2.有参构造函数
template<typename DataType>
SeqList<DataType>::SeqList(DataType a[],int n){
if (n > MaxSize)
throw "illegal parameter";
for (int i=0; i<n; i++)
data[i] = a[i];
length = n;
}
3.判空操作
template<typename DataType>
bool SeqList<DataType>::Empty(){
return length==0?true:false;
}
4.求顺序表的长度
template<typename DataType>
int SeqList<DataType>::Length(){
return length;
}
5.遍历操作
template<typename DataType>
void SeqList<DataType>::PrintList(){
for (int i=0; i<length; i++){
cout << data[i] << "\t";
}
cout << endl;
}
6.按位查找 O(1)
template<typename DataType>
DataType SeqList<DataType>::Get(int i){
// 按位查找,时间复杂度为O(1)
if (i<1 || i>length)
throw "illegal search location";
else
return data[i-1];
}
7.按值查找 O(n)
template<typename DataType>
int SeqList<DataType>::Locate(DataType x){
// 按值查找,时间复杂度为O(n)
for (int i=0; i<length; i++){
if (data[i]==x)
return i+1;
}
return -1; // 退出循环,说明查找失败
}
8.插入操作 O(n)
template<typename DataType>
void SeqList<DataType>::Insert(int i,DataType x){
// 插入操作,时间复杂度为O(n)
if (length==MaxSize)
throw "overflow";
if (i<1 || i>length+1)
throw "illegal insertion location";
for (int j=length; j>=i; j--){
data[j] = data[j-1]; // 将待插入位置右侧的元素向右移动
}
data[i-1] = x;
length++;
}
9.删除操作 O(n)
template<typename DataType>
DataType SeqList<DataType>::Delete(int i){
// 删除操作,时间复杂度为O(n)
DataType x;
if (length == 0)
throw "underflow";
if (i<1 || i>length)
throw "illegal deleted location";
x = data[i-1];
for (int j=i; j<length; j++){
data[j-1] = data[j]; // 将待删除元素的右侧元素向左移动
}
length--;
return x;
}
② 采用动态分配方式
采用C++的模板机制定义模板类SeqList。
const int InitSize = 100; // 顺序表的初始长度
const int IncreSize = 10; // 顺序表存储空间每次扩展的长度
template<typename DataType> // 定义模板类SeqList
class SeqList{
public:
// 与顺序表的静态分配相同
SeqList(); // 建立空的顺序表
SeqList(DataType a[],int n); // 建立长度为n的顺序表
~SeqList(); // 析构函数
int Length(); // 求线性表的长度
DataType Get(int i); // 按位查找,查找第i个元素的值
int Locate(DataType x); // 按值查找,查找值为x的元素序号
void Insert(int i,DataType x); // 插入操作,在第i个位置插入值为x的元素
DataType Delete(int i); // 删除操作,删除第i个元素
bool Empty(); // 判断线性表是否为空
void PrintList(); // 遍历操作,按序号依次输出各元素
private:
DataType *data; // 动态申请数组空间的首地址
int maxSize; // 当前数组空间的最大长度
int length; // 线性表的长度
};
在顺序表的动态分配方式下,求线性表的长度、按位查找、按值查找、删除、判空和遍历等基本操作的算法,与顺序表的静态分配方式相同。下面讨论其他基本操作的实现。
1.无参构造函数
template<typename DataType>
SeqList<DataType>::SeqList(){
data = new DataType[InitSize];
maxSize = InitSize;
length = 0;
}
2.有参构造函数
template<typename DataType>
SeqList<DataType>::SeqList(DataType a[],int n){
data = new DataType[2*n];
maxSize = 2*n;
for (int i=0; i<n; i++){
data[i] = a[i];
}
length = n;
}
3.析构函数
template<typename DataType>
SeqList<DataType>::~SeqList(){
delete[] data;
}
4.插入操作 O(n)
template<typename DataType>
void SeqList<DataType>::Insert(int i,DataType x){
if (i<1 || i>length+1)
throw "illegal insertion location";
if (length == maxSize){
// 发生上溢,扩充存储空间
DataType *oldData = data;
maxSize += IncreSize;
data = new DataType[maxSize];
for (int j=0; j<length; j++){
data[j] = oldData[j];
}
delete[] oldData;
}
for (int j=length; j>=i; j--){
data[j] = data[j-1];
}
data[i-1] = x;
length++;
}