线性表的顺序表示和实现
顺序表介绍
📢线性表的顺序表示指的是用一组地址连续的存储单元依次储存线性表的数据元素。这种储存结构的线性表称为顺序表(Sequential List)。
📌特点:逻辑上相邻的数据元素,其物理次序也是相邻的
只要确定了存储线性表的起始位置,线性表中任一数据元素都是可随机存储,所以线性表的顺序储存结构 是一种随机存取的储存结构。由于高级程序设计语言中的数组类型也有随机存取的特性,所以 通常用数组来描述数据结构中的顺序存储结构。
代码介绍
简要说明
(1)预定义常量及类型
#define OK 1 // 表示函数结果状态正常
#define ERROR 0 // 表示函数结果状态异常
#define OVERFLOW -2 // 异常退出 - 函数exit()
#define MAXSIZE 100 // 最大容量
typedef int Status; // Status是函数返回值类型,其值是函数结果状态代码
typedef int ElemType; //本文定义的数据类型是int型,其实际数据类型由用户自行定义(char、float...)
📢有关函数exit( )的内容请参考 http://t.csdn.cn/TfOHe
(2)声明函数
int menu (); // 菜单,提供用户选取操作,返回操作的序号
Status InitList (SqList *L); // 初始化顺序表L,分配空间
Status CreateList (SqList *L, int len); // 输入数据,创建长度为len的顺序表L
Status GetElem (SqList L, int i, ElemType *e); // 根据位置i,获取元素e
int LocateElem (SqList L, ElemType e); // 根据元素e,返回位置
Status ListInsert (SqList *L, int i, ElemType e); // 根据位置i,插入元素e
Status ListDelete (SqList *L, int i); // 根据位置i,删除元素
Status TraverseList (SqList L); // 输出顺序表中的所有内容
(3)顺序存储结构的类型定义
typedef struct {
ElemType *elem; // 用数组来描述
int length; // 来描述顺序表的长度
} SqList;
函数功能实现
菜单函数 int menu ();
int menu () {
int choose = 0;
printf("\t0.退出顺序表\n");
printf("\t1.初始顺序表\n");
printf("\t2.创建顺序表\n");
printf("\t3.顺序表取值\n");
printf("\t4.顺序表匹配\n");
printf("\t5.顺序表插入\n");
printf("\t6.顺序表删除\n");
printf("\t7.遍历顺序表\n\n");
printf("\t请输入你的选择:");
scanf("%d",&choose);
printf("\n");
return choose;
}
初始化函数 Status InitList (SqList *L);
Status InitList (SqList *L) {
L -> elem = (ElemType*) malloc (sizeof(ElemType) * MAXSIZE); // 为顺序表动态分配一个大小为MAXSIZE的数组空间
if (!L -> elem) exit(OVERFLOW); // 存储分配失败退出
L -> length = 0; // 空表长度为0
return OK;
}
创建函数 Status CreateList (SqList *L, int len);
Status CreateList (SqList *L, int len) {
if (!L -> elem) return ERROR; // 为空则失败
printf("请输入%d个数据(Tips:用空格隔开):", len);
L -> length = len; // 顺序表的长度
for (int i = 0; i < L -> length; i++)
scanf("%d", &L -> elem[i]); // 循环输入
return OK;
}
获取函数 Status GetElem (SqList L, int i, ElemType *e);
Status GetElem (SqList L, int i, ElemType *e) {
if (i < 1 || i > L.length) return ERROR; // 判断i值是否合理
*e = L.elem[i - 1]; // 提取该值
return OK;
}
时间复杂度为O(1)
匹配函数 int LocateElem (SqList L, ElemType e);
int LocateElem (SqList L, ElemType e) {
for (int i = 0; i < L -> length; i++)
if( L.elem[i] == e ) return i + 1; // 寻找该数据的位置
return 0;
}
时间复杂度为O(n)
插入函数 Status ListInsert (SqList *L, int i, ElemType e);
Status ListInsert (SqList *L, int i, ElemType e) {
if (i < 1 || i > L -> length + 1) return ERROR; // 判断i是否合理 注意i > L->length + 1
if (L -> length == MAXSIZE) return ERROR;
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 OK;
}
时间复杂度为O(n)
删除函数 Status ListDelete (SqList *L, int i);
Status ListDelete (SqList *L, int i) {
if (i < 1 || i > L -> length) return ERROR; // 判断i是否合理
for (int j = i; j <= L -> length - 1; j++)
L -> elem[j - 1] = L -> elem[j]; // 元素前移
--L -> length; //长度减一
return OK;
}
时间复杂度为O(n)
遍历函数 Status TraverseList (SqList L);
Status TraverseList (SqList L) {
if (!L.elem) return ERROR; // 为空则失败
for (int i = 0; i < L -> length; i++)
printf("%d ", L.elem[i]); // 循环输出
printf("\n");
return OK;
}
时间复杂度为O(n)
主函数 void main();
int main() {
int len = 0; // 顺序表的长度
int pos = 0; // 描述位置
int choose = -1; // 菜单选项,先定义为-1,进入while循环体
SqList L; // 定义顺序表L
ElemType num; // 描述顺序表中的数据元素elem
while (choose) {
system("cls"); // 清屏操作,界面更加美观
choose = menu(); // 菜单返回值
switch (choose) { // 进入switch
case 0:
printf("已成功退出!\n");
break;
// system("pause");的作用与上方的system("cls");有关,在用户enter以后执行清屏
// if else 的判断是有关函数结果状态的判断
case 1:
if (InitList (&L)) printf("初始化成功!\n");
system("pause");
break;
case 2:
// 书本上提出循环使用ListInsert函数进行内容输入,比较简单
printf("请输入顺序表长度:");
scanf("%d", &len);
if (CreateList (&L, len)) {
printf("创建成功!\n");
} else {
printf("创建失败!\n");
}
system("pause");
break;
case 3:
printf("请输入取值位置:");
scanf("%d", &pos);
if (GetElem(L, pos, &num)) {
printf("顺序表第%d位上是%d\n", pos, num);
} else {
printf("取值失败!\n");
}
system("pause");
break;
case 4:
printf("请输入查询内容:");
scanf("%d", &num);
if (pos = LocateElem(L, num)) {
printf("%d在顺序表的第%d位上\n", num, pos);
} else {
printf("查找失败!\n");
}
system("pause");
break;
case 5:
printf("请输入插入位置和内容(Tips:\" \"):");
scanf("%d%d", &pos, &num);
if (ListInsert(&L, pos, num)) {
printf("插入成功!\n");
} else {
printf("插入失败!\n");
}
system("pause");
break;
case 6:
printf("请输入删除位置:");
scanf("%d", &pos);
if (ListDelete(&L, pos)) {
printf("删除成功!\n");
} else {
printf("删除失败!\n");
}
system("pause");
break;
case 7:
if (TraverseList(L)) {
} else {
printf("遍历失败!");
}
system("pause");
break;
default: // choose不规范的情况
printf("输入错误!请重新输入!\n");
system("pause");
break;
}
}
system("pause");
return 0;
}
完整代码
/*
* @Author: Einstein
* @Date: 2023-01-31
*/
#include "stdio.h"
#include "stdlib.h"
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MAXSIZE 100
typedef int ElemType;
typedef int Status;
typedef struct {
ElemType *elem;
int length;
}SqList;
int menu (); // 菜单,提供用户选取操作,返回操作的序号
Status InitList (SqList *L); // 初始化顺序表L,分配空间
Status CreateList (SqList *L, int len); // 输入数据,创建长度为len的顺序表L
Status GetElem (SqList L, int i, ElemType *e); // 根据位置i,获取元素e
int LocateElem (SqList L, ElemType e); // 根据元素e,返回位置
Status ListInsert (SqList *L, int i, ElemType e); // 根据位置i,插入元素e
Status ListDelete (SqList *L, int i); // 根据位置i,删除元素
Status TraverseList (SqList L); // 输出顺序表中的所有内容
int main() {
int len = 0;
int pos = 0;
int choose = -1;
SqList L;
ElemType num;
while (choose) {
system("cls");
choose = menu();
switch (choose) {
case 0:
printf("已成功退出!\n");
break;
case 1:
if (InitList (&L)) printf("初始化成功!\n");
system("pause");
break;
case 2:
printf("请输入顺序表长度:");
scanf("%d", &len);
if (CreateList (&L, len)) {
printf("创建成功!\n");
} else {
printf("创建失败!\n");
}
system("pause");
break;
case 3:
printf("请输入取值位置:");
scanf("%d", &pos);
if (GetElem(L, pos, &num)) {
printf("顺序表第%d位上是%d\n", pos, num);
} else {
printf("取值失败!\n");
}
system("pause");
break;
case 4:
printf("请输入查询内容:");
scanf("%d", &num);
if (pos = LocateElem(L, num)) {
printf("%d在顺序表的第%d位上\n", num, pos);
} else {
printf("查找失败!\n");
}
system("pause");
break;
case 5:
printf("请输入插入位置和内容(Tips:\" \"):");
scanf("%d%d", &pos, &num);
if (ListInsert(&L, pos, num)) {
printf("插入成功!\n");
} else {
printf("插入失败!\n");
}
system("pause");
break;
case 6:
printf("请输入删除位置:");
scanf("%d", &pos);
if (ListDelete(&L, pos)) {
printf("删除成功!\n");
} else {
printf("删除失败!\n");
}
system("pause");
break;
case 7:
if (TraverseList(L)) {
} else {
printf("遍历失败!");
}
system("pause");
break;
default:
printf("输入错误!请重新输入!\n");
system("pause");
break;
}
}
system("pause");
return 0;
}
int menu () {
int choose = 0;
printf("\t0.退出顺序表\n");
printf("\t1.初始顺序表\n");
printf("\t2.创建顺序表\n");
printf("\t3.顺序表取值\n");
printf("\t4.顺序表匹配\n");
printf("\t5.顺序表插入\n");
printf("\t6.顺序表删除\n");
printf("\t7.遍历顺序表\n\n");
printf("\t请输入你的选择:");
scanf("%d",&choose);
printf("\n");
return choose;
}
Status InitList (SqList *L) {
L -> elem = (ElemType*) malloc (sizeof(ElemType) * MAXSIZE);
if (!L -> elem) exit(OVERFLOW);
L -> length = 0;
return OK;
}
Status CreateList (SqList *L, int len) {
if (!L -> elem) return ERROR;
printf("请输入%d个数据(Tips:用空格隔开):", len);
L -> length = len;
for (int i = 0; i < L -> length; i++)
scanf("%d", &L -> elem[i]);
return OK;
}
Status GetElem (SqList L, int i, ElemType *e) {
if (i < 1 || i > L.length) return ERROR;
*e = L.elem[i - 1];
return OK;
}
int LocateElem (SqList L, ElemType e) {
for (int i = 0; i < L.length; i++)
if( L.elem[i] == e ) return i + 1;
return 0;
}
Status ListInsert (SqList *L, int i, ElemType e) {
if (i < 1 || i > L -> length + 1) return ERROR;
if (L -> length == MAXSIZE) return ERROR;
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 OK;
}
Status ListDelete (SqList *L, int i) {
if (i < 1 || i > L -> length) return ERROR;
for (int j = i; j <= L -> length - 1; j++)
L -> elem[j - 1] = L -> elem[j];
--L -> length;
return OK;
}
Status TraverseList (SqList L) {
if (!L.elem) return ERROR;
for (int i = 0; i < L.length; i++)
printf("%d ", L.elem[i]);
printf("\n");
return OK;
}
Tips
(1)有关书本中&,例如InitList(&L)
📢以"&"打头的参数即为引用参数,是C++语言引用调用的参数传递方式。与传递指针的效果是一样的,但引用使用起来比指针更方便、高效。
📢有关内容请参考 http://t.csdn.cn/ROOpi
(2)有关书本InitList函数中new
📢new是C++中用于动态内存分配的运算符,在C语言中一般使用malloc函数。
📢有关内容请参考 http://t.csdn.cn/KL6Mu