内容:
实现书中代码
代码功能:
创建顺序表、插入、删除、查找、输出
代码内容:
#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++ 中,数组和指针之间存在密切的关系
-
动态数组:
-
当你通过
malloc
或new
为L.elem
分配内存时,你创建了对这块内存的动态分配,而不是在栈上定义一个固定大小的数组。 -
例如,
L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
是在堆上分配内存,这段内存可以看作是一个连续的区域,能够存储LIST_INIT_SIZE
个ElemType
类型的元素。
-
-
指针算术:
-
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:
使用>=而非使用==的原因:
-
当前长度和容量的关系:
L.length
表示当前线性表中元素的数量,而L.listsize
表示分配的空间容量。因此,当L.length
等于L.listsize
时,表已经满了,不能再插入新元素。而当L.length
超过L.listsize
时,依然会发生溢出,这是不允许的。所以>=
是更安全的判断条件。 -
避免潜在的溢出:使用
>=
可以确保在容量已满的情况下,不会进行插入操作。如果使用==
,只会在完全满的时候返回溢出状态,但如果其他部分代码不当处理,导致L.length
误增加到大于L.listsize
,可能会引发未定义行为或内存错误。
(2)删
①代码逻辑:
输入待删除元素位置、判断输入是否正确、记录要删除的元素、使用循环进行覆盖删除、更新长度
Tips:
覆盖删除的实现:
-
覆盖元素: 当你删除一个元素时(例如位置
i
的元素),代码并不会真正将该元素的内存释放,而是将该元素后面的所有元素向前移动一位,以覆盖被删除的元素。这种移动是通过循环实现的。 -
更新长度: 删除操作通过减少线性表的长度来反映当前有效元素的数量,而不是改变内存的分配。这样,原本的
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语句进行操作提示,以免不知道自己进行到了哪一步