【头歌】顺序表的基本操作

news2024/9/23 13:28:25

第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) ;
    }
    else
    	cout<<"插入位置不合法,插入失败!"<<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;
	else
		return  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;
	}
	else
		cout<<"删除位置不合法,删除失败!"<<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;
	else
		return  0;
}

/*****顺序表的基本操作*****/

void InitList(SqList&L) 
{	// 操作结果:构造一个空的顺序线性表L
 	/********** Begin **********/ 
	L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));
	if(!L.elem)
		return; // 存储分配失败
	L.length=0; // 空表长度为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 **********/ 
	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;      // 表长增1
	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++);
	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;
	}
	else
		cout<<"查找失败!"<<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;
	else
		return  0;
}

/*****顺序表的基本操作*****/
void InitList(SqList&L) 
{	// 操作结果:构造一个空的顺序线性表L
 	/********** Begin **********/ 
	L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));
	if(!L.elem)
		return; // 存储分配失败
	L.length=0; // 空表长度为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 **********/ 
	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;      // 表长增1
	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++);
	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;
	}
	else
		cout<<"查找失败!"<<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;
	else
		return  0;
}

/*****顺序表的基本操作*****/

void InitList(SqList&L) 
{	// 操作结果:构造一个空的顺序线性表L
 	/********** Begin **********/ 
	L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));
	if(!L.elem)
		return; // 存储分配失败
	L.length=0; // 空表长度为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 **********/ 
	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;      // 表长增1
	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++);
	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;
	else
		return  0;
}

/*****顺序表的基本操作*****/

void InitList(SqList&L) 
{	// 操作结果:构造一个空的顺序线性表L
 	/********** Begin **********/ 
	L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));
	if(!L.elem)
		return; // 存储分配失败
	L.length=0; // 空表长度为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 **********/ 
	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;      // 表长增1
	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++);
	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;
	else
		return  0;
}

/*****顺序表的基本操作*****/
void InitList(SqList&L) 
{	// 操作结果:构造一个空的顺序线性表L
 	/********** Begin **********/ 
	L.elem=(ElemType*)malloc( INIT_SIZE*sizeof(ElemType));
	if(!L.elem)
		return; // 存储分配失败
	L.length=0; // 空表长度为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 **********/ 
	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;      // 表长增1
	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++);
	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 **********/
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/176741.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv5/v7 引入 YOLOv8 的 C2f 模块

YOLOv8 项目地址&#xff1a;https://github.com/ultralytics/ultralytics YOLOv8 Ultralytics YOLOv8 是由 Ultralytics 开发的一个前沿的 SOTA 模型。它在以前成功的 YOLO 版本基础上&#xff0c;引入了新的功能和改进&#xff0c;进一步提升了其性能和灵活性。YOLOv8 基于快…

C 指针变量 取地址符的用法 *指针变量名的用法

文章目录IntroCode图示Intro C语言中有一类特殊的变量&#xff1a;指针变量(pointer variable)&#xff0c;用于存储某个变量的内存地址的值。 要打印指针变量一般用%p格式符&#xff0c;会打印出该指针变量的值&#xff0c;即一个内存值。 Code // Created by wuyujin1997 …

【Linux】进程概念一

进程概念一 冯诺依曼体系结构 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系。 截止目前为止&#xff0c; 我们所认识的计算机&#xff0c;都是一个个的硬件组成 输入设备&#xff1a;包括键盘&#x…

如何使用JDBC操作数据库?JDBC API的使用详细解读

文章目录1. DriverManager1.1 注册驱动1.2 获取连接2. Connection2.1 获取执行sql的对象2.2 事务管理3. Statement4. ResultSet5. PreparedStatement5.1 sql注入问题5.2 preparedStatement 原理6. 总结Java编程基础教程系列1. DriverManager DriverManager &#xff0c;驱动管…

C++模板不支持分离编译的问题

目录前言分离编译模式普通函数的分离编译(正常)模板函数的分离编译(出错)分析解决方式拓展--extern关键字extern"C"extern变量extern模板--控制实例化前言 分离编译模式 一个项目如果有多个源文件.c组成&#xff0c;每个源文件单独编译&#xff0c;形成目标文件。最…

Kubernetes:分享一个可以展示资源视图的 K8s开源 Web/桌面 客户端工具 Octant

写在前面 博文内容主要为 Octant 介绍以及 桌面/Web 端的安装教程涉及 Linux/Windows 的安装。理解不足小伙伴帮忙指正 其实当你什么都经历了&#xff0c;会发现&#xff0c;人生无论你怎么精心策划都抵不过一场命运的安排。 Octant 不是仪表板&#xff0c;Octant 是一个带有仪…

数据结构 最短路径课设(源码+实验报告+视频讲解)(不要钱、用了自取)

XIAN TECHNOLOGICAL UNIVERSITY 课程设计报告 实验课程名称 算法与数据结构 专 业&#xff1a; 班 级&#xff1a; 姓 名&#xff1a; 学 号&#xff1a; 实验学时&#xff1a; 指导…

Linux Debian11安装QT6开发环境

从Qt5.14开始&#xff0c;官方不提供离线安装包&#xff0c;只提供源码包和在线安装器。但是清华为我们提供了快速的在线安装方式。 一.下载清华提供的在线安装器 在线安装器下载链接 二、给在线安装器文件赋予执行权限 三、配置镜像地址运行安装器 清华源&#xff1a; ./…

7.Java判断和循环+面试相关力扣算法题详解

提示&#xff1a; 文章目录前言一、顺序结构二、分支语句(1)if语句(2)switch语句*default的位置和省略:*case穿透*switch新特性*switch和if的第三种格式各自的使用场景三、循环结构1.分类2.for循环3.while循环4.for和while的对比:5.for和while循环的区别:6.练习:四、面试时的两…

【安卓】zoo for zotero WebDAV 自动论文同步笔记

前言 前言是我写这篇博客的动机&#xff0c;可以跳过直接从“准备”开始看 之前使用mendeley管理文献&#xff0c;它不仅可以同步文件&#xff0c;还跨平台&#xff08;win、安卓等&#xff09;。但是后面&#xff0c;mendeley停止了移动平台的支持&#xff0c;导致我不能用我…

JQUERY案例

电梯导航 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, i…

一、pyhon准备工作篇(黑马程序猿-python学习记录)

黑马程序猿的python学习视频&#xff1a;https://www.bilibili.com/video/BV1qW4y1a7fU/ 目录 1. python官网 2. 检查是否安装完毕 3. pycharm官网 5. phcharm更换主题 6. 新建第一个python文件 7. pycharm字体大小设置 ​​​​​​​8. 设置快捷键 设置字体大小 ​​​​​​…

AJAX 简介

AJAX 是一种在无需重新加载整个网页的情况下&#xff0c;能够更新部分网页的技术。 AJAX 是什么&#xff1f; AJAX Asynchronous JavaScript and XML. AJAX 是一种用于创建快速动态网页的技术。 AJAX 通过在后台与服务器进行少量数据交换&#xff0c;使网页实现异步更新。这…

第三章 关系数据库标准语言SQL

第三章 关系数据库标准语言SQL 目录第三章 关系数据库标准语言SQL3.1 SQL概述3.1.1 产生与发展3.1.2 SQL的特点3.1.3 SQL的基本概念3.2 数据库实例3.3 数据定义3.3.1 模式的定义和删除3.2.2基本表的定义、删除和修改1.常见数据类型2.定义基本表3.修改基本表4.删除基本表5.模式和…

2. 返回传播计算方法|神经网络整体架构|神经元个数对结果的影响|正则化与激活函数|神经网络过拟合解决方法

文章目录返回传播计算方法神经网络整体架构&#xff08;暂时留存&#xff0c;等后面补&#xff09;神经元个数对结果的影响正则化与激活函数神经网络过拟合解决方法返回传播计算方法 实际上计算L&#xff08;损失值&#xff09;的时候并不是只是拿一组w来进行计算&#xff0c;…

用过MyBatis-Plus,我再也不想用mybatis了——MyBatis-Plus快速入门加常见注解总结,一文快速掌握MyBatis-Plus

相比与mybatis只做增强&#xff0c;不做修改 MyBatis-Plus学习笔记一&#xff0c;是什么二&#xff0c;入门案例1.建库建表2.创建spring Boot工程3.配置相关包及类4.测试三&#xff0c;基本的curd1.BaseMapper2.通用Service四.常用注解1.TableName2.TableId3TableField4.TableL…

【python】面向对象编程

文章目录一、函数大全1.1 匿名函数 lambda1.2 过滤函数 filter1.3 format1.4 try和except1.5 位置参数和关键字参数二、类与对象2.1创建对象2.2 封装的实现方式2.3 继承2.4方法重写2.5 object 类2.5.1 __str()__2.5.2 dict()2.5.3 len()2.5.4 add()2.5.5 new()init()2.6 多态的…

初识C语言(下)

写在前面 好了,现在我们开始C语言的第二个部分.今天我们需要看下面几个知识点,都是非常简单的,我们主要认识一下. 数组 我们知道一个一个属性可以用一个类型去表示,那么我想问的是如果是一个属性的多个呢?也就是多个一样的东西,此时我们就要使用数组来进行表示,所谓的数组就…

22. 输入和输出

1. 输出格式美化 (1) 如果你希望输出的形式更加多样&#xff0c;可以使用 str.format() 函数来格式化输出值。 (2) 如果你希望将输出的值转成字符串&#xff0c;可以使用 repr() 或 str() 函数来实现。   str()&#xff1a; 函数返回一个用户易读的表达形式。   repr()&am…

产品原型设计方法

产品原型设计方法1. 色彩选择与按钮设计1.1色彩选择1.2 按钮设计2. 使用原型设计中的基础元素2.1 使用文字元素2.2 使用图标元素3. 设计导航菜单栏和卡片式布局3.1设计导航菜单栏4.3 设计卡片式布局4. 使用UI框架4.1 使用UI框架的好处4.2 常用的UI框架1. 色彩选择与按钮设计 1…