作业文件名 | LinkList.h | SeqList.h | StaticLinkList.h | 线性表.cpp |
---|---|---|---|---|
包含内容 | 链式存储结构的类模板声明及函数实现 | 顺序存储结构的类模板声明及函数实现 | 静态链表存储结构的类模板声明及函数实现 | 测试代码 |
1.实现线性表的顺序存储结构(SeqList)和链式存储结构(LinkList)。在上述 两种存储结构的基础上,分别实现以下算法:
顺序存储结构(SeqList)的类模板代码:
template<class Elementtype>
class SeqList {
public:
SeqList(){//无参构造,初始化表长为0
len = 0;
}
SeqList(Elementtype a[], int n);//有参构造,用一个数组初始化线性表
//因为没有自己手动开辟空间,析构函数跟拷贝构造就用默认的。
void Insert(int i, Elementtype x);//随机插入元素
void Delete1(int i); //按位删除操作
void Delete2(Elementtype x); //按值删除操作
void Sort();//排序,我用的简单冒泡排序
void DeleteRe();//对于已排好序的线性表,删除所有重复元素的算法。
void Reverse();//线性表“逆置”算法
void MoveRight(int k);//循环右移
void MoveLeft(int k);//循环左移
void Print();//打印线性表
void MergeSeqList(SeqList& L);//合并两个已排好序线性表的算法
private:
Elementtype elements[maxlength]; //数组,用来存放线性表中的元素
int len;//记录表长
};
链式存储结构(LinkList)的类模板代码:
template<class Elementtype>
class LinkList
{
public:
LinkList();//无参构造函数,生成具有头节点的空链表
LinkList(Elementtype a[], int n);
~LinkList();//因为自己在堆中开辟了空间,所以得重新设置析构函数
int Locate(Elementtype x);//查找
void Insert(int i, Elementtype x);
Elementtype Delete1(int i);//按位删除,返回被删除的值
int Delete2(Elementtype x);//按值删除,返回该值的位置
void Print();
void Sort();//排序,我用的简单冒泡排序
void DeleteRe();//对于已排好序的线性表,删除所有重复元素的算法。
void Reverse();//线性表“逆置”算法
void MoveRight(int k);//循环右移
void MoveLeft(int k);//循环左移
void MergeSeqList(LinkList& L);//合并两个已排好序线性表的算法
public:
Node<Elementtype>* first;
};
① 删除给定元素的算法。
顺序存储结构(SeqList)的按位删除算法:
template <class Elementtype>
void SeqList<Elementtype>::Delete1(int i) //按位删除操作
{
if (len == 0) {
cout << "EMPTY!" << endl;
}
else if (i<1 || i>len) {
cout << "WRONG!" << endl;
}
else {
for (int j = i; j < len; j++)
elements[j - 1] = elements[j];
len--;
}
}
顺序存储结构(SeqList)的按值删除算法:
template<class Elementtype>
struct Node
{
Elementtype data;
Node<Elementtype>* next;
};
template <class Elementtype>
void SeqList<Elementtype>::Delete2(Elementtype x) //按值删除操作,重复元素只删除第一个
{
int p = 0;
for (int i = 0; i < len; i++)
if (elements[i] == x) {
p = i + 1;
break;
}
if (p == 0)
cout << "未找到该值" << endl;
else {
for (int j = p; j < len; j++)
elements[j - 1] = elements[j];
len--;
}
}
顺序存储结构(SeqList)的删除算法的测试代码及结果图:
int a[] = { 1,999,87,87,7,5,5,7,9,10,31,541,521 };
SeqList<int> SL1(a, sizeof(a) / sizeof(int));
SL1.Print();
cout << "按位删除第五个元素" << endl;
SL1.Delete1(5);
SL1.Print();
cout << "按值删除5" << endl;
SL1.Delete2(5);
SL1.Print();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LRTUznNz-1677332023085)(1.assets/G170KEQP_4T%KQY6A{0%BB3-16648924710912-16648924762094.png)]
链式存储结构(LinkList)的按位删除算法:
template<class Elementtype>
Elementtype LinkList<Elementtype>::Delete1(int i)//按位删除
{
Node<Elementtype>* p = first;
int count = 0;
while (p != NULL && count < i - 1)
{
p = p->next;
count++;
}
if (p == NULL || p->next == NULL) throw "位置为空!";//前驱为空或者前途是终端节点
else {
Node<Elementtype>* q = p->next;
int x = q->data;
p->next = q->next;
return x;//返回被删除的值
}
}
链式存储结构(LinkList)的按值删除算法:
template<class Elementtype>//只删除遇到的第一个值
int LinkList<Elementtype>::Delete2(Elementtype x)//按值删除
{
int Y = Locate(x);
Delete1(Y);
return Y;
}
链式存储结构(LinkList)的删除算法的测试代码以及结果图:
我的有参构造用的头插法,所以顺序是反过来的。
int a[] = { 1,999,87,87,7,5,5,7,9,10,31,541,521 };
LinkList<int> LL1(a, sizeof(a) / sizeof(int));
LL1.Print();
cout << "按位删除第五个元素" << endl;
LL1.Delete1(5);
LL1.Print();
cout << "按值删除5" << endl;
LL1.Delete2(5);
LL1.Print();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zfdPZgt3-1677332023086)(1.assets/1.png)]
**② 对于已排好序的线性表,删除所有重复元素的算法。 **
顺序存储结构(SeqList)的删除重复元素算法:
template <class Elementtype>
void SeqList<Elementtype>::Sort() {//我用的简单冒泡排序
int i, j;
for (i = 0; i < len-1; i++)
{
bool flag = false;
for (j = len-1; j >= i + 1; j--)
if (elements[j] < elements[j - 1])
{
Elementtype temp = elements[j];
elements[j] = elements[j - 1];
elements[j - 1] = temp;
flag = true;
}
if (flag == false)
return;
}
}
template <class Elementtype>
void SeqList<Elementtype>::DeleteRe()//对于已排好序的线性表,删除所有重复元素的算法。
{
this->Sort();//内置了排序功能
int i, j;
for (i = 0; i < len - 1; i++) {
Elementtype temp = elements[i];
for (j = i + 1; j < len; j++) {
if (elements[j] != temp)
break;
else
Delete1(j + 1);
}
}
}
顺序存储结构(SeqList)的删除算法重复元素算法测试代码及结果:
int a[] = { 1,999,87,87,7,5,5,7,9,10,31,541,521 };
SeqList<int> SL1(a, sizeof(a) / sizeof(int));
SL1.Print();
cout << "删除排序后的重复元素" << endl;
SL1.DeleteRe();
SL1.Print();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UdlOmS8B-1677332023086)(1.assets/2.png)]
链式存储结构(LinkList)的删除重复元素算法:
template<class Elementtype>
void LinkList<Elementtype>::Sort()//这里用的选择排序
{
for (Node<Elementtype>* p = first->next; p != NULL; p = p->next) {
Node<Elementtype>* min = p;
for (Node<Elementtype>* q = p->next; q != NULL; q = q->next) {
if (q->data < min->data)
min = q;
}
if (min != p) {//这里其实没有真正改变链表结构,只是交换了结构体的值
Elementtype temp = min->data;
min->data = p->data;
p->data = temp;
}
}
}
template<class Elementtype>
void LinkList<Elementtype>::DeleteRe()//对于已排好序的线性表,删除所有重复元素的算法。
{
this->Sort();//先排序
int count = 1;//计数器
for (Node<Elementtype>* p = first->next; p != NULL; p = p->next) {
Elementtype temp = p->data;
for (Node<Elementtype>* q = p->next; q != NULL; q = q->next) {
int n = count + 1;
if (q->data == temp)
this->Delete1(n);
n++;
}
count++;
}
}
链式存储结构(LinkList)的删除重复元素算法测试代码及结果:
int a[] = { 1,999,87,87,7,5,5,7,9,10,31,541,521 };
LinkList<int> LL1(a, sizeof(a) / sizeof(int));
LL1.Print();
cout << "删除排序后的重复元素" << endl;
LL1.DeleteRe();
LL1.Print();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jqeAodAy-1677332023086)(1.assets/3.png)]
③ 线性表“逆置”算法。
顺序存储结构(SeqList)的逆置算法:
template <class Elementtype>
void SeqList<Elementtype>::Reverse()//线性表“逆置”算法
{
int i = 0, j = len - 1;
for (i = 0; i != j; i++) {
Elementtype temp = elements[i];
elements[i] = elements[j];
elements[j] = temp;
j--;
}
}
顺序存储结构(SeqList)的逆置算法测试代码及结果:
int a[] = { 1,999,87,87,7,5,5,7,9,10,31,541,521 };
SeqList<int> SL1(a, sizeof(a) / sizeof(int));
SL1.Print();
cout << "逆置算法" << endl;
SL1.Reverse();
SL1.Print();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nQ51vJlc-1677332023086)(1.assets/4.png)]
链式存储结构(LinkList)的逆置算法:
template<class Elementtype>
void LinkList<Elementtype>::Reverse()//线性表“逆置”算法
{
Node<Elementtype>* end;
for (end = first->next; end->next != NULL; end = end->next);//找到末尾
Node<Elementtype>* q = end;
for (Node<Elementtype>* p = first->next; p != q; p = p->next) {
Node<Elementtype>* T = q;
Elementtype temp = p->data;
p->data = q->data;
q->data = temp;
for ( q=first->next ; q->next != T; q = q->next);//找末尾的前驱
}
}
链式存储结构(LinkList)的逆置算法测试代码及结果:
int a[] = { 1,999,87,87,7,5,5,7,9,10,31,541,521 };
LinkList<int> LL1(a, sizeof(a) / sizeof(int));
LL1.Print();
cout << "逆置算法" << endl;
LL1.Reverse();
LL1.Print();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4wD5MIkX-1677332023087)(1.assets/5.png)]
**④ 线性表循环左移/右移 k 位的算法。 **
顺序存储结构(SeqList)的循环左移/右移k位算法:
template <class Elementtype>
void SeqList<Elementtype>::MoveRight(int k)//循环右移
{
while (k--) {
Elementtype temp = elements[len - 1];
for (int i = len - 1; i > 0; i--) {
elements[i] = elements[i - 1];
}
elements[0] = temp;
}
}
template <class Elementtype>
void SeqList<Elementtype>::MoveLeft(int k)//循环左移
{
while (k--) {
Elementtype temp = elements[0];
for (int i = 0; i < len - 1; i++) {
elements[i] = elements[i + 1];
}
elements[len - 1] = temp;
}
}
顺序存储结构(SeqList)的循环左移/右移k位算法测试代码及结果:
int a[] = { 1,999,87,87,7,5,5,7,9,10,31,541,521 };
SeqList<int> SL1(a, sizeof(a) / sizeof(int));
SL1.Print();
cout << "右移两位" << endl;
SL1.MoveRight(2);
SL1.Print();
cout << "左移三位" << endl;
SL1.MoveLeft(3);
SL1.Print();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-npyvFrB5-1677332023087)(1.assets/6.png)]
链式存储结构(LinkList)的循环左移/右移k位算法:
template<class Elementtype>
void LinkList<Elementtype>::MoveRight(int k)//循环右移
{
while (k--)
{
Node<Elementtype>* end;
for (end = first->next; end->next != NULL; end = end->next);//找到末尾
Elementtype a = end->data;//用于临时保存末尾的数据
Node<Elementtype>* q = end;
while(q!=first->next) {
Node<Elementtype>* T = q;//最开始指向末尾
for (q = first->next; q->next != T; q = q->next);//把q变成T的前驱
T->data = q->data;
}
first->next->data = a;
}
}
template<class Elementtype>
void LinkList<Elementtype>::MoveLeft(int k)//循环左移
{
while (k--) {
Elementtype a = first->next->data;//用于临时保存第一个数据
Node<Elementtype>* p;
for ( p = first->next; p->next != NULL; p = p->next) {//循环出口为末尾
p->data = p->next->data;
}
p->data = a;
}
}
链式存储结构(LinkList)的循环左移/右移k位算法测试代码及结果:
int a[] = { 1,999,87,87,7,5,5,7,9,10,31,541,521 };
LinkList<int> LL1(a, sizeof(a) / sizeof(int));
LL1.Print();
cout << "右移两位" << endl;
LL1.MoveRight(2);
LL1.Print();
cout << "左移三位" << endl;
LL1.MoveLeft(3);
LL1.Print();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-akCoHvsR-1677332023087)(1.assets/7.png)]
⑤ 合并两个已排好序的线性表的算法。
顺序存储结构(SeqList)的合并算法://这里的合并算法排序并删除了重复元素
template <class Elementtype>
void SeqList<Elementtype>::MergeSeqList(SeqList& L) {
int i = L.len;
for (int j = 0; j < i; j++)
this->Insert(1, L.elements[j]);
this->DeleteRe();
}
顺序存储结构(SeqList)的合并算法测试代码及结果:
int a[] = { 1,999,87,87,7,5,5,7,9,10,31,541,521 };
int b[] = { 654,12,56,546,12,645,32 };
SeqList<int> SL1(a, sizeof(a) / sizeof(int));
SeqList<int> SL2(b, sizeof(b) / sizeof(int));
SL1.Print();
SL2.Print();
cout << "合并算法" << endl;
SL1.MergeSeqList(SL2);
SL1.Print();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8uWg5p4i-1677332023087)(1.assets/8.png)]
链式存储结构(LinkList)的合并算法://这里的合并算法未删除重复元素,所以二者结果有稍微不同。
template<class Elementtype>
void LinkList<Elementtype>::MergeSeqList(LinkList& L)//合并两个已排好序线性表的算法
{
Node<Elementtype>* q ;
for (q = L.first->next; q != NULL; q = q->next) {
this->Insert(1, q->data);
}
this->Sort();
}
链式存储结构(LinkList)的合并算法测试代码及结果:
int a[] = { 1,999,87,87,7,5,5,7,9,10,31,541,521 };
int b[] = { 654,12,56,546,12,645,32 };
LinkList<int> LL1(a, sizeof(a) / sizeof(int));
LinkList<int> LL2(b, sizeof(b) / sizeof(int));
LL1.Print();
LL2.Print();
cout << "合并算法" << endl;
LL1.MergeSeqList(LL2);
LL1.Print();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QflWu4iN-1677332023087)(1.assets/9.png)]
设计线性表的静态单向链表存储结构,并实现线性表的“逆置”算法。
静态单向链表的类模板代码:
const int Maxsize = 100;
template<class DataType>
struct SNode {
DataType data;
int next;
};
template<class DataType>
class StaticLinkList {
public:
StaticLinkList();//无参构造,初始化静态链表
void BuildList(int L);//在静态链表空间中创建一个线性表实例,即把游标位置从可用空间表中移除
int GetNode();//相当于NEW操作
void FreeNode(int q);//回收操作
void Insert(DataType x, int p);
void Delete(int p);//参数为数组位置,删的实际是SList[p].next
void Reverse(int L);//参数为游标头
void print(int L);
int FindEnd(int L);//查找一个游标指向线性表的末尾位置
public:
SNode<DataType> SList[Maxsize];
int av;//标识线性表
int len;//记录线性表长度
};
初始化及在数组中创建以游标为标志的线性表:
template<class DataType>
StaticLinkList<DataType>::StaticLinkList() {//无参构造,初始化静态链表
int j = 0;
for (j = 0; j < Maxsize - 1; j++)
SList[j].next = j + 1;
SList[j].next = -1;//最后一个为空
av = 0;//可用空间表
len = 0;
}
template<class DataType>
void StaticLinkList<DataType>::BuildList(int L)//在静态链表空间中创建一个线性表实例,即把游标位置从可用空间表中移除
{
int j = 0;
for (j = 0; SList[j].next != L; j= SList[j].next);//已经到了空闲表中游标的前驱
int i= SList[L].next;//空闲表中游标的后继
SList[j].next = i;
SList[L].next = -1;//初始化表头等于表尾
}
静态单向链表的逆置算法:
template<class DataType>
void StaticLinkList<DataType>::Reverse(int L) {
int i = FindEnd(L);//L表的末尾
int j ;
for (j = SList[L].next; j != i; j = SList[j].next) {
int temp = i;
DataType n = SList[j].data;//i,j前后交换
SList[j].data = SList[i].data;
SList[i].data = n;
for (i = j; SList[i].next != temp; i = SList[i].next);//找到i的前驱
}
}
template<class DataType>
int StaticLinkList<DataType>::FindEnd(int L)//查找一个游标指向线性表的末尾位置
{
int j;
for (j = L; SList[j].next != -1; j = SList[j].next);//到达末尾
return j;
}
静态单向链表的逆置算法的测试代码及结果:
int L = 2;//游标位置为2,相当于一个线性表实例
StaticLinkList<int> SLL;
SLL.BuildList(L);//以L为游标头在数组中创建一个线性表
for (int i = 1; i < 10; i++) //循环插入数据
SLL.Insert(i, L);
cout << "逆置前" << endl;
SLL.print(L);//因为是头插法,所以插入顺序和表中数据是反过来的
cout << "逆置后" << endl;
SLL.Reverse(L);
SLL.print(L);
SList[j].data = SList[i].data;
SList[i].data = n;
for (i = j; SList[i].next != temp; i = SList[i].next);//找到i的前驱
}
}
template
int StaticLinkList::FindEnd(int L)//查找一个游标指向线性表的末尾位置
{
int j;
for (j = L; SList[j].next != -1; j = SList[j].next);//到达末尾
return j;
}
静态单向链表的逆置算法的测试代码及结果:
```c++
int L = 2;//游标位置为2,相当于一个线性表实例
StaticLinkList<int> SLL;
SLL.BuildList(L);//以L为游标头在数组中创建一个线性表
for (int i = 1; i < 10; i++) //循环插入数据
SLL.Insert(i, L);
cout << "逆置前" << endl;
SLL.print(L);//因为是头插法,所以插入顺序和表中数据是反过来的
cout << "逆置后" << endl;
SLL.Reverse(L);
SLL.print(L);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pL3hXeX4-1677332023088)(刘虹志作业2.assets/456.png)]