顺序表的定义和特点
顺序表的定义是:把线性表中的所有表项按照其逻辑顺序依次存储到从计算机存储中指定存储位置开始的一块的连续空间中。第一个表项的假设顺序表中每个表项的数据类型使T,则每个表项所战勇的存储空间的大小相同,均为sizeof(T),整个顺序表占用的存储空间的大小为n*sizeof(T),其中n为线性表的长度。
事实上,以上描述和C/C++中的一维数组十分相似。在C++中,只要定义了一个数组,就定义了一块可供用户使用的连续的存储空间,其起始位置就是由数组名表示的地址常量。
顺序表的特点是:
(1)在顺序表中,各个表项的逻辑顺序与其存放的物理顺序一致,即第i个表项存储于第i个物理位置。
(2) 对顺序表中所有表项,既可以进行顺序访问,也可以随机访问。即,既可以从第一个表项开始逐个访问,也可以直接由序号(下标)访问。
假设顺序表A的起始存储位置为Loc(1),第i个表项的存储位置为Loc(i),则有:
Loc(i)=Loc(1)+(i-1)*sizeof(T)
其中,Loc(1)是第一个表项的存储位置,即下标为0的元素位置。
类定义与实现
这里用C++的动态存储分配定义数组。
以下是"SeqList.h"头文件,包括函数的声明与定义。
#pragma once
#include<iostream>
#include<stdlib.h>
const int defaultSize = 100; //全局常变量
using namespace std;
template<class T> //模板类
class SeqList
{
protected:
T* data; //动态分配
int maxSize; //顺序表最大容量
int last; //当前顺序表最后元素的位置
bool reSize(int newSize); //重新设置容量
public:
SeqList(int sz = defaultSize); //构造函数
SeqList(SeqList<T>& L); //重载构造函数
~SeqList() { delete[] data; }; //析构函数
int Size()const { return maxSize; }; //返回顺序表的容量
int Length()const { return last + 1; } //返回当前长度
int Search(T& x)const; //搜索函数
int Locate(int i)const; //定位函数
bool getData(int i, T& x)const //取值函数(内联)
{
if (i > 0 && i <= last + 1)
{
x = data[i - 1];
return true;
}
else
return false;
}
bool setData(int i, T& x) //设值函数(内联)
{
if (i > 0 && i <= last + 1)
{
data[i - 1] = x;
return true;
}
else
return false;
}
bool Insert(int i, T& x); //插入函数
bool Remove(int i, T& x); //删除函数
bool IsEmpty()const //判空(内联)
{
return (last == -1) ? true : false;
}
bool IsFull()const //判满(内联)
{
return (last == maxSize - 1) ? true : false;
}
void input(); //输入函数
void output(); //输出函数
void sort(); //排序函数(冒泡)
void merge(SeqList<T>& LA, SeqList<T>& LB); //归并函数(将两表按大小顺序合并)
void Union(SeqList<T>& LA, SeqList<T>& LB); //取并集
void Intersection(SeqList<T>& LA, SeqList<T>& LB); //取交集
SeqList<T>& operator=(SeqList<T>& L); //重载"="运算符
SeqList<T>& link(SeqList<T> &L); //连接函数
};
将关键字const放在函数参数表后面、函数体的前面起到了一种保护作用,表明它不能该表操作它的对象的数据成员的值。如int Length()const中的const。另外,const成员函数执行时不能调用非const成员函数。
template<class T> //模板类
SeqList<T>::SeqList(int sz) //构造函数含默认参数
{
if (sz > 0)
{
maxSize = sz;
last = -1; //无元素时,最后一个元素的位置置为-1
data = new T[maxSize]; //动态分配
if (data == NULL)
{
cout << "Error: Distribution Failure!" << endl;
exit(0);
}
for (int i = 0; i <= sz; i++)
{
data[i] = 0; //初始化为0
}
}
}
template<class T>
SeqList<T>::SeqList(SeqList& L) //复制构造函数
{
maxSize = L.Size();
last = L.Length() - 1;
T value;
data = new T[maxSize]; //动态分配
if (data == NULL)
{
cout << "Error: Distribution Failure!" << endl;
exit(0);
}
for (int i = 0; i <= last; i++)
{
L.getData(i+1, value); //取值并赋值
data[i] = value;
}
}
template<class T>
bool SeqList<T>::reSize(int newSize) //重新分配容量
{
if (newSize <= 0)
{
cout << "Invalid input!" << endl;
return false;
}
if (newSize != maxSize)
{
T* newarray = new T[newSize];
if (newarray == NULL)
{
cout << "Error: Distribution Failure!" << endl;
}
int n = last + 1;
T* srcptr = data;
T* desptr = newarray;
while (n--)
{
*desptr++ = *srcptr++; //将原有表项复制到新表
}
delete []data; //删除原表
data = newarray;
maxSize = newSize;
}
return true;
}
template<class T>
int SeqList<T>::Search(T& x)const //搜索函数
{
for (int i = 0; i <= last; i++) //遍历顺序表
{
if (data[i] == x)
return i + 1;
}
return 0;
}
template<class T>
int SeqList<T>::Locate(int i)const //定位函数
{
if (i >= 1 && i <= last + 1)
return i;
else
return 0;
}
template<class T>
bool SeqList<T>::Insert(int i, T& x) //插入函数
{
if (last == maxSize)
return false;
if (last == maxSize - 1) //容量已满时无法插入
return false;
if (i<0 || i>last + 1) //输入不合法
return false;
for (int j = last; j >= i; j--)
data[j + 1] = data[j]; //将插入位置以后的表项向后挪动
data[i] = x; //插入值
last++;
return true;
}
template<class T>
bool SeqList<T>::Remove(int i, T& x) //删除函数
{
if (i<1 || i>last + 1) //输入不合法
return false;
for (int j = i; j <= last; j++)
data[j - 1] = data[j]; //将删除位置以后的表项向前移动
last--;
return true;
}
template<class T>
void SeqList<T>::input(void) //输入
{
cout << "Constructing SeqList, pleaes enter in the last place of the elements(begin from 0):" << endl;
while (1)
{
cin >> last;
if (last >= maxSize - 1) //容量已满时无法输入
break;
cout << "Error! The number is not allowed to exceed" << maxSize << ":";
}
cout << "请输入元素!" << endl;
for (int i = 0; i <= last; i++)
{
cout << "请输入第" << i + 1 << "个元素:" << endl;
cin >> data[i];
cout << "已输入" << i + 1 << "个元素!" << endl;
}
}
template<class T>
void SeqList<T>::output() //输出函数
{
cout << "顺序表当前元素最后位置为:" << last << endl;
for (int i = 0; i <= last; i++)
cout << "#" << i + 1 << ":" << data[i] << " place:" << i << endl;
}
template <class T>
SeqList<T>& SeqList<T>::operator=(SeqList<T>& L) 重载运算符"="
{
if (maxSize < L.Size())
reSize(L.Size()); //重新分配容量
maxSize = L.Size();
last = L.Length() - 1;
for (int i = 0; i <= last; i++)
{
L.getData(i + 1,data[i]); //取值并赋值
}
return *this;
}
template <class T>
void SeqList<T>::Union(SeqList<T>& LA)
//取并集
{
int n = Length();
int m = LA.Length();
int k, x;
for (int i = 1; i <= m; i++)
{
LA.getData(i, x);
k = Search(x); //若原表中没有,则将该元素插入
if (k == 0)
{
Insert(i, x);
i++;
}
}
}
template <class T>
void SeqList<T>::Intersection(SeqList<T>& LA)
//求交集
{
int n = Length();
int m = LA.Length();
int k, x;
for (int i = 1; i <= m; i++)
{
LA.getData(i, x);
k = Search(x); //若原表中有,则将该元素删除
if (k == 0)
{
Remove(i,x);
n--;
}
}
}
template <class T>
void SeqList<T>::sort() //排序函数(冒泡)
{
T temp;
for (int i = 0; i < last; i++)
{
for (int j=0; j < last;j++)
if (data[j + 1] < data[j])
{
temp = data[j];
data[j] = data[j+1];
data[j + 1] = temp;
}
}
}
template<class T>
void SeqList<T>::merge(SeqList<T>& LA, SeqList<T>& LB)
//归并函数
{
LA.sort();
LB.sort();
int m = LA.Length() + LB.Length(); //取二者之和为容量
int i=0;
if( Size()<m)
reSize(m); //重新分配容量
T* ptra = LA.data;
T* ptrb = LB.data;
last=0;
while (*ptra!=0 && *ptrb!=0)
{
if (*ptra < *ptrb) //取较小者放入新表
{
Insert(i++, *ptra); //新表指针后移,原表指针后移
ptra++;
}
else
if(*ptra > *ptrb)
{
Insert(i++, *ptrb);
ptrb++;
}
else
{
Insert(i++, *ptra); //相等时任取其一放入新表
*ptra++;
*ptrb++;
}
}
while (*ptra!=0) //当一表已全部放入后,另一表直接连接在新表后
{
Insert(i++,*ptra++);
}
while (*ptrb!=0)
{
Insert(i++,*ptrb++);
}
last--;
}
template<class T>
SeqList<T>& SeqList<T>::link(SeqList<T> &L)
//连接函数
{
int m = Length() + L.Length();
if (reSize(m))
{
T* desptr = &data[last]; //定位在前表最后位置
desptr++;
T* srcptr = L.data; //遍历后表
cout<<"reSize="<<m<<endl;
for(int i=0;i<L.Length();i++)
{
*desptr++=*srcptr++; //将后表元素按顺序连接到前表
last++; //更新最后元素的位置
}
}
return *this;
}
以下是测试函数。
在main程序中需要链接头文件"SeqList.h"。
#include <iostream>
#include"SeqList.h"
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main(int argc, char** argv)
{
SeqList<int> a(5),b(5),c; //创建对象
int x;
a.input(); //输入
a.output(); //输出
b.input();
b.output();
cout<<"sorting..."<<endl;
// a.sort(); //排序
// b.sort();
// a=a.link(b); //连接
c.merge(a,b); //归并
c.output();
// a.Intersection(b); //求交集
// a.output();
return 0;
}