概念就不多讲了,直接上代码,仅供参考。
模板类:
#include <iostream>
using namespace std;
const int defaultSize = 100;
/*
*基类 顺序表
*/
template<class T>
class LinearList
{
public:
LinearList() {}; //构造函数
~LinearList() {}; //析构函数
//const关键字表明该方法不能修改数据成员
//=0表示这是一个纯虚函数,必须由自己的继承类实现
virtual int Size() const = 0; //求表的最大长度
virtual int Length() const = 0; //求当前表的长度
virtual int Search(T& x) const = 0; //搜索给定值x在表中的位置
virtual int Locate(int i) const = 0; //在表中定位第i个元素的值
virtual bool GetData(int i, T& x) const = 0; //获取表中第i个表项
virtual bool SetData(int i, T& x) = 0; //修改第i个表项为x
virtual bool Insert(int i, T& x) = 0; //在第i个位置插入表项x;
virtual bool Remove(int i, T& x) = 0; //移除第i个表项,返回值表示是否成功,x用来暂存删除的表项
virtual bool IsEmpty() const = 0;//检查是否为空
virtual bool IsFull() const = 0; //检查表是否已经满了
virtual void Sort() = 0; //排序
virtual void Input() = 0; //接受输入
virtual void Output() = 0; //输出
//virtual LinearList<T> operator=(LinearList<T>& L) = 0; //复制顺序表
};
//常量,不指定参数情况下顺序表的默认大小
template<class T>
class SeqList :public LinearList<T>
{
protected:
T* data; //指向T类型顺序表的指针
int maxSize; //最大可以容纳的表项数
int last; //最后一个表项的下标,从0开始计数 last=length-1
//改变data数组空间的大小,一般用于扩容,如果输入的参数小于last+1,可能导致数据丢失
public:
SeqList(int sz = defaultSize); //构造函数,默认长度为100
SeqList(SeqList<T>& L); //复制构造函数
~SeqList(); //析构函数
int Size() const; //容量查询函数
int Length() const; //实际存储数据长度的查询函数
int Search(T& x)const; //在表中搜索x,并返回其位置
int Locate(int i)const; //定位第i个表项,返回其表项序号
bool GetData(int i, T& x)const; //获取第i个表项的值
bool SetData(int i, T& x); //用x的值取代第i个表项的值,使用返回值表示是否成功
bool Insert(int i, T& x); //在第i个表项后面插入x
bool Remove(int i, T& x); //移除第i个表项
bool IsEmpty() const; //判断表是否为空
bool IsFull() const; //判断表是否满
void Input();
void Output();
void Sort();
void Add(T& x);
void Swap(int a,int b);
void Union( SeqList<T>& L2,SeqList<T>& res); //并运算
void Intersection(SeqList<T>& L2, SeqList<T>& res); //交运算
SeqList<T> operator=(SeqList<T>& L); //表整体赋值
void Resize(int newSize);
void ResizeDouble(); //默认情况下,将容量扩充为原来的一倍
private:
template<class T>
friend ostream& operator<<(ostream& out, SeqList<T>& list) ;
template<class T>
friend istream& operator>>(istream& out, SeqList<T>& list);
};
template<class T>
void SeqList<T>::Resize(int newSize)
{
if (newSize < last + 1) //安全校验,负数属于不合法数据,小于last+1,会造成数据丢失
{
cerr << "无效的数组大小" << endl;
return;
}
T* newArray = new T[newSize];
if (newArray == NULL) //校验内存分配是否成功
{
cerr << "存储分配错误" << endl;
exit(1);
}
int n = last + 1;
T* srcPtr = data; //原顺序表
T* destPtr = newArray;//目标顺序表指针
while (n--) {
*destPtr++ = *srcPtr++;
/*等价于
*destPtr = *srcPtr;
destPtr++;
srcPtr++;
*/
}
delete[] data;
data = newArray;
maxSize = newSize;
}
template<class T>
void SeqList<T>::ResizeDouble()
{
Resize(maxSize * 2);
}
//构造函数的具体实现
template<class T>
SeqList<T>::SeqList(int sz) {
//除了在内部使用安全检查机制之外,也可以接受无符号整型作为参数
if (sz > 0) //检查输入的顺序表长度是否合法
{
maxSize = sz;
last = -1;
data = new T[maxSize]; //创建存储数组
if (data == NULL) //检查动态分配是否成功,一般情况都会成功
{
cerr << "内存分配出现错误" << endl;
exit(1);
}
}
else { //输入内容不合法,构造默认大小的数据空间
maxSize = 100;
last = -1;
data = new T[maxSize];
if (data == NULL)
{
cerr << "内存分配出现错误" << endl;
exit(1);
}
}
}
//复制构造函数的具体实现
template<class T>
SeqList<T>::SeqList(SeqList<T>& L)
{
maxSize = L.maxSize;
last = L.Length() - 1;
data = new T[maxSize];
if (data == NULL) //检查动态分配是否成功,一般情况都会成功
{
cerr << "内存分配出现错误" << endl;
exit(1);
}
//逐一赋值
for (int i = 1; i <= last + 1; i++)
{
T temp;
//获取数值是根据数据的位置,从1开始计数,1---last+1
L.GetData(i, temp);
//根据下标进行赋值 0-last
data[i - 1] = temp;
}
}
//析构函数具体实现
template<class T>
SeqList<T>::~SeqList()
{
delete[] data; //将开辟的内存空间还给系统
}
//容量查询具体实现
template<class T>
int SeqList<T>::Size() const
{
return maxSize;
}
//数据长度查询具体实现
template<class T>
int SeqList<T>::Length() const
{
return last + 1;
}
template<class T>
int SeqList<T>::Search(T& x) const
{
//返回值不是下标,是表项在表中的位置,从1开始
//返回0表示该表中没有搜索到相同的表项
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
{
//检查第i个表项是否存在
if (i > 0 && i <= last + 1) {
return i;
}
return 0; //表示第i个数据不存在
}
template<class T>
bool SeqList<T>::GetData(int i, T& x) const
{
//安全校验,检查第i个数据是否存在,存在则保存在x中,否则返回false
if (i > 0 && i <= last + 1) {
x = data[i - 1];
return true;
}
return false;
}
template<class T>
bool SeqList<T>::SetData(int i, T& x)
{
//安全校验,检查第i个数据是否存在,存在则替换为x,否则返回false
if (i > 0 && i <= last + 1) {
data[i - 1] = x;
}
return false;
}
template<class T>
bool SeqList<T>::Insert(int i, T& x)
{
//安全校验,表是否已满,满的情况下无法插入数据
if (IsFull()) {
return false;
}
//检查插入位置是否合理
if (i<0 || i>last + 1)
{
//用1代表数据项,0代表可插入位置 010...10
return false;
}
for (int j = last; j >= i; j--)
{
data[j + 1] = data[j];
}
data[i] = x;
last++;//数据增加1个
return true;
}
template<class T>
bool SeqList<T>::Remove(int i, T& x)
{
if (IsEmpty()) //安全校验,是否为空表
{
return false;
}
if (i >= 0 && i <= last) {
x = data[i - 1];
for (int j = i; j <= last; j++)
{
data[j - 1] = data[j];
}
last--;
return true;
}
else {
return false;
}
}
template<class T>
bool SeqList<T>::IsEmpty() const
{
return last == -1 ? true : false;
}
template<class T>
bool SeqList<T>::IsFull() const
{
return last + 1 == maxSize ? true : false;
}
template<class T>
void SeqList<T>::Input()
{
cout << "开始建立顺序表,请输入表中元素的个数:";
//利用死循环接收数据,如果输入格式正确跳出循环,错误继续接收输入值
while (true) {
cin >> last;
last--;
if (last<= maxSize-1 && last>=0) {
break; //跳出循环
}
//提示:
cout << "输入的元素个数不能超过存储上限:" << maxSize<< endl;
}
for (int i = 0; i <=last; i++)
{
cin >> data[i];
if (i != last) {
cout << "输入下一个数据:" << endl;
}
else {
cout << "输入结束" << endl;
}
}
}
template<class T>
void SeqList<T>::Output()
{
cout << "当前表中元素个数为:" << last + 1 << endl;
for (int i = 0; i <= last; i++)
{
cout << "#" << i + 1 << ":" << data[i] << endl;
}
}
template<class T>
void SeqList<T>::Sort() //利用冒泡算法进行排序
{
for (int i = 0; i <= last; i++)
{
for (int j = 0; j <last; j++)
{
if (data[j] > data[j + 1]) {
this->Swap(j + 1, j + 2);
}
}
}
}
template<class T>
void SeqList<T>::Add(T& x)
{
Insert(last+1, x);
}
template<class T>
void SeqList<T>::Swap(int a,int b) //交换第a个数字和第b个数字
{
T temp =data[a-1];
data[a - 1] = data[b - 1];
data[b - 1] = temp;
}
template<class T>
void SeqList<T>::Union(SeqList<T>& L2, SeqList<T>& res)
{
int leftLength = Length();
int rightLength = L2.Length();
res.Resize(leftLength + rightLength); //保证能存储的下
for (int i = 0; i <= last; i++)
{
res.data[i]= data[i];
}
res.last = last;
for (int i = 1; i <= L2.last+1; i++)
{
T temp;
L2.GetData(i, temp);
if (!res.Search(temp))
{
res.Add(temp);
}
}
}
template<class T>
void SeqList<T>::Intersection(SeqList<T>& L2, SeqList<T>& res) //交运算
{
if (Length() > L2.Length()) {
res.Resize(Length());
}
else {
res.Resize(L2.Length());
}
res.last = -1;
for (int i = 1; i <= last+1; i++)
{
T temp;
this->GetData(i, temp);
if (L2.Search(temp)) {
res.Add(temp);
}
}
}
template<class T>
SeqList<T> SeqList<T>::operator=(SeqList<T>& L)
{
maxSize = L.maxSize;
delete[] data;
data = new T[maxSize];
last = L.last;
for (int i = 1; i <= last + 1; i++)
{
T temp;
L.GetData(i, temp);
data[i - 1] = temp;
}
}
template<class T>
ostream& operator<<(ostream& OutStream, SeqList<T>& OutList)
{
OutStream << "数组内容 : " << endl;
for (int i = 0; i < OutList.Length(); i++)
OutStream << OutList.data[i] << "";
OutStream << endl << "数组当前大小 : " << OutList.Length() << endl;
return OutStream;
}
template<class T>
istream& operator>>(istream& in, SeqList<T>& inlist)
{
cout << "开始建立顺序表,请输入表中元素的个数:";
while (true) {
in >> inlist.last;
inlist.last--;
if (inlist.last <= inlist.maxSize - 1 && inlist.last >= 0) {
break; //跳出循环
}
//提示:
cout << "输入的元素个数不能超过存储上限:" << inlist.maxSize << endl;
}
for (int i = 0; i <= inlist.last; i++)
{
in >> inlist.data[i];
if (i != inlist.last) {
cout << "输入下一个数据:" << endl;
}
else {
cout << "输入结束" << endl;
}
}
return in;
}
测试01
#include <iostream>
#include "LinearList.h"
using namespace std;
int main() {
SeqList<int> seq01(3); //构造函数测试
cout << "顺序表是否为满:" << seq01.IsFull()<<endl; //
cout << "顺序表是否为空:" << seq01.IsEmpty() << endl;
cout << "表的容量为:" << seq01.Size() << "表中存储的数据个数为" << seq01.Length() << endl;
seq01.Input(); //输入函数测试
cout <<"顺序表是否为满:"<< seq01.IsFull() << endl;
cout <<"顺序表是否为空:"<<seq01.IsEmpty() << endl;
seq01.Output(); //原始构造的列表输出
cout << "移除第二个数字:"<<endl;
int temp;
seq01.Remove(2, temp); //移除函数测试
cout << "表的容量为:" << seq01.Size() << "表中存储的数据个数为" << seq01.Length() << endl;
seq01.Output(); //移除后列表输出
cout << "在第一个数据后插入 5"<<endl;
int m = 5;
seq01.Insert(1, m); //在第一个数据后插入5输出
cout << "表的容量为:" << seq01.Size() << "表中存储的数据个数为" << seq01.Length() << endl;
seq01.Output();
cout <<"利用=运算符重载"<< endl;
SeqList<int> seq02 = seq01; //=运算符重载测试
cout << "表的容量为:" << seq02.Size() << "表中存储的数据个数为" << seq02.Length() << endl;
seq02.Output();
cout << "使用resize进行扩容:" << endl;
seq02.Resize(10);
cout << "表的容量为:" << seq02.Size() << "表中存储的数据个数为" << seq02.Length() << endl;
seq02.ResizeDouble();
cout << "表的容量为:" << seq02.Size() << "表中存储的数据个数为" << seq02.Length() << endl;
cout << "使用getdata获取指定位置的数字:" << endl;
int temp01;
if (seq02.GetData(2, temp01)) {
cout << "第2个数字是:" << temp01 << endl;
}
cout << "使用setdata设置指定位置的数字:" << endl;
int temp02=8;
seq02.SetData(3, temp02);
seq02.Output();
cout << "使用复制构造函数" << endl;
SeqList<int> seq03(seq02);
seq03.Output();
}
测试02 排序
int main() {
SeqList<int> seq04(6);
seq04.Input();
seq04.Output();
seq04.Sort();
seq04.Output();
}
测试03 模板类中使用友元函数重载<<和>>运算符
注意:写代码时遇到了报错,LNK2019 无法解析的外部符号 “class std::basic_ostream<char,struct std::char_traits > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits > &,class SeqList &)” (??6@YAAA
解决方法:声明的时候加上 **template < class T> **详见 参考资料2
测试代码:
int main() {
SeqList<int> seq08(10);
cin >> seq08;
cout << seq08;
}
运行结果:
测试04 交和并
int main() {
cout << "输入第一个顺序表" << endl;
SeqList<int> seq05(3);
seq05.Input();
seq05.Output();
cout << "输入第二个顺序表" << endl;
SeqList<int> seq06(3);
seq06.Input();
seq06.Output();
SeqList<int> unionRes;
seq05.Union(seq06, unionRes);
cout << "union的结果是:" << endl;
unionRes.Output();
SeqList<int> intersectionRes;
seq05.Intersection(seq06, intersectionRes);
cout << "Intersection的结果是:" << endl;
intersectionRes.Output();
}
参考资料:
- 清华大学计算机系列教材 数据结构 殷人昆主编
- 在c++ 模板类外写 操作符重载函数,并且是模板类的友元函数
- C++运算符重载三种形式(成员函数,友元函数,普通函数)详解