一、实验目的
1、 熟练掌握线性表的结构特点,掌握顺序表的基本操作。
2、 巩固 C++相关的程序设计方法与技术。
3、 学会使用顺序表解决实际问题。
二、实验内容
1、顺序表的建立与操作实现
建立 n 个元素的顺序表(n 的大小和表里数据自己确定),实现相关的操作:输出,插入,删除,查找等功能。编写完整程序实现,程序语言不限定,使用技术形式不定。
2、实际问题的解决(*)
使用顺序表来实现约瑟夫环问题。
三、设计与编码
1.本实验用到的理论知识
(1)线性表的序号用数组的下标i表示,注意对线性表操作时其下标要在范围之内。
(2)建造线性表或在线性表中插入元素时,线性表的长度不能超过数组的最大长度。
2.算法设计
(1)定义SeqList类模板
class SeqList{
public:
SeqList(){length=0;} //建立一个空表
SeqList(int a[], int n); //带参构造函数
~SeqList(){} //析构函数
void Insert (int i, int x); //在第i个位置插入值为x的元素
int Delete (int i); //删除线性表中的第i个元素
int Locate (int x); //按值查找,在线性表中查找x的元素序号
int Get (int i); //按位查找,在线性表中查找第i个元素
void PrintList(); //遍历操作,按序号依次输出各元素
int getLength(){return length;} //获取线性表的长度
private:
int data[MaxSize];
int length; //线性表长度
};
(2)构造函数:无参构造函数建立一个空表,并给length赋值0;带参构造函数建立一个长度为n的顺序表a[],把length赋值为n,并把数组元素作为顺序表的元素传入顺序表中。
(3)获取线性表的长度:成员函数返回length的值。
(4)按值查找元素序号:①.定义一个布尔类型的变量b,开始赋值false,若有找到元素值为x,b赋值true,若b的值为false,表示没有找到。
②.遍历顺序表,如果元素值为x,输出该元素序号。
(5)按位置查找元素:查找顺序表的第i个元素只需返回类中数组下标为(i-1)的元素,注意查找位置要在顺序表序号范围内,否则抛出异常。
(6)插入元素:若表满了或元素插入位置不在范围之内则抛出异常。插入时,将最后一个元素到第i个元素依次往后移一个位置,再把x插入第i个位置;最后顺序表的长度加1。
(7)删除元素:若表是空表或删除元素位置不在范围之内则抛出异常。删除时把第i+1个元素到最后一个元素依次往前移一个位置,最后线性表的长度-1。
(8)遍历顺序表:依次打印线性表的数据元素。
3. 代码:
//#ifndef SeqList_H
//#define SeqList_H
#include<iostream.h>
const int MaxSize=10;
class SeqList
{
public:
SeqList(){length=0;} //建立一个空表
SeqList(int a[], int n); //带参构造函数
~SeqList(){} //析构函数
void Insert (int i, int x); //在第i个位置插入值为x的元素
int Delete (int i); //删除线性表中的第i个元素
int Locate (int x); //按值查找,在线性表中查找x的元素序号
int Get (int i); //按位查找,在线性表中查找第i个元素
void PrintList(); //遍历操作,按序号依次输出各元素
int getLength(){return length;} //获取线性表的长度
private:
int data[MaxSize];
int length; //线性表长度
};
//#endif
#include<iostream.h>
//#include "SeqList.h"
SeqList::SeqList(int a[],int n) //带参构造函数,建一个长度为n的顺序表
{
if(n>MaxSize)throw"参数非法\n";
for(int i=0;i<n;i++)
data[i]=a[i];
length=n;
}
void SeqList::Insert(int i,int x) //在第i个位置插入值为x的元素
{
if(length>=MaxSize)throw"上溢\n";
if(i<1||i>length+1)throw"\t\t位置非法\n";
for(int j=length;j>=i;j--)
data[j]=data[j-1];
data[i-1]=x;
length++;
}
int SeqList::Delete(int i) //删除线性表中的第i个元素
{
if(length==0)throw"\n\t\t下溢\n";
if(i<1||i>length)throw"\n\t\t位置非法\n";
int x=data[i-1];
for(int j=i;j<length;j++)
data[j-1]=data[j];
length--;
return x;
}
int SeqList::Locate(int x) //按值查找
{
for(int i=0;i<length;i++)
if(data[i]==x)return i+1;
return 0;
}
int SeqList::Get(int i) //按位查找
{
if(i<1&&i>length)throw"查找位置非法";
else return data[i-1];
}
void SeqList::PrintList() //遍历操作,按序号依次输出各元素
{
cout<<"\t\t序号\t出列的编号\n";
for(int i=0;i<length;i++)
cout<<"\t\t "<<i+1<<"\t "<<data[i]<<"\n";
cout<<"此时线性表的长度是:"<<i<<endl; //输出此时线性表的长度
}
#include <iostream.h>
//#include "SeqList.h"
void main()
{
int r[5]={1,2,3,4,5};
SeqList L(r,5);
cout<<"执行插入操作前数据:"<<endl;
L.PrintList();
try
{
L.Insert(2,3);
}
catch(char*s)
{
cout<<s<<endl;
}
cout<<"执行插入操作后数据:"<<endl;
L.PrintList();
cout<<"值为3的元素位置为:";
cout<<L.Locate(3)<<endl;
cout<<"第1个元素为:";
cout<<L.Get(1)<<endl;
cout<<"执行删除第一个元素操作,删除前数据为:"<<endl;
L.PrintList();
try
{
L.Delete(1);
}
catch(char*s)
{
cout<<s<<endl;
}
cout<<"删除后数据为:"<<endl;
L.PrintList();
}
四、运行与测试
(1)用数组r[5]={1,2,3,4,5};作为线性表的数据元素建立一个顺序表;查找第1个元素,结果是1;查找值为3的元素序号有2;在顺序表的第2个位置插入元素3,遍历顺序表插入成功;删除顺序表的第1个位置的元素,删除成功。
(2)若在建立顺序表时把给定数组的长度5改为15(MaxSize=10),输出异常(参数非法!);
(3)若查找第8个元素,输出异常(查找位置非法!);
(4)若在第0或第8个位置插入元素,输出异常(查找位置非法!);
(5)若删除第0或第8个位置的元素,输出异常(查找位置非法!);
五、总结与心得
通过这次实验复习了C++的大部分知识,但是代码的熟练程度有提高。
疑问:1.求线性表长度这个成员函数在哪里调用?
2.try{}catch{};抛出异常函数还没学,不太懂。
2、实际问题的解决(*)
使用顺序表来实现约瑟夫环问题。
c语言:
#include <stdio.h>
#define N 19
#define M 6
int main()
{
int players[N];// 所有人组成一个数组
int i = 0, j = 0, alive = N, n = 0;// 初始化变量
for (; i < N; i++) {
players[i] = 1; // 存活用 1 表示,出局就是 0
}
while (alive > 1) { // 只要不止一人存活,就循环下去
if (j >= N) {// 如果下标越界了,取余数,让其还是在数组下标范围内
j = j % N;
}
// 忽略出局的人
if (players[j] == 1) {
// 计算现在是第几个人了
n++;
if (n % M == 0) {// 如果这个人正好是倍数,进行出局处理
players[j] = 0; // 设置这个人出局
--alive;// 存活人数 - 1
}
}
j++;
}
for (i = 0; i < N; i++) { // 输出结果
if (players[i] == 1) {
printf("最后存活的人是:%d\n", i + 1);
break;
}
}
return 0;
}
顺序表:
#include<iostream.h>
const int MaxSize=70;
template<class S>
class SeqList{
private:
S data[MaxSize];
int length; //线性表的长度
public:
SeqList(){length=0;} //建一个空表
SeqList(int n);
~SeqList(){}
void Insert(int i,S x); //在第i个位置插入值为x的元素
int Delete(int i); //删除线性表中的第i个元素
S Get(int i); //按序号查找第i个元素
void Locate(S x); //按值查找元素序号
int GetLength(){return length;} //获取线性表的长度
void PrintList(); //遍历操作,按序号依次输出各元素
};
template<class S>
SeqList<S>::SeqList(int n){ //带参构造函数,建一个长度为n的顺序表
if(n>MaxSize) throw"参数非法!\n";
for(int i=0;i<n;i++) data[i]=i+1;
length=n;
}
template<class S>
void SeqList<S>::Insert(int i,S x){ //在第i个位置插入值为x的元素
if(length>=MaxSize) throw"上溢!\n";
if(i<1||i>length+1) throw"\t\t插入位置非法!\n";
for(int j=length;j>=i;j--){
data[j]=data[j-1];
}
data[i-1]=x;
length++;
}
template<class S>
int SeqList<S>::Delete(int i){ //删除线性表中的第i个元素
if(length==0) throw"\n\t\t下溢!\n";
if(i<1||i>length) throw"\n\t\t查找位置非法!\n";
int x=data[i-1];
for(int j=i;j<length;j++){
data[j-1]=data[j];
}
length--;
return x;
}
template<class S>
void SeqList<S>::PrintList(){ //遍历操作,按序号依次输出各元素
cout<<"\t\t序号\t出列的编号\n";
for(int i=0;i<length;i++){
cout<<"\t\t "<<i+1<<"\t "<<data[i]<<"\n";
}
cout<<"此时线性表的长度为:"<<i<<endl; //输出此时线性表的长度
}
int main(){
try{
int n,m,j,k=5,N;
cout<<"请输入玩游戏的人数:";
cin>>n;
SeqList<int> s1(n); //把n个人的编号按顺序存放到s1的顺序表中
cout<<"请输入开始报数的编号:";
cin>>m;
if(m<1||m>s1.GetLength())
throw"\t\t报数编号非法!\n";
cout<<"请输入要出列的编号:";
cin>>j; //报到k这个数的人(编号)出列
SeqList<int> s2; //建立顺序表s2
for(int i=0;s1.GetLength()>1;i++){
N=k; //计算报数的总次数
if(k>=n) //超出下标的最大值,则取k与n的余数
k=k%n;
if(N%j==0) //如果是出列编号j的倍数,则该数出列
s2.Insert(i+1,k);
m=k;
s1.Delete(k); //删除第k个元素
k=k+m+1; //进行第二次报数
}
s2.PrintList(); //输出出列的编号
}
catch(char *p)
{
cout<<p;
}
return 0;
}
疑问:顺序表的操作思路跟c语言的一样,为什么运行时总是出现“查找位置非法”?(而且我查找过没出现“ if(i<1||i>length) throw"\n\t\t查找位置非法!\n";”这种状况,求解答)