文章目录
线性表-顺序表实验报告
记录于此,方便复习使用
一、概述
实验任务全部完成,基本掌握顺序表的基础操作,能够自行设计实验并完成。
顺序表的优势:
1.不需要为表示表中元素之间的逻辑关系而增加额外的存储空间
2.可以快速地存取表中任一位置的元素
局限:
1.插入删除操作需要移动大量元素
2.适用于存储规模容易确定的线性表
3.造成存储空间的碎片
二、实验设计及测试
0.头文件及基本常量数据类型等定义
#include<stdio.h>
#include<stdlib.h>
// 基本常量定义
// 顺序表存储大小
#define MAXSIZE 5
#define OK 1
#define ERROR 0
// 设置数据类型
typedef int ElemType;
typedef int Status;
typedef int Position;
typedef struct Seq_list{
ElemType *data;
int len;
int storage_size;
}Seq_list;
1. 初始化与销毁测试
初始化函数与销毁函数
// 初始化顺序表
// 无参数
// 成功返回指向空顺序表的指针,失败返回NULL
Seq_list * Init_Seq(){
Seq_list * seq_list;
// 申请内存
seq_list = (Seq_list*)malloc(sizeof(Seq_list));
// 申请是否成功?
if(!seq_list){
// 申请失败
return NULL;
}
// 申请数据存储内存
seq_list->data = (ElemType*)malloc(MAXSIZE*sizeof(ElemType));
if(!seq_list){
// 申请失败
// 释放刚申请的顺序表
free(seq_list);
return NULL;
}
// 申请成功,数据初始化
seq_list->len=0;
seq_list->storage_size=MAXSIZE;
return seq_list;
}
// 销毁顺序表
// 参数:顺序表指针
// 销毁成功返回OK反之ERROR
Status Destroy_Seq(Seq_list* seq_list){
if(seq_list){
if(seq_list->data){
free(seq_list->data);
}
free(seq_list);
return OK;
}
return ERROR;
}
测试程序
int main()
{
int i;
Seq_list * seq_list;
// 初始化测试模块
seq_list = Init_Seq();
if(seq_list){
printf("初始化成功\n");
}else{
printf("初始化失败\n");
}
//销毁测试模块
if(Destroy_Seq(seq_list)){
printf("销毁成功\n");
}else{
printf("销毁失败\n");
}
return 0;
}
测试结果
2.表空表满测试
判断 表空/表满函数
// 判断顺序表是否为空
// 参数:指向顺序表的指针
// 空返回OK,非空返回 ERROR
Status Is_Empty_Seq(Seq_list* seq_list){
if(seq_list->len==0){
return OK;
}
return ERROR;
}
// 判断顺序表是否为满
// 参数:指向顺序表的指针
// 满返回OK,反之ERROR
Status Is_Full_Seq(Seq_list* seq_list){
// len 记录当前元素个数
if(seq_list->len==MAXSIZE){
return OK;
}
return ERROR;
}
两个函数的时间复杂度均为O(1);
测试程序
int main()
{
ElemType t[MAXSIZE]={5,6,1,3,8};
int i;
Seq_list * seq_list;
// 初始化测试模块
seq_list = Init_Seq();
if(seq_list){
printf("初始化成功\n");
}else{
printf("初始化失败\n");
}
printf("\n\n\n");
// 表空表满测试
if(Is_Empty_Seq(seq_list)){
printf("顺序标为空\n");
}else{
printf("顺序表不为空\n");
}
if(Is_Full_Seq(seq_list)){
printf("顺序标已满\n");
}else{
printf("顺序表未满\n");
}
Set_Data(seq_list,t);
if(Is_Empty_Seq(seq_list)){
printf("顺序标为空\n");
}else{
printf("顺序表不为空\n");
}
if(Is_Full_Seq(seq_list)){
printf("顺序标已满\n");
}else{
printf("顺序表未满\n");
}
printf("\n\n\n");
//销毁测试模块
if(Destroy_Seq(seq_list)){
printf("销毁成功\n");
}else{
printf("销毁失败\n");
}
return 0;
}
结果
3.数据插入模块测试
插入函数和打印顺序表函数
// 插入数据
// 参数:顺序表指针,位置,元素值
// 返回 OK/ERROR
Status Insert_Seq(Seq_list* seq_list, Position i, ElemType e){
int j;
ElemType temp;
// 判断参数是否合法
if(i<0 || i>seq_list->len){
return ERROR;
}
// 判断表是否已满
if(Is_Full_Seq(seq_list)){
// 已满
return ERROR;
}
// 后移i后的位置,seq_list->len下标的位置为空
for(j=seq_list->len;j>i;j--){
seq_list->data[j]=seq_list->data[j-1];
}
seq_list->data[i]=e;
// 长度加一
seq_list->len++;
return OK;
}
// 遍历打印顺序表
// 参数:顺序表
// 成功返回OK失败ERROR
Status Print_Seq(Seq_list * seq_list){
Position i;
if(seq_list){
printf("表中数据为:\n");
for(i=0;i<seq_list->len;i++){
printf("%d ", seq_list->data[i]);
}
printf("\n");
return OK;
}
return ERROR;
}
插入函数和打印函数的时间复杂度均为O(n)
循环输入至超出最大长度
测试程序
void Get_Mod(Seq_list *s);
int main()
{
int i;
Seq_list * seq_list;
// 初始化测试模块
seq_list = Init_Seq();
if(seq_list){
printf("初始化成功\n");
}else{
printf("初始化失败\n");
}
// 调用测试
Get_Mod(seq_list);
//销毁测试模块
if(Destroy_Seq(seq_list)){
printf("销毁成功\n");
}else{
printf("销毁失败\n");
}
return 0;
}
void Get_Mod(Seq_list *s){
int i;
for(i=0;i<MAXSIZE+3;i++){
if(Insert_Seq(s,i,i)){
// 输入成功
printf("%d 输入成功\n", i);
}else{
printf("%d 输入失败\n", i);
}
}
Print_Seq(s);
}
输出
3.寻找数据模块测试
查找函数
// 按元素值查找相应元素位置
// 参数:顺序表指针,元素值, 记录下标的指针
// 找到返回OK反之ERROR
Status Location_By_Value_Seq(Seq_list* seq_list, ElemType e, Position* p){
Position i;
if(seq_list){
// seq_list->len下标处为空
for(i=0;i<seq_list->len;i++){
// 找到返回下标
if(seq_list->data[i]==e){
*p = i;
return OK;
}
}
}
// 找不到或seq_list为NULL
return ERROR;
}
// 按下标查找相应元素值
// 参数:顺序表指针,位置,记录元素值的指针
// 找到返回OK反之ERROR
Status Location_By_Index_Seq(Seq_list* seq_list, Position i, ElemType *e){
if(seq_list){
// seq_list->len下标处为空
if(i>=0&&i<seq_list->len){
*e = seq_list->data[i];
return OK;
}
}
return ERROR;
}
两种查找函数的时间复杂度均为O(n)
测试程序
// 设置测试数据函数
void Set_Data(Seq_list *s, ElemType * t){
int i;
for(i=0;i<MAXSIZE;i++){
Insert_Seq(s,i,t[i]);
}
Print_Seq(s);
printf("数据设置完成\n\n\n");
}
// 查找模块
void Find_Mod(Seq_list *s){
ElemType t[MAXSIZE]={5,6,1,3,8};
int i;
ElemType * e;
Set_Data(s,t);
printf("寻找下标为0,2,4,6(超过MAXSIZE)的元素值:\n");
for(i=0;i<=6;i++){
if(i%2==0){
if(Location_By_Index_Seq(s, i, e)){
printf("查找成功,下标为%d 的元素值为 %d \n", i, *e);
}else{
printf("查找失败,找不到下标为%d 的元素,出错了qwq\n",i);
}
}
}
printf("\n\n");
printf("寻找元素值为1,3,5,7(不存在)的元素下标:\n");
for(i=0;i<=7;i++){
if(i%2){
if(Location_By_Value_Seq(s, i, e)){
printf("查找成功,元素值为 %d 的下标为%d \n", i, *e);
}else{
printf("查找失败,找不到值为%d 的元素,出错了qwq \n",i);
}
}
}
}
出现问题
无法正常输出数值,只输出查找成功
调试过程
数值显示错误:使用指针错误,应该取用指针所指向的值 (漏了
*
号)只显示查找成功:逻辑使用出错,应使用 && 而不是 ||
输出
4.删除模块测试
删除函数
// 按下标删除元素
// 参数:顺序表指针,位置
// 删除返回OK反之ERROR
Status Del_By_Index_Seq(Seq_list* seq_list, Position i){
Position j;
// 判断参数是否合法
// seq_list->len下标处为空
if(i<0||i>=seq_list->len){
return ERROR;
}
// 判断表是否为空
if(Is_Empty_Seq(seq_list)){
return ERROR;
}
// 将i之后的所有元素前移一位
for(j=i;j<seq_list->len-1;j++){
seq_list->data[j] = seq_list->data[j+1];
}
// seq_list->len 记录哪些数据为有效数据,虽然此位置仍然有数据,但是不使用,即为无效数据,可视为空
seq_list->len--;
return OK;
}
// 按元素值删除所有的元素值
// 参数:顺序表指针,元素值
// 删除返回OK反之ERROR
Status Del_By_Value_Seq(Seq_list* seq_list, ElemType e){
Position i;
int flag = 0;
if(seq_list){
for(i=0;i<seq_list->len;i++){
if(seq_list->data[i]==e){
// 调用下标删除
Del_By_Index_Seq(seq_list, i);
flag++;
}
}
}
// 进行过删除flag即为真
if(flag){
return OK;
}
return ERROR;
}
两种删除函数的时间复杂度均为O(n)
测试程序
按下标删除
void Del_Mod(Seq_list *s){
ElemType t[MAXSIZE]={5,6,1,6,8};
Set_Data(s,t);
// 按下标删除
printf("删除下标为1的元素\n");
printf("执行删除前数据:\n");
Print_Seq(s);
if(Del_By_Index_Seq(s, 1)){
printf("下标为%d 的元素成功删除\n",1);
}else{
printf("删除失败\n");
}
printf("执行删除后数据:");
Print_Seq(s);
printf("\n");
printf("删除下标为6(不存在)的元素\n");
printf("执行删除前数据:");
Print_Seq(s);
if(Del_By_Index_Seq(s, 6)){
printf("下标为%d 的元素成功删除\n",6);
}else{
printf("删除失败\n");
}
printf("执行删除后数据:");
Print_Seq(s);
}
结果
按元素值进行删除
void Del_Mod(Seq_list *s){
ElemType t[MAXSIZE]={5,6,1,6,8};
ElemType e;
Set_Data(s,t);
// 按元素值删除
printf("删除值为3(不存在)的元素\n");
printf("执行删除前数据:\n");
Print_Seq(s);
if(Del_By_Value_Seq(s, 3)){
printf("值为%d 的元素成功删除\n",3);
}else{
printf("删除失败\n");
}
printf("执行删除后数据:");
Print_Seq(s);
printf("\n");
printf("删除值为6(两个)的元素\n");
printf("执行删除前数据:");
Print_Seq(s);
if(Del_By_Value_Seq(s, 6)){
printf("值为%d 的元素成功删除\n",6);
}else{
printf("删除失败\n");
}
printf("执行删除后数据:");
Print_Seq(s);
}
结果
三、评价分析
1.实验结果分析
顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。存放数据的部分操作方式与操作数组类似,因为都是存放在一块连续的内存空间上。按照元素值查找和删除时,只能一一比较,遍历整块内存地址,所以时间复杂度均为O(n)级别,而按照下标去删除或者与插入时,可以方便快速找到需要操作的位置,只不过需要移动大量数据来完成操作,降低效率。
2.算法性能分析
时间性能,查找O(1),插入或删除O(n)
空间性能,顺序表的存储空间是静态分配的,所以必须提前确定其内存大小。
适用于存储规模容易确定的线性表
总结和体会
顺序表优势:
无需为表示表中元素之间的逻辑关系而增加额外的存储空间
可以快速地存取表中任一位置的元素
局限:
插入删除操作需要移动大量元素
当线性表长度变化较大时,难以确定存储空间的容量
造成存储空间的碎片
注意指针的使用。
基本掌握顺序表的基础操作