10.5 顺序表实践

内容:

实现书中代码

代码功能:

创建顺序表、插入、删除、查找、输出

代码内容:

#include<stdio.h>
#include<malloc.h>
#define LIST_INIT_SIZE 100//线性表初始分配空间的容量
#define LISTINCREMENT 10//线性表增加分配空间的量
#define ERROR 0
#define OK 1
#define OVERFLOW -2
typedef int ElemType;
typedef int Status;

typedef struct
{
	ElemType* elem;
	int length;
	int listsize;
}SqList;

Status SqList_Create(SqList& L, int n)//创建一个长度为n的顺序表L
{
	L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));//分配预定大小的空间
	if (!L.elem)//如果空间分配失败
		return OVERFLOW;
	L.listsize = LIST_INIT_SIZE;
	L.length = n;
	for(int i = 0;i < L.length;i++)
		scanf_s("%d", &L.elem[i]);//输入顺序表中各个元素
	return OK;
}
Status SqList_Insert(SqList& L, int i, ElemType e)//在顺序表L中第i个元素前插入新元素e,其中i的合法值是1<=i<=n+1
{
	if (i<1 || i>L.length + 1)//插入位置不正确
		return ERROR;
	if (L.length >= L.listsize)//顺序表L空间已满
		return OVERFLOW;
	for (int j = L.length - 1;j >= i - 1;j--)
		L.elem[j + 1] = L.elem[j];//将第i个元素及后续元素位置向后移一位
	L.elem[i - 1] = e;//在第i个元素位置处插入新元素e
	L.length++;//顺序表L的长度加1
	return OK;
}
Status SqList_Delete(SqList& L, int i, ElemType& e)//在顺序表L中删除第i个元素,并用e返回值,其i的合法值是1<=i<=n
{
	if (i<1 || i>L.length)//删除位置不正确
		return ERROR;
	e = L.elem[i - 1];
	for (int j = i;j <= L.length - 1;j++)
		L.elem[j - 1] = L.elem[j];//将第i+1个元素及后继元素位置向前移一位
	L.length--;//顺序表的长度减1
	return OK;
}

int SqList_Search(SqList L, ElemType e)//在顺序表中查找值为e的元素,如果找到,则函数返回该元素在顺序表中的位置,否则返回0
{
	int i;
	for (i = 1;i <= L.length && L.elem[i - 1] != e;i++);//从第i个元素起依次将每个元素值与给定值e比较
	if (i <= L.length)
		return i;
	else
		return 0;
}

void SqList_Output(SqList L)//输出顺序表L中各个元素值
{
	for (int i = 0;i < L.length;i++)
		printf("%d ", L.elem[i]);
	printf("\n");
}

int main()
{
	SqList L;
	int i, n;
	ElemType e;

	scanf_s("%d", &n);//输入顺序表的长度
	SqList_Create(L, n);
	SqList_Output(L);//输出顺序表中各元素值
	scanf_s("%d", &i);//输入插入位置
	scanf_s("%d", &e);//输入待插入元素值
	if (SqList_Insert(L, i, e) == 1)
		SqList_Output(L);//输出插入后的顺序表
	else
		printf("Intsertion failed!\n");

	scanf_s("%d", &i);//输入删除位置
	if (SqList_Delete(L, i, e) == 1)
	{
		SqList_Output(L);//输出删除后的顺序表
		printf("%d\n", e);
	}
	else
		printf("Deleteion failed!\n");

	scanf_s("%d", &e);//输入待查找元素值
	if (SqList_Search(L, e))
		printf("%d Search succeeded!\n", SqList_Search(L, e));//输出查找到的元素所在的位置
	else
		printf("Search failed!\n");
	return 0;
}

代码思路:

1、编写主体架构:

引入头文件、定义常/变量、定义顺序存储结构、创建顺序表、编写输出模块、创建主函数

#include<stdio.h>
#include<malloc.h>
#define LIST_INIT_SIZE 100
#define ERROR 0
#define OK 1
#define OVERFLOW -2
typedef int ElemType;
typedef int Status;

typedef struct
{
	ElemType* elem;//线性表存储空间的基地址
	int length;
	int listsize;
}SqList;//动态的顺序存储结构类型名

Status SqList_Create(SqList& L, int n)//创建一个长度为n的顺序表L
{
	L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));//分配预定大小的空间
	if (!L.elem)//如果空间分配失败
		return OVERFLOW;
	L.listsize = LIST_INIT_SIZE;
	L.length = n;
	for(int i = 0;i < L.length;i++)
		scanf_s("%d", &L.elem[i]);//输入顺序表中各个元素
	return OK;
}

void SqList_Output(SqList L)//输出顺序表L中各个元素值
{
	for (int i = 0;i < L.length;i++)
		printf("%d ", L.elem[i]);
	printf("\n");
}

int main()
{
    
    return 0;
}
(1)引入头文件
#include<stdio.h>//引入标准输入输出库
#include<malloc.h>//引入内存分配库
(2)定义常/变量
#define LIST_INIT_SIZE 100//定义表容量
#define ERROR 0//定义状态码
#define OK 1//定义状态码
#define OVERFLOW -2//定义状态码
typedef int ElemType; // 元素类型定义为整型
typedef int Status; // 状态类型定义为整型
(3)定义顺序存储结构
typedef struct
{
	ElemType* elem;//线性表存储空间的基地址
	int length;
	int listsize;
}SqList;//动态的顺序存储结构类型名
(4)创建顺序表
Status SqList_Create(SqList& L, int n)//创建一个长度为n的顺序表L
{
	L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));//分配预定大小的空间
	if (!L.elem)//如果空间分配失败
		return OVERFLOW;
	L.listsize = LIST_INIT_SIZE;
	L.length = n;
	for(int i = 0;i < L.length;i++)
		scanf_s("%d", &L.elem[i]);//输入顺序表中各个元素
	return OK;
}
①代码思路:
构建函数原型
Status SqList_Create(SqList& L, int n)

包括返回类型、名称、参数类型

在SqList& L中,&为C++用法,表示引用。引用&有丰富的内涵及用法,在此我只将其理解为创建一个名为L的线性表,长度为n

编写函数体

分配存储空间、判定、设置初始值、输入数据、返回状态码

{
	L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));//分配预定大小的空间
	if (!L.elem)//如果空间分配失败
		return OVERFLOW;
	L.listsize = LIST_INIT_SIZE;
	L.length = n;
	for(int i = 0;i < L.length;i++)
		scanf_s("%d", &L.elem[i]);//输入顺序表中各个元素
	return OK;
}

内存分配malloc,模板:指针 = (数据类型*)malloc(数组大小 * sizeof(数据类型));

其中第一个*,(ElemType*)表示的是强制类型转换,因为原本malloc函数的返回值类型为void*,而此处的L.elem为(ElemType*)类型,故需强制转换。

而第二个*则表示的是乘法,(LIST_INIT_SIZE * sizeof(ElemType)表示数量*空间大小,得到需要分配的存储空间大小,用sizeof函数获得ElemType所占的字节大小(此处ElemType为int型,4字节)

关于为什么可以直接使用 &L.elem[i],而不需事先定义 L.elem为数组

在 C 或 C++ 中,数组和指针之间存在密切的关系

  1. 动态数组

    • 当你通过 malloc 或 new 为 L.elem 分配内存时,你创建了对这块内存的动态分配,而不是在栈上定义一个固定大小的数组。

    • 例如,L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType)); 是在堆上分配内存,这段内存可以看作是一个连续的区域,能够存储 LIST_INIT_SIZE 个 ElemType 类型的元素。

  2. 指针算术

    • L.elem 是一个指向 ElemType 的指针,它指向分配的内存的开始位置。

    • 由于 L.elem 是指针,你可以使用数组下标语法来访问这块内存中的元素,比如 L.elem[i]

即,当为L.elem分配内存后,指针L.elem指向一个连续的空间,可等同于开辟了一块数组空间,由此可用数组的方式输入数据

(5)编写输出模块
void SqList_Output(SqList L)//输出顺序表L中各个元素值
{
	for (int i = 0;i < L.length;i++)
		printf("%d ", L.elem[i]);
	printf("\n");
}
(6)创建主函数
int main()
{
    
    return 0;
}

2、编写功能模块:增删(改)查

(1)增(插入)
        ①代码逻辑:

判断插入位置是否正确、判满、移位、插入、增加表长、返回状态码

Status SqList_Insert(SqList& L, int i, ElemType e)//在顺序表L中第i个元素前插入新元素e,其中i的合法值是1<=i<=n+1
{
	if (i<1 || i>L.length + 1)//插入位置不正确
		return ERROR;
	if (L.length >= L.listsize)//顺序表L空间已满
		return OVERFLOW;
	for (int j = L.length - 1;j >= i - 1;j--)
		L.elem[j + 1] = L.elem[j];//将第i个元素及后续元素位置向后移一位
	L.elem[i - 1] = e;//在第i个元素位置处插入新元素e
	L.length++;//顺序表L的长度加1
	return OK;
}
        ②代码解读
判满

如果目前表长大于等于设定表长,则空间已满,返回溢出码

if (L.length >= L.listsize)//顺序表L空间已满
		return OVERFLOW;
tips:

使用>=而非使用==的原因:

  1. 当前长度和容量的关系L.length 表示当前线性表中元素的数量,而 L.listsize 表示分配的空间容量。因此,当 L.length 等于 L.listsize 时,表已经满了,不能再插入新元素。而当 L.length 超过 L.listsize 时,依然会发生溢出,这是不允许的。所以 >= 是更安全的判断条件。

  2. 避免潜在的溢出:使用 >= 可以确保在容量已满的情况下,不会进行插入操作。如果使用 ==,只会在完全满的时候返回溢出状态,但如果其他部分代码不当处理,导致 L.length 误增加到大于 L.listsize,可能会引发未定义行为或内存错误。

(2)删
        ①代码逻辑:

输入待删除元素位置、判断输入是否正确、记录要删除的元素、使用循环进行覆盖删除、更新长度

        Tips:

覆盖删除的实现:

  1. 覆盖元素: 当你删除一个元素时(例如位置 i 的元素),代码并不会真正将该元素的内存释放,而是将该元素后面的所有元素向前移动一位,以覆盖被删除的元素。这种移动是通过循环实现的。

  2. 更新长度: 删除操作通过减少线性表的长度来反映当前有效元素的数量,而不是改变内存的分配。这样,原本的 elem 数组仍然在内存中,未被释放,只是表示该位置的元素不再有效。

Status SqList_Delete(SqList& L, int i, ElemType& e)//在顺序表L中删除第i个元素,并用e返回值,其i的合法值是1<=i<=n
{
	if (i<1 || i>L.length)//删除位置不正确
		return ERROR;
	e = L.elem[i - 1];
	for (int j = i;j <= L.length - 1;j++)
		L.elem[j - 1] = L.elem[j];//将第i+1个元素及后继元素位置向前移一位
	L.length--;//顺序表的长度减1
	return OK;
}
(3)查
        ①代码逻辑:

输入待查找元素值、使用for循环在表内查找、判断该元素是否在表内

int SqList_Search(SqList L, ElemType e)//在顺序表中查找值为e的元素,如果找到,则函数返回该元素在顺序表中的位置,否则返回0
{
	int i;
	for (i = 1;i <= L.length && L.elem[i - 1] != e;i++);//从第i个元素起依次将每个元素值与给定值e比较
	if (i <= L.length)
		return i;
	else
		return 0;
}
        ②代码解读:
for (i = 1;i <= L.length && L.elem[i - 1] != e;i++);

该查找代码只有一行,末端以分号“;”结尾,而无需其他语句。这是因为该代码仅用括号内的内容就可实现查找功能。

形式为:使用计数器,采用循环遍历的方式对表内元素进行比对,并用计数器i进行进度记录。若待查找元素不在表内,则该语句会遍历整个表,最终计数器i的值将会大于表长,以此判断待查找元素是否在表内。

3、编写主函数

int main()
{
	SqList L;
	int i, n;
	ElemType e;

	scanf_s("%d", &n);//输入顺序表的长度
	SqList_Create(L, n);
	SqList_Output(L);//输出顺序表中各元素值
	scanf_s("%d", &i);//输入插入位置
	scanf_s("%d", &e);//输入待插入元素值
	if (SqList_Insert(L, i, e) == 1)
		SqList_Output(L);//输出插入后的顺序表
	else
		printf("Intsertion failed!\n");

	scanf_s("%d", &i);//输入删除位置
	if (SqList_Delete(L, i, e) == 1)
	{
		SqList_Output(L);//输出删除后的顺序表
		printf("%d\n", e);
	}
	else
		printf("Deleteion failed!\n");

	scanf_s("%d", &e);//输入待查找元素值
	if (SqList_Search(L, e))
		printf("%d Search succeeded!\n", SqList_Search(L, e));//输出查找到的元素所在的位置
	else
		printf("Search failed!\n");
	return 0;
}
(1)代码逻辑:

定义所需常/变量、演示功能

4、注意事项

编写代码演示模块的时候务必使用printf语句进行操作提示,以免不知道自己进行到了哪一步

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值