第1关:顺序表的插入操作

任务描述

本关任务:编写顺序表的初始化、插入、遍历三个基本操作函数。

相关知识

顺序表的存储结构

顺序表的存储结构可以借助于高级程序设计语言中的数组来表示,一维数组的下标与元素在线性表中的序号相对应。线性表的顺序存储结构可用C语言中动态分配的一维数组定义如下:

/*线性表的动态分配顺序存储结构(用一维数组)*/
#define INIT_SIZE 100
//线性表存储空间的初始分配量
#define INCREMENT 10
//线性表存储空间的分配增量
typedef  struct{  ElemType *elem;     //存储空间基地址  int     length;    //当前长度  int  listsize;     //当前分配的存储容量
}SqList;

在上述定义中,ElemType为顺序表中数据元素的类型,SqList是顺序表类型。

为了令算法具有通用性,使其尽可能地适用于各种可能的场合,将要处理的数据类型加以抽象,使其适用于不同类型的数据,是提高代码通用性的重要手段。

ElemType类型根据实际问题需要灵活定义:

/* 定义ElemType为int类型 */
typedef int ElemType;

或者,有学生数据类型定义如下:

typedef struct date
{  int year;    int month;    int day;
}DATE;
typedef struct student
{     int num;     char name[20];     char sex;     DATE birthday;     float score;}STUDENT;
/* 定义ElemType为STUDENT类型 */
typedef STUDENT ElemType;

顺序表中数据类型ElemType可以多种多样,但是在编程实现算法时针对不同数据类型,每类数据元素的输入输出是有区别的,顺序表的基本操作算法要在计算机上执行,须针对ElemType类型数据编写输入、输出、比较等函数:

void input(ElemType &s);void output(ElemType s);int equals(ElemType a,ElemType b);

C语言函数基本的参数传递机制是值传递,被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。如果需要将函数中变化的形式参数的值反映在实际参数中,在C语言的实现中,就需要通过指针变量作形式参数,接收变量的地址,达到修改实参变量值的目的。

C++语言中用引用作函数的形参,被调函数对形参做的任何操作都影响了主调函数中的实参变量值,而操作一个变量比操作一个指针要简单的多,为了便于算法描述,本书函数参数传递机制采用有两种方式:值传递和引用传递。如果不想修改实参的值,函数参数传递按值传递;如果需要修改实参的值,则使用引用传递。

举例说明,在定义输入函数void input(ElemType &s);时,在函数体内需要输入主调函数中的实参变量的值,也就是说要改变主调函数中的实参变量的值,因此函数形参定义为引用;在定义输出函数void output(ElemType s);时,在函数体内不需要改变主调函数中的实参变量的值,只需读取主调函数中的实参变量的值,因此函数形参定义为变量,采用值传递。

顺序表的初始化操作、销毁操作、插入操作和删除操作,在函数体内改变了顺序表L的数据成员的值,因此函数形参为引用。顺序表的查找操作、遍历操作,在函数体内不改变顺序表L的数据成员的值,函数形参为变量,采用值传递。

下面举例说明如何在线性表的顺序存储结构上实现线性表的基本操作。

顺序表的初始化操作

void InitList(SqList&L)
{ // 操作结果:构造一个空的顺序线性表L  L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));  if(!L.elem)  exit(-1); // 存储分配失败  L.length=0; // 空表长度为0  L.listsize=INIT_SIZE; // 初始存储容量
}

顺序表的遍历操作

void ListTraverse(SqList L,void(*vi)(ElemType ))
{   // 初始条件:顺序线性表L已存在    // 操作结果:依次对L的每个数据元素调用函数vi()      ElemType *p;       int i;           p=L.elem;       for(i=1; i<=L.length; i++)         vi(*p++);       printf("\n");
}

在执行ListTraverse()函数输出顺序表的所有数据元素时,用函数指针vi来实现对output()函数的调用。

在执行遍历函数输出顺序表的所有数据元素时,用函数指针vi来实现对output()函数的调用。

顺序表的插入运算

线性表的插入运算是指在表的第i (1≤i≤n+1)个位置,插入一个新元素x,使长度为n的线性表 ( a1,…,ai−1,ai,…,an) 变成长度为n+1的线性表( a1,…,ai−1,x,ai+1,…,an) 。

算法思想:用顺序表作为线性表的存储结构时,由于结点的物理顺序必须和结点的逻辑顺序保持一致,因此我们必须将原表中位置n-1,n-2,…,i-1上的结点,依次后移到位置n,n-1,…,i上,空出第i-1个位置,然后在该位置上插入新结点x。当i=n+1时,是指在线性表的末尾插入结点,所以无需移动结点,直接将x插入表的末尾即可。

算法分析:

  1. 最好的情况:当i=n+1时(插入尾元素),移动次数为0;

  1. 最坏的情况:当i=1时(插入第一个元素),移动次数为n;

平均情况:在位置i插入新元素x,需要将ai~an的元素均后移一次,移动次数为n-i+1。假设在等概率下pi(pi=1/(n+1)),移动元素的平均次数为:

插入算法的主要时间花费在元素移动上,所以算法平均时间复杂度为O(n)。

编程要求

根据提示,在右侧编辑器 Begin-End 区间补充代码,完成顺序表的初始化操作,遍历操作及插入操作三个子函数的定义,具体要求如下:

  • void InitList(SqList &L); //构造一个空的顺序表L

  • void ListTraverse(SqList L,void(*vi)(ElemType ));// 依次调用函数vi()输出顺序表L的每个数据元素

  • int ListInsert(SqList &L,int i,ElemType e);//在顺序表L中第i个位置之前插入新的数据元素

测试说明

平台会对你编写的代码进行测试:

输入说明 第一行输入顺序表的长度M; 第二行输入顺序表的M个整数; 第三行输入要插入元素的位置; 第四行输入要插入的数据元素的值。

输出说明 第一行输出插入是否成功的提示信息; 如果插入成功,第二行输出插入元素后的顺序表所有元素;如果插入失败,则不输出第二行。

测试输入: 5 12 47 5 8 69 1 99 预期输出: 插入成功,插入后顺序表如下: 99 12 47 5 8 69

测试输入: 5 12 47 5 8 69 7 99 预期输出: 插入位置不合法,插入失败!

开始你的任务吧,祝你成功!

实例代码


#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define INIT_SIZE 5
#define INCREMENT 10
# define OK 1
# define ERROR 0/* 定义ElemType为int类型 */
typedef int ElemType;
void input(ElemType &s);
void output(ElemType s);
int equals(ElemType a,ElemType b);/* 顺序表类型定义 */
typedef  struct
{ElemType *elem;    //存储空间基地址int    length;     //当前长度int  listsize;    //当前分配的存储容量
}SqList;
void InitList(SqList&L);
int ListInsert(SqList &L,int i,ElemType e);
void ListTraverse(SqList L,void(*vi)(ElemType ) );int main()               //main() function
{   SqList A;ElemType e;InitList(A);int n,i;// cout<<"Please input the list number ";cin>>n;for(i=1;i<=n;i++){ cin>>e;ListInsert(A, i, e);}//cout<<"请输入插入的位置:"<<endl;cin>>i;//cout<<"请输入插入的值:"<<endl;input(e);if(  ListInsert(A,i,e) ){cout<<"插入成功,插入后顺序表如下:"<<endl;ListTraverse(A,output) ;}elsecout<<"插入位置不合法,插入失败!"<<endl;return 0;
}/*****ElemType类型元素的基本操作*****/
void input(ElemType &s)
{cin>>s;
}
void output(ElemType s){cout<<s<<" ";
}
int equals(ElemType a,ElemType b)
{if(a==b)return  1;elsereturn  0;
}/*****顺序表的基本操作*****/
void InitList(SqList&L)
{   // 操作结果:构造一个空的顺序线性表L     /********** Begin **********/ L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));if(!L.elem)exit(-1); L.length=0; L.listsize=INIT_SIZE; /********** End **********/
}int  ListInsert(SqList &L,int i,ElemType e)
{   // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1// 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1/********** Begin **********/ if(L.length>=INIT_SIZE*sizeof(ElemType)||L.length<i-1||i<=0)return 0;for(int j=L.length-1;j>=i-1;j--){L.elem[j+1]=L.elem[j];}L.elem[i-1]=e;L.length++;return 1;/********** End **********/
}void ListTraverse(SqList L,void(*vi)(ElemType ) )
{   // 初始条件:顺序线性表L已存在// 操作结果:依次对L的每个数据元素调用函数vi()输出    /********** Begin **********/ ElemType *p;int i;p=L.elem;for(i=1; i<=L.length; i++)vi(*p++);cout<<endl;/********** End **********/
}

第2关:顺序表的删除操作

任务描述

本关任务:编写顺序表的删除操作函数。

相关知识

线性表的删除运算是指将表的第i(1≤i≤n)个元素删去,使长度为n的线性表 ( a1,…,ai−1,ai,ai+1,…,an),变成长度为n-1的线性表( a1,…,ai−1,ai+1,…,an)。

算法思想:在顺序表上实现删除运算必须移动结点,才能反映出结点间的逻辑关系的变化。若i=n,则只要简单地删除终端结点,无须移动结点;若1≤i≤n-1,则必须将表中位置i+1,i+2,…,n的结点,依次前移到位置i,i+1,…,n-1位置上,以填补删除操作造成的空缺。

算法分析:

  1. 最好的情况:当i=n时(删除尾元素),移动次数为0;

  1. 最坏的情况:当i=1时(删除第一个元素),移动次数为n-1;

  1. 平均情况:删除位置i的元素ai,需要将ai+1~an的元素均前移一次,移动次数为n-(i+1)+1=n-i。假设在等概率下pi(pi=1/n),移动元素的平均次数为:

删除算法的主要时间花费在元素移动上,所以算法的平均时间复杂度为O(n)。

编程要求

根据提示,在右侧编辑器 Begin-End 区间补充代码,完成顺序表的删除操作函数的定义,具体要求如下:

  • int ListDelete(SqList &L,int i,ElemType &e) //删除顺序表L的第i个数据元素,并用e返回其值,L的长度减1

测试说明

平台会对你编写的代码进行测试:

测试输入: 5 12 47 5 8 69 1 预期输出: 删除成功,删除后顺序表如下: 47 5 8 69 删除元素的值:12

测试输入: 5 12 47 5 8 69 6 预期输出: 删除位置不合法,删除失败!

输入说明 第一行输入顺序表的长度M; 第二行输入顺序表的M个整数; 第三行输入要删除元素的位置;

输出说明 第一行输出删除是否成功的提示信息; 如果删除成功,第二行输出删除元素后的顺序表;第三行输出删除的数据元素;如果删除位置不合法,不输出第二行和第三行。


开始你的任务吧,祝你成功!

实例代码

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define INIT_SIZE 5
#define INCREMENT 10/* 定义ElemType为int类型 */
typedef int ElemType;
void input(ElemType &s);
void output(ElemType s);
int equals(ElemType a,ElemType b);/* 顺序表类型定义 */
typedef  struct
{ElemType *elem;    //存储空间基地址int    length;     //当前长度int  listsize;    //当前分配的存储容量
}SqList;void InitList(SqList&L);
int  ListInsert(SqList &L,int i,ElemType e);
int  ListDelete(SqList &L,int i,ElemType&e) ;
void ListTraverse(SqList L,void(*vi)(ElemType ) );int main()               //main() function
{   SqList A;ElemType e;InitList(A);int n,i;// cout<<"Please input the list number ";cin>>n;for(i=1;i<=n;i++){ cin>>e;ListInsert(A, i, e);}//cout<<"请输入删除的位置:"<<endl;cin>>i;  if(  ListDelete(A,i,e) ){cout<<"删除成功,删除后顺序表如下:"<<endl;ListTraverse(A,output) ;cout<<"删除元素的值:";output(e);cout<<endl;}elsecout<<"删除位置不合法,删除失败!"<<endl;
}/*****ElemType类型元素的基本操作*****/
void input(ElemType &s)
{cin>>s;
}
void output(ElemType s)
{cout<<s<<" ";
}
int equals(ElemType a,ElemType b)
{if(a==b)return  1;elsereturn  0;
}/*****顺序表的基本操作*****/void InitList(SqList&L)
{   // 操作结果:构造一个空的顺序线性表L/********** Begin **********/ L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));if(!L.elem)return; // 存储分配失败L.length=0; // 空表长度为0L.listsize=INIT_SIZE; // 初始存储容量/********** End **********/
}int  ListInsert(SqList &L,int i,ElemType e)
{   // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1// 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1/********** Begin **********/ ElemType *newbase,*q,*p;if(i<1||i>L.length+1) // i值不合法return 0;if(L.length>=L.listsize){ // 当前存储空间已满,增加分配if(!(newbase=(ElemType*)realloc(L.elem,(L.listsize+INCREMENT)*sizeof(ElemType))))return(0); ; // 存储分配失败L.elem=newbase; // 新基址L.listsize+= INCREMENT; // 增加存储容量}q=L.elem+i-1; // q为插入位置for(p=L.elem+L.length-1;p>=q;--p) // 插入位置及之后的元素右移*(p+1)=*p;*q=e;            // 插入e++L.length;      // 表长增1return 1;/********** End **********/
}void ListTraverse(SqList L,void(*vi)(ElemType ) )
{ // 初始条件:顺序线性表L已存在// 操作结果:依次对L的每个数据元素调用函数vi()输出/********** Begin **********/ ElemType *p;int i;p=L.elem;for(i=1;i<=L.length;i++)vi(*p++);printf("\n");/********** End **********/
}int  ListDelete(SqList &L,int i,ElemType&e)
{// 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)// 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1/********** Begin **********/ if(i<1||i>L.length+1){return 0;}e = L.elem[i-1]; for(int j = i;j<L.length;j++){L.elem[j-1] = L.elem[j];}L.length--;       return e;/********** End **********/
}

第3关:顺序表的按照序号查找值操作

任务描述

本关任务:编写顺序表的按照序号i查找数据元素值的操作函数。

相关知识

顺序表L已存在,先判断i值是否合法,如果合法,将顺序表L中第i个数据元素的值赋给e,e要带出函数体,类型声明为引用。

编程要求

根据提示,在右侧编辑器 Begin-End 区间补充代码,完成顺序表的按照序号查找操作函数的定义,具体要求如下:

  • int GetElem(SqList L,int i,ElemType &e);//用e返回顺序表L中第i个数据元素的值

测试说明

平台会对你编写的代码进行测试:

测试输入: 10 12 47 5 8 6 92 45 63 75 38 8

预期输出: 查找成功! 第8个元素的值: 63

测试输入: 10 12 47 5 8 6 92 45 63 75 38 11

预期输出: 查找失败!

输入说明 第一行输入顺序表的长度M; 第二行输入顺序表的M个整数; 第三行输入要查找的序号;

输出说明 第一行输出按照序号查找是否成功的提示信息; 如果查找成功,输出查找的元素的值;如果查找失败,则不输出。


开始你的任务吧,祝你成功!

实例代码

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define INIT_SIZE 5
#define INCREMENT 10
# define OK 1
# define ERROR 0/* 定义ElemType为int类型 */
typedef int ElemType;
void input(ElemType &s);
void output(ElemType s);
int equals(ElemType a,ElemType b);/* 顺序表类型定义 */
typedef  struct
{ElemType *elem;    //存储空间基地址int    length;     //当前长度int  listsize;    //当前分配的存储容量
}SqList;
void InitList(SqList&L);
int ListInsert(SqList &L,int i,ElemType e);
void ListTraverse(SqList L,void(*vi)(ElemType ) );
int GetElem(SqList L,int i,ElemType&e);int main()               //main() function
{   SqList A;ElemType e;InitList(A);int n,i;// cout<<"Please input the list number ";cin>>n;for(i=1;i<=n;i++){ cin>>e;ListInsert(A, i, e);}//cout<<"请输入查找的序号:"<<endl;cin>>i;  if(  GetElem(A,i,e) ){cout<<"查找成功!"<<endl;cout<<"第"<<i<<"个元素的值:"<<endl;output(e);cout<<endl;}elsecout<<"查找失败!"<<endl;
}/*****ElemType类型元素的基本操作*****/
void input(ElemType &s)
{cin>>s;
}
void output(ElemType s){cout<<s<<" ";
}
int equals(ElemType a,ElemType b)
{if(a==b)return  1;elsereturn  0;
}/*****顺序表的基本操作*****/
void InitList(SqList&L)
{   // 操作结果:构造一个空的顺序线性表L/********** Begin **********/ L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));if(!L.elem)return; // 存储分配失败L.length=0; // 空表长度为0L.listsize=INIT_SIZE; // 初始存储容量/********** End **********/
}int  ListInsert(SqList &L,int i,ElemType e)
{   // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1// 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1/********** Begin **********/ ElemType *newbase,*q,*p;if(i<1||i>L.length+1) // i值不合法return 0;if(L.length>=L.listsize){ // 当前存储空间已满,增加分配if(!(newbase=(ElemType*)realloc(L.elem,(L.listsize+INCREMENT)*sizeof(ElemType))))return(0); ; // 存储分配失败L.elem=newbase; // 新基址L.listsize+= INCREMENT; // 增加存储容量}q=L.elem+i-1; // q为插入位置for(p=L.elem+L.length-1;p>=q;--p) // 插入位置及之后的元素右移*(p+1)=*p;*q=e;            // 插入e++L.length;      // 表长增1return 1;/********** End **********/
}void ListTraverse(SqList L,void(*vi)(ElemType ) )
{ // 初始条件:顺序线性表L已存在// 操作结果:依次对L的每个数据元素调用函数vi()输出/********** Begin **********/ ElemType *p;int i;p=L.elem;for(i=1;i<=L.length;i++)vi(*p++);printf("\n");/********** End **********/
}int GetElem(SqList L,int i,ElemType&e)
{//初始条件:顺序线性表L已存在,1≤i≤ListLength(L)。//操作结果:用e返回L中第i个数据元素的值/********** Begin **********/ if(i<1||i>L.length)return 0;e=L.elem[i-1];return e;/********** End **********/
}

第4关:顺序表的按照值查找序号操作

任务描述

本关任务:编写顺序表按照值查找序号操作的函数。

相关知识

在顺序表L找第一个值为e的元素,找到后返回其逻辑序号,否则返回0。

注意:由于线性表的逻辑序号从1开始,这里用0表示没有找到值为e的元素。

在算法实现时,应根据顺序表数据元素的类型ElemType编写判断两个数据元素是否相等的比较函数equals()。举例说明: (1)数据元素的类型ElemType为int类型

typedef  int  ElemType;
int equals(ElemType a,ElemType b)
{ // 根据两个整数a,b是否相等,分别返回1或0       if (a == b)         return 1;       else           return 0;}

(2)数据元素的类型ElemType为char [20] 类型

typedef  char  ElemType[20];
int equals (ElemType a,ElemType b)
{ // 根据两个字符串a、b是否相等,分别返回1或0        if ( strcmp(a,b) == 0 )         return 1;       else           return 0;
}

(3)数据元素的类型ElemType为自定义结构体变量类型,判断两个数据元素是否相等,就需要比较所有结构体变量成员。

struct student{
char num[20];
char name[16];
int  year;
float  score;
};
typedef  struct student  ElemType;
int equals (ElemType a,ElemType b)
{   // 如果a,b的所有成员值相等,返回1,否则返回0    if ( ( strcmp( a.num, b.num ) != 0 )        return 0;    else  if ( strcmp( a.name, b.name ) != 0 )        return 0;    else  if  ( a.year != b.year )         return 0;       else  if ( a.score != b. score ) )           return 0;    else        return 1;}

编程要求

根据提示,在右侧编辑器 Begin-End 区间补充代码,完成顺序表的按照值查找序号操作函数的定义,具体要求如下:

  • int LocateElem(SqList L,ElemType e,int (*equal) (ElemType , ElemType) );// 返回顺序表L中第1个与e满足相等关系equal()的数据元素的位序,若这样的数据元素不存在,则返回值为0。

测试说明

平台会对你编写的代码进行测试:

测试输入: 10 12 47 5 8 6 92 45 63 75 38 92

预期输出: 查找成功! 92 是顺序表第6个元素

测试输入: 10 12 47 5 8 6 92 45 63 75 38 93

预期输出: 查找失败!

输入说明 第一行输入顺序表的长度M; 第二行输入顺序表的M个整数; 第三行输入要查找的数据元素的值。

输出说明 第一行输出按照值查找是否成功的提示信息; 如果查找成功,第二行输出查找元素的逻辑序号;如果查找失败,则不输出。


开始你的任务吧,祝你成功!

实例代码

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define INIT_SIZE 5
#define INCREMENT 10
# define OK 1
# define ERROR 0/* 定义ElemType为int类型 */
typedef int ElemType;
void input(ElemType &s);
void output(ElemType s);
int equals(ElemType a,ElemType b);/* 顺序表类型定义 */
typedef  struct
{ElemType *elem;    //存储空间基地址int    length;     //当前长度int  listsize;    //当前分配的存储容量
}SqList;void InitList(SqList&L);
int  ListInsert(SqList &L,int i,ElemType e);
void ListTraverse(SqList L,void(*vi)(ElemType ) );
int LocateElem(SqList L,ElemType e,int (*compare) (ElemType , ElemType));int main()               //main() function
{   SqList A;ElemType e;InitList(A);int n,i;// cout<<"Please input the list number ";cin>>n;for(i=1;i<=n;i++){ cin>>e;ListInsert(A, i, e);}//cout<<"请输入查找的元素:"<<endl;cin>>e;  i=LocateElem(A,e,equals);if( i ) {cout<<"查找成功!"<<endl;        output(e);cout<<"是顺序表第"<<i<<"个元素"<<endl;}elsecout<<"查找失败!"<<endl;
}/*****ElemType类型元素的基本操作*****/
void input(ElemType &s)
{cin>>s;
}
void output(ElemType s)
{cout<<s<<" ";
}
int equals(ElemType a,ElemType b)
{if(a==b)return  1;elsereturn  0;
}/*****顺序表的基本操作*****/void InitList(SqList&L)
{   // 操作结果:构造一个空的顺序线性表L/********** Begin **********/ L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));if(!L.elem)return; // 存储分配失败L.length=0; // 空表长度为0L.listsize=INIT_SIZE; // 初始存储容量/********** End **********/
}int  ListInsert(SqList &L,int i,ElemType e)
{   // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1// 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1/********** Begin **********/ ElemType *newbase,*q,*p;if(i<1||i>L.length+1) // i值不合法return 0;if(L.length>=L.listsize){ // 当前存储空间已满,增加分配if(!(newbase=(ElemType*)realloc(L.elem,(L.listsize+INCREMENT)*sizeof(ElemType))))return(0); ; // 存储分配失败L.elem=newbase; // 新基址L.listsize+= INCREMENT; // 增加存储容量}q=L.elem+i-1; // q为插入位置for(p=L.elem+L.length-1;p>=q;--p) // 插入位置及之后的元素右移*(p+1)=*p;*q=e;            // 插入e++L.length;      // 表长增1return 1;/********** End **********/
}void ListTraverse(SqList L,void(*vi)(ElemType ) )
{ // 初始条件:顺序线性表L已存在// 操作结果:依次对L的每个数据元素调用函数vi()输出/********** Begin **********/ ElemType *p;int i;p=L.elem;for(i=1;i<=L.length;i++)vi(*p++);printf("\n");/********** End **********/
}int LocateElem(SqList L,ElemType e,int (*compare) (ElemType , ElemType))
{// 初始条件:顺序表L已存在,compare()是数据元素判定函数(满足为1,否则为0)// 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。// 若这样的数据元素不存在,则返回值为0。/********** Begin **********/ int i=0;for (i=0;i<L.length;i++){if(compare(e,L.elem[i])){return i+1; }}return 0;/********** End **********/}

第5关:顺序表的逆置操作

任务描述

本关任务:编写顺序表的逆置操作函数。

相关知识

关于逆置,有一种非常暴力的解决方法,就是单独开辟一个同等大小的顺序表,然后新表从前往后遍历,同时原表从后往前遍历,依次赋值,最后得到的就是逆置后的顺序表。但这种方法的空间复杂度为O(n),所以并不能这么做。

顺序表的就地逆置,只需让顺序表中的数据元素头尾依次交换即可,即交换第一个元素和最后一个元素,第二个和倒数第二个,依此类推,这种方法的空间复杂度为O(1)。

编程要求

根据提示,在右侧编辑器 Begin-End 区间补充代码,完成顺序表的逆置操作函数的定义:

  • void reverse(SqList &A); //将顺序表就地逆置

测试说明

平台会对你编写的代码进行测试:

测试输入: 10 12 47 5 8 6 92 45 63 75 38

预期输出: 逆置顺序表: 38 75 63 45 92 6 8 5 47 12

输入说明 第一行输入顺序表的长度M; 第二行输入顺序表的M个整数;

输出说明 第一行输出提示信息; 第二行输出逆置后的顺序表。


开始你的任务吧,祝你成功!

代码示例

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define INIT_SIZE 5
#define INCREMENT 10
# define OK 1
# define ERROR 0/* 定义ElemType为int类型 */
typedef int ElemType;
void input(ElemType &s);
void output(ElemType s);
int equals(ElemType a,ElemType b);/* 顺序表类型定义 */
typedef  struct
{ElemType *elem;    //存储空间基地址int    length;     //当前长度int  listsize;    //当前分配的存储容量
}SqList;void InitList(SqList&L);
int  ListInsert(SqList &L,int i,ElemType e);
void ListTraverse(SqList L,void(*vi)(ElemType ) );
void reverse(SqList &A);
int main()               //main() function
{   SqList A;ElemType e;InitList(A);int n,i;// cout<<"Please input the list number ";cin>>n;for(i=1;i<=n;i++){ cin>>e;ListInsert(A, i, e);}cout<<"逆置顺序表:"<<endl;reverse(A);ListTraverse(A,output) ;
}/*****ElemType类型元素的基本操作*****/
void input(ElemType &s)
{cin>>s;
}
void output(ElemType s)
{cout<<s<<" ";
}
int equals(ElemType a,ElemType b)
{if(a==b)return  1;elsereturn  0;
}/*****顺序表的基本操作*****/void InitList(SqList&L)
{   // 操作结果:构造一个空的顺序线性表L/********** Begin **********/ L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));if(!L.elem)return; // 存储分配失败L.length=0; // 空表长度为0L.listsize=INIT_SIZE; // 初始存储容量/********** End **********/
}int  ListInsert(SqList &L,int i,ElemType e)
{   // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1// 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1/********** Begin **********/ ElemType *newbase,*q,*p;if(i<1||i>L.length+1) // i值不合法return 0;if(L.length>=L.listsize){ // 当前存储空间已满,增加分配if(!(newbase=(ElemType*)realloc(L.elem,(L.listsize+INCREMENT)*sizeof(ElemType))))return(0); ; // 存储分配失败L.elem=newbase; // 新基址L.listsize+= INCREMENT; // 增加存储容量}q=L.elem+i-1; // q为插入位置for(p=L.elem+L.length-1;p>=q;--p) // 插入位置及之后的元素右移*(p+1)=*p;*q=e;            // 插入e++L.length;      // 表长增1return 1;/********** End **********/
}void ListTraverse(SqList L,void(*vi)(ElemType ) )
{ // 初始条件:顺序线性表L已存在// 操作结果:依次对L的每个数据元素调用函数vi()输出/********** Begin **********/ ElemType *p;int i;p=L.elem;for(i=1;i<=L.length;i++)vi(*p++);printf("\n");/********** End **********/
}/********** 定义 void reverse(SqList &A)函数**********/
void reverse(SqList &A)
{/********** Begin **********/ int  temp;for (int i = 0; i < (A.length / 2); i++) {temp = A.elem[i];A.elem[i] = A.elem[A.length - 1 - i];A.elem[A.length - 1 - i] = temp;}/********** End **********/
}

第6关:两个有序顺序表的合并操作

任务描述

本关任务:分别输入两个有序的整数序列(分别包含M和N个数据),建立两个有序顺序表,编写将这两个有序顺序表合并成为一个大的有序顺序表的合并操作函数。

相关知识

已知有两个按元素值递增有序的顺序表A和B。设计一个算法将顺序表A和B的全部元素归并到一个按元素递增有序的顺序表C中。

算法思想:用i遍历顺序表A,用j遍历顺序表B。当A和B都未遍历完时,比较两者的当前元素,则将较小者复制到C中,若两者的当前元素相等,则将这两个元素都复制到C中。最后将尚未遍历完的顺序表的余下元素均复制到顺序表C中。

本算法的空间复杂度为O(1),时间复杂度为O(n+m),其中n和m分别为顺序表A和B的长度。

要注意,如果顺序表中数据类型ElemType是结构体类型,结构体变量之间整体是不可以比较大小的,结构体变量之间只能比较某个成员的大小;比较两个结构体变量是否相等与比较两个结构体变量某个成员的大小也是有区别的。

编程要求

根据提示,在右侧编辑器 Begin-End 区间补充代码,完成两个有序顺序表的合并操作函数的定义:

  • int MergeList(SqList La, SqList Lb, SqList &Lc) ;// 归并La和Lb得到新的顺序表Lc,Lc的元素也按值非递减排列。

测试说明

平台会对你编写的代码进行测试:

测试输入: 5 10 15 20 25 30 6 12 22 32 42 52 62

输入说明 第一行输入有序表A的长度M; 第二行依次输入有序表A的M个有序的整数; 第三行输入有序表B的长度N; 第四行依次输入有序表B的N个有序的整数。

预期输出: 合并两个有序顺序表: 10 12 15 20 22 25 30 32 42 52 62

输出说明 第一行输出提示信息; 第二行输出合并后的有序顺序表所包含的M+N个有序的整数。


开始你的任务吧,祝你成功!

代码示例

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define INIT_SIZE 5
#define INCREMENT 10/* 定义ElemType为int类型 */
typedef int ElemType;
void input(ElemType &s);
void output(ElemType s);
int equals(ElemType a,ElemType b);/* 顺序表类型定义 */
typedef  struct
{ElemType *elem;    //存储空间基地址int    length;     //当前长度int  listsize;    //当前分配的存储容量
}SqList;
void InitList(SqList&L);
int  ListInsert(SqList &L,int i,ElemType e);
void ListTraverse(SqList L,void(*vi)(ElemType ) );
int MergeList(SqList La, SqList Lb, SqList &Lc) ;int main()               //main() function
{   SqList A,B,C;ElemType e;InitList(A);InitList(B);int n,i;// cout<<"Please input the list number ";cin>>n;for(i=1;i<=n;i++){ cin>>e;ListInsert(A, i, e);}cin>>n;for(i=1;i<=n;i++){ cin>>e;ListInsert(B, i, e);}cout<<"合并两个有序顺序表:"<<endl;MergeList(A,B,C);  ListTraverse(C,output) ;
}/*****ElemType类型元素的基本操作*****/
void input(ElemType &s)
{cin>>s;
}
void output(ElemType s)
{cout<<s<<" ";
}
int equals(ElemType a,ElemType b)
{if(a==b)return  1;elsereturn  0;
}/*****顺序表的基本操作*****/
void InitList(SqList&L)
{   // 操作结果:构造一个空的顺序线性表L/********** Begin **********/ L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));if(!L.elem)return; // 存储分配失败L.length=0; // 空表长度为0L.listsize=INIT_SIZE; // 初始存储容量/********** End **********/
}int  ListInsert(SqList &L,int i,ElemType e)
{   // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1// 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1/********** Begin **********/ ElemType *newbase,*q,*p;if(i<1||i>L.length+1) // i值不合法return 0;if(L.length>=L.listsize){ // 当前存储空间已满,增加分配if(!(newbase=(ElemType*)realloc(L.elem,(L.listsize+INCREMENT)*sizeof(ElemType))))return(0); ; // 存储分配失败L.elem=newbase; // 新基址L.listsize+= INCREMENT; // 增加存储容量}q=L.elem+i-1; // q为插入位置for(p=L.elem+L.length-1;p>=q;--p) // 插入位置及之后的元素右移*(p+1)=*p;*q=e;            // 插入e++L.length;      // 表长增1return 1;/********** End **********/
}void ListTraverse(SqList L,void(*vi)(ElemType ) )
{ // 初始条件:顺序线性表L已存在// 操作结果:依次对L的每个数据元素调用函数vi()输出/********** Begin **********/ ElemType *p;int i;p=L.elem;for(i=1;i<=L.length;i++)vi(*p++);printf("\n");/********** End **********/
}int MergeList(SqList La, SqList Lb, SqList &Lc)
{  // 已知顺序线性表La和Lb的元素按值非递减排列。// 归并La和Lb得到新的顺序线性表Lc,Lc的元素也按值非递减排列。/********** Begin **********/ Lc.length=La.length+Lb.length;Lc.elem=new ElemType[Lc.length];int *pa=La.elem,*pb=Lb.elem,*pc=Lc.elem;int *pa_last=La.elem+La.length-1,*pb_last=Lb.elem+Lb.length-1;while((pa<=pa_last)&&(pb<=pb_last))
{if(*pa<=*pb)*pc++=*pa++;else*pc++=*pb++;}
while(pa<=pa_last)*pc++=*pa++;while(pb<=pb_last)*pc++=*pb++;/********** End **********/
}

【头歌】顺序表的基本操作相关推荐

  1. Tsai笔记:C++学习随性笔记(2)—— 数据结构:顺序表的基本操作

    Tsai笔记:C++学习随性笔记(2)-- 数据结构:顺序表的基本操作 Tsai三步.(第一步,功能说明.第二步,结果图显示.第三步,代码展示) 第一步,功能说明. 1.线性表的顺序存储 线性表的顺序 ...

  2. c++实现顺序表的基本操作

    顺序表 数组描述方法将元素存储在一个数组中,用一个数学公式来确定每个元素存储的位置,即在数组中的索引.这是最简单的一种存储方式,所有元素依次存储在一片连续的存储空间中,这就是通常所说的顺序表.   - ...

  3. 顺序表的基本操作(C语言)

    1.要求 编程实现顺序表的基本操作,并设计一个菜单调用. ①建立(初始化).遍历.取值.查找.插入.删除 ②判空.求元素个数.前驱.后继.置为空表.销毁 2.分析 我们需要去定义一个结构体(以下代码的 ...

  4. C++:顺序表的基本操作(待完善)

    根据命令提示进行顺序表的基本操作(待完善) #include<iostream> #include<algorithm> using namespace std; #defin ...

  5. PTA 顺序表的基本操作

    原题有50分,这个答案有45分,欢迎指出不足 ;) 6-2 顺序表基本操作 (50 分) 实现顺序表的基本操作,如初始化.插入.删除.输出等. 注意:顺序表中可有重复元素值. 要求:写出三个基本操作函 ...

  6. 编程实现顺序表的基本操作

    void InitList(SqList &L)//建立空顺序表函数 voidListInsert(SqList &L, int i, ElemType e) //在顺序表中第i个位置 ...

  7. 顺序表的基本操作(详细、全面)

    顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素.使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素 ...

  8. 线性表之顺序表的基本操作

    线性表的定义 线性表是具有相同数据类型的 n ( n > = 0 ) n(n>= 0) n(n>=0)个数据元素的有限序列,其中 n n n为表长,当 n = 0 n=0 n=0时线 ...

  9. 线性表-顺序表的基本操作

    线性表的定义和特点 线性表:由n(n≥0)个数据特性相同的元素构成的有限序列 线性表中元素的个数n(n≥0)称为线性表的长度 空表:n=0 对于非空的线性表或线性结构,特点为: 存在唯一的一个被称作& ...

最新文章

  1. java需要记的语法,Java笔记(三)……基础语法
  2. 项目管理过程中,如何编制初步工作说明书
  3. linux下配置 ITK
  4. 026_图书管理案例
  5. 关于Transformer,面试官们都怎么问?
  6. 程序员跳槽全攻略pdf
  7. 英特尔第十代处理器为什么不支持win7_5GHz动力澎湃 高主频多核处理器成就巅峰玩家...
  8. java excel 2007兼容包_Office 2007兼容包官方下载_2007 Office system 兼容包免费版下载-华军软件园...
  9. 《统计会犯错——如何避免数据分析中的统计陷阱》一导读
  10. Jira中的Tempo查看component以及issue的工作量汇总
  11. vsftp登录失败_VSFTP虚拟账户无法登陆530 Login incorrect错误解决方法 | 系统之家官网...
  12. 网络编程:网络协议简介
  13. VBA怎样关闭工作簿和退出Excel
  14. JAVA下载文件的几_详解Java文件下载的几种实现方式
  15. 【毕设教程】单片机RFID模块的使用 - 物联网 嵌入式 毕业设计 stm32
  16. 张正友标定法几个坐标系的意思
  17. js监听手机返回按键操作,禁用返回按键操作。
  18. 【源码分享】jquery+css实现侧边导航栏
  19. SpringCloud五大神器(对比Dubbo+Zookeeper)
  20. 【C语言】PCM音频数据处理---左右声道分离

热门文章

  1. python自动填写问卷_Python填写问卷星
  2. centos7 挂载 硬盘 shell 懒人系列-2
  3. houseoforange_hitcon_2016(unsortbin attack,fsop)
  4. ARM汇编之MOV指令
  5. C++中类成员函数指针使用方法
  6. Java实现单向链表基本功能
  7. 2023复旦大学计算机考研经验分享
  8. C++异常(异常的基本语法、栈解旋unwinding、异常接口声明、异常变量的生命周期、异常的多态使用、C++系统标准异常库)
  9. 论文中绘制神经网络工具汇总
  10. Sniper模拟器的安装