本例子是《数据结构与算法c++描述》中的线性表中抽象数据类型 (abstract data type, ADT):
目录
基本概念:
构造函数与析构函数:
是否为空:
Find函数:
查找函数:
删除数据:
插入函数:
输出函数与重构 << 符号输出:
题目部分函数:
changeSize函数:
Reverse函数:
复制构造函数:
操作函数:
线性交叉函数:
Merge函数:
Split函数:
测试程序:
先看基本类型吧:
本例子采用了类模板,这里提醒一下大家,不要把定义与实现一个写在.h与.cpp, 因为模板的性质,当你在别的文件使用的时候,就会报无法解析外部符号的错误。
本例子代码是书上的代码,后边的新加的功能是课后习题需要开发的,同时也对这个程序完善了一部分。
首先我们先看类的定义:
listearLine.h 文件中
/*
数组结构中的线性表数组样式
对应书中代码:数据结构算法与应用c++描述
程序编写:比卡丘不皮
编写时间:2020年6月24日 13:51:23
*/
#pragma once
#include
#include "all_error.h"
#include
using namespace std;
template
class LinearList
{
public:
LinearList();
LinearList(int MaxListSize ); //构造函数默认为
~LinearList(); //析构函数
LinearList(const LinearList & L); //复制构造函数
bool IsEmpty()const; //判断是否为空
int Length() const { return length; } //返回表的长度,即表中元素个数
bool Find(int k, T& x)const; //返回第k个元素至x中 若不存在第k个元素,则返回false
int Search(const T& x) const; // 返回x所在位置 如果x 不在表中,则返回0
LinearList& Delete(int k, T& x); // 删除第k个元素并将它返回至x中
LinearList& Insert(int k, const T& x); // 在第k个元素之后插入x
//改变数组最大长度函数,l为数组长度,m为数组最大长度
LinearList& changeSize(T * elementNew, int nlength, int max);
LinearList& Reverse(); //元素次序的反转 element[k]=element[length-k]
LinearList& Half(); //数组减半
void Reset() { current = 1; } //设置数据位
bool Current(T &x); //返回当前的值
bool End()const; //是否为最后边
bool Front() const; //是否为最前边
void Next(); //到下个值
void Previous(); //到前一个值
void clear();
//线性表交叉组合
LinearList& Alternate(const LinearList & list1, const LinearList & list2);
//有规律(元素从小到大排列)线性表的组合
LinearList& Merge(const LinearList & list1, const LinearList & list2);
//线性表分割函数
void Split(LinearList & list1, LinearList & list2);
void Output(ostream& out) const; // 输出函数
LinearList & operator =(const LinearList & x); //重载赋值运算
private:
int length; //数组的长度
int MaxSize; //数组最大值
T * element; //一维动态数组
int current; //元素当前的位置
};
这里先讲下
#include "all_error.h"
这里我写了抛出的异常类:
/*
线性表中的数组结构
对应书中代码:数据结构算法与应用c++描述
程序编写:比卡丘不皮
编写时间:2020年6月24日 13:51:23
*/
#pragma once
#include
using namespace std;
class Noman
{
public:
Noman()
{
cout << "内存不足"<< endl;
}
~Noman()
{
}
};
//使new引发NoMemory异常而不是xalloc异常
void my_new_handler()
{
throw Noman();
}
new_handler Old_Handler_ = set_new_handler(my_new_handler);
class OutOfBounds
{
public:
OutOfBounds()
{
cout << "超出范围" << endl;
}
~OutOfBounds()
{
}
};
为了超出数组触发不同的异常警告。
还是回到类成员函数中(listearLine.h 里面):
template
inline LinearList::LinearList()
{
MaxSize = 1;
element = new T[MaxSize];
length = 0;
}
//构造函数默认为10
template
LinearList::LinearList(int MaxListSize)
{
MaxSize = MaxListSize;
element = new T[MaxSize];
length = 0;
}
//析构函数
template
LinearList::~LinearList()
{
delete[] element;
}
//判断是否为空
template
bool LinearList::IsEmpty() const
{
return 0 == length;
}
//返回第k个元素至x中 若不存在第k个元素,则返回false
template
bool LinearList::Find(int k, T & x) const
{
if (k<1 || k>length)
{
return false;
}
else
{
x = element[k-1];
}
return true;
}
template
int LinearList::Search(const T & x) const
{
for (int i =0; i
template
LinearList& LinearList::Delete(int k, T & x)
{
if (Find(k,x))
{
for (int i = k; i < length; i++)
{
element[i - 1] = element[i];
}
length--;
if (length == (MaxSize / 4) && length > 0)
{
MaxSize /= 2;
changeSize(element,length,MaxSize);
}
return *this;
}
else
{
throw OutOfBounds();
}
}
这里本没有:
if (length == (MaxSize / 4) && length > 0)
{
MaxSize /= 2;
changeSize(element,length,MaxSize);
}
这段代码,这里是后面习题中添加的功能,后面又详细解答。
//插入数据
//在第k个元素之后插入x;函数返回修改后的线性表
template
LinearList& LinearList::Insert(int k, const T & x)
{
//在第k个元素之后插入x;函数返回修改后的线性表
//如果不存在第k个元素,则引发异常OutOfBound
//如果表已经满,则引发异常NoMem
if (k<0 || k > length)
{
throw OutOfBounds();
}
if (length == MaxSize)
{
throw Noman();
}
//向后移动一位 书中这里是减一 书写错误
for (int i = length - 1; i >= k; i--)
{
element[i + 1] = element[i];
}
element[k] = x;
length++;
if (length == MaxSize)
{
MaxSize *= 2;
changeSize(element, length, MaxSize);
}
return *this;
}
template
void LinearList::Output(ostream & out) const
{
for (int i = 0; i < length; i++)
{
out << element[i] << " ";
}
}
template
ostream & operator<<(ostream & out, const LinearList & x)
{
x.Output(out);
return out;
}
已上的函数功能都是书中的代码部分,下面的部分为书上 课后习题里面需要的。
//改变大小,节省空间
template
inline LinearList& LinearList::changeSize(T * elementNew, int nlength, int max)
{
element = new T[max];
for (int i = 0; i
这个函数可以节省空间,可以看插入函数与删除函数,在执行删除操作期间,如果线性表的尺寸降至当前 MaxSize 的四分之一,则分配一个更小的、尺寸为 MaxSize / 2的数组,并将老数组中的数据复制到新数组中,最后将老数组删除。
题目2:
//数据反转函数
template
LinearList& LinearList::Reverse()
{
for (int i = 0; i< (length/2); i++)
{
T temp = element[i];
element[i] = element[length-1-i];
element[length - 1 - i] = temp;
}
return *this;
}
//就地反转函数利用对象
template
void ReverseEle(LinearList & data)
{
data.Reverse();
}
这里是后面对比使用的函数。
template
LinearList& LinearList::Half()
{
length = (length + 1) / 2;
//这里两种方案来写程序,也是剑指offer中的知识点
//方法1
T *elementNew = new T[length+1];
for (int i = 0; i<=length; i++)
{
elementNew[i] = element[2 * i];
}
delete[] element;
element = new T[length+1];
for (int i = 0; i <= length; i++)
{
element[i] = elementNew[i];
}
delete[] elementNew;
return *this;
//方法二是直接利用构造函数,这样就不用自己写delete了,这里就不记录了
}
//复制构造函数
template
LinearList::LinearList(const LinearList& L)
{
if (this == &L)
{
return;
}
else
{
this->length = L.length;
this->MaxSize = L.MaxSize;
delete[] element;
element = new T[length+1];
memcpy(element, L.element, length * sizeof(T));
}
}
当写完后一定要写重载 = 符号不然很容易出问题:
template
inline LinearList& LinearList::operator=(const LinearList& x)
{
if (this == &x)
{
return *this;
}
this->MaxSize = x.MaxSize;
this->length = x.length;
memcpy(element, x.element,length * sizeof(T));
}
template
bool LinearList::Current(T & x)
{
if (current < 0 || current > MaxSize)
{
return false;
}
else
{
x = element[current - 1];
return true;
}
}
template
inline bool LinearList::End() const
{
return current == length;
}
template
inline bool LinearList::Front() const
{
return current == 1;
}
template
inline void LinearList::Next()
{
if (current < length)
{
current++;
}
else
{
throw OutOfBounds();
}
}
template
inline void LinearList::Previous()
{
if (current > 1)
{
current--;
}
else
{
throw OutOfBounds();
}
}
template
void LinearList::clear()
{
this->MaxSize = 1;
delete [] element;
element = new T[MaxSize];
this->length = 0;
}
Reset 在定义的时候已经写完了。这里我自己添加了个clear函数。
template
LinearList& LinearList::Alternate(const LinearList& list1, const LinearList& list2)
{
//线性交叉
if (length>0)
{
delete[] element; //清除原有数据
}
length = list1.length + list2.length;
element = new T[length];
// MaxSize = length;
LinearList A = list1, B = list2; //复制构造函数
A.Reset();
B.Reset();
int value = 0; //记录当前位置的值
int minLenght = A.length <= B.length ? A.length: B.length; //获取当前比较小的值
for (int i = 0; i
template
LinearList& LinearList::Merge(const LinearList& list1, const LinearList& list2)
{
if (length > 0)
{
delete[] element;
}
length = list1.length + list2.length;
MaxSize = length;
element = new T[length]; //创建新的标签
int ca = 0, cb = 0, ct = 0;
//先拍都有的数据
while (ca < list1.length && cb < list2.length)
{
if (list1.element[ca] >= list2.element[cb])
{
element[ct++] = list2.element[cb++];
}
else
element[ct++] = list1.element[ca++];
}
//在排剩下的数据
if (ca == list1.length) //表示list1数组排完了
{
for (int i = cb;i < list2.length;i++)
{
element[ct] = list2.element[i];
ct++;
}
}
else
{
for (int i = ca; i < list1.length; i++)
{
element[ct] = list1.element[i];
ct++;
}
}
return *this;
}
void LinearList::Split(LinearList& list1, LinearList& list2)
{
int aNum = 0;
int bNum = 0;
for (int i = 0; i < length; i++)
{
if ((i & 1) == 0)
{
list1.Insert(aNum++, element[i]);
}
else
{
list2.Insert(bNum++, element[i]);
}
}
}
//测试列表数组
void testLinearList()
{
try
{
//设置为空的时候
cout << "初始化开始" << endl;
LinearList L;
cout << "Lenght = " << L.Length() << endl;
cout << "IsEmpty = " << L.IsEmpty() << endl;
L.Insert(0, 2);
L.Insert(1, 6);
//也可以这样写
L.Insert(2, 5).Insert(3, 4).Insert(4, 8);
cout << "List is " << L << endl;
cout << "isEmpty " << L.IsEmpty() << endl;
//测试插入函数
L.Insert(1, 10).Insert(2,1);
cout << "List is " << L << endl;
cout << "isEmpty " << L.IsEmpty() << endl;
cout << "lengh is " << L.Length()<< endl;
int z;
L.Find(1, z); //找到第一个数的数据
cout << "first element " << z << endl;
cout << "Lenght = " << L.Length() << endl;
cout << "lengh is " << L.Length() << endl;
L.Delete(1, z);
cout << "Deleted element is " << z << endl;
cout << "List is " << L << endl;
cout << "lengh is " << L.Length() << endl;
cout << endl;
//测试查找
cout << "test Search" << endl;
cout << "List is " << L << endl;
cout << "6 in L? " << L.Search(6) << endl;
cout << "9 in L? " << L.Search(9) << endl;
cout << endl;
cout << "test Reverse" << endl;
L.Reverse();
cout << "List is " << L << endl;
cout << "isEmpty " << L.IsEmpty() << endl;
cout << "lengh is " << L.Length() << endl;
//反转测试
for (int i = 0; i<500000; i++)
{
L.Insert(i, i);
}
cout << L.Length() << endl;
clock_t startTime, stopTime;
startTime = clock();
L.Reverse();
stopTime = clock();
cout << "类成员反转使用的时间: " << float(stopTime - startTime) / CLK_TCK << endl;
//就地反转
startTime = clock();
ReverseEle(L);
stopTime = clock();
cout << "就地反转使用的时间: " << float(stopTime - startTime) / CLK_TCK << endl;
//测试half
L.Half();
cout << "length is : " << L.Length()<< endl;
//测试复制构造函数
LinearList ML(L);
cout << "length L is : " << L.Length() << endl;
cout << "length ML is : " << ML.Length() << endl;
//测试current类容
ML.Reset(); //位置置0
//测试next
ML.Next(); //移动到下个位置
cout << "判断是否是前边的 " << ML.Front() << endl;
int value = 0;
cout << "当前是否有问题 :" << ML.Current(value) << endl;
cout << "输出当前的值是 :" << value << endl;
//其他函数测试也是相同的
//测试交叉数据
LinearList A, B;
for (int i = 0; i<4; i++)
{
A.Insert(i, i);
B.Insert(i, i);
}
B.Insert(4, 4).Insert(5, 5);
cout << "A is List : " << A < C;
C.Alternate(A,B);
cout << "C is list :" << C << endl;
//测试合并排序,前提都是顺序的
A.Insert(4, 10);
LinearList D;
D.Merge(A,B);
cout << "D is list :" << D << endl;
//测试
A.clear();
B.clear();
D.Split(A,B);
cout << "D is list :" << D << endl;
cout << "A is List : " << A << endl;
cout << "B is List : " << B << endl;
}
catch (const std::exception&)
{
cerr << "An exception has occurred" << endl;
}
}
主函数:
#include
#include "listearLine.h"
using namespace std;
int main()
{
//测试线性表数组
testLinearList();
return 0;
}
已上就是题目中的程序了,从第9题目开始,只是变成下标为1开始数组,这里类推一下就好不难的。写题目部分程序毕竟是自己来写的,难免会有程序问题,若你有发现问题,可在下面评论区交流,或者关注我博客,让我们一起进步,加油。
需要书籍的可以来取:
对应数据结构的书籍
本文例子的连接:
链接:本文例子 提取码:ao3c
如果例子失效,可以私信,或者下方评论。