《C语言动态顺序表:从内存管理到功能实现》
1.顺序表
1.1 概念
- 顺序存储的线性表,叫顺序表。
1.2顺序表存放的实现方式
- 可以使用数组存储数据,可以实现逻辑上相连,物理内存上也相连。
- 也可以使用malloc在堆区申请一片连续的空间,存放数据,实现逻辑上相连,物理内存上也相连。
1.3 顺序表的组成
- 需要一片连续的空间,存放数据。 可以是数组,也可以是连续堆区空间
- 还需要一个变量来记录当前顺序表的长度。(已存放的元素个数)
1.4 对顺序表长度的解析
- 顺序表的长度能够表示顺序表中实际使用的元素个数
- 也能够表示数组中第一个没有存放数据元素的数组元素下标
- 要遍历整个顺序表时,顺序表的长度是最大上限
1.5 顺序表结构体类型
#define MAX 20 //顺序表最大容量
typedef int datatype; //数据元素类型//定义顺序表结构体类型
typedef struct
{datatype data[MAX]; //存放顺序表的数组int len; //顺序表的长度
}SeqList, *SeqListPtr;
2.有关顺序表函数的操作
2.1创建顺序表
2.1.1函数功能概述
create_seq
函数的主要功能是在堆区动态分配内存来创建一个顺序表,并对其进行初始化,最后返回指向该顺序表的指针。
2.1.2实现步骤
- 内存分配:
- 使用
malloc
函数在堆区分配一块大小为sizeof(seq_list)
的内存空间,用于存储顺序表。 - 将分配的内存地址强制转换为
seq_p
类型,并赋值给指针S
。
- 使用
- 检查分配结果:
- 检查
S
是否为NULL
,如果为NULL
说明内存分配失败,输出错误信息并返回NULL
。
- 检查
- 初始化顺序表长度:
- 将顺序表的长度
S->len
初始化为 0,表示顺序表中当前没有元素。
- 将顺序表的长度
- 初始化数组元素:
- 使用
bzero
函数将顺序表中存储元素的数组S->data
全部置为 0,确保数组中的元素初始值为 0。
- 使用
- 返回指针:
- 返回指向新创建并初始化好的顺序表的指针
S
。
- 返回指向新创建并初始化好的顺序表的指针
//创建顺序表
seq_p create_seq()
{// 从堆区申请一个顺序表的空间// 使用 malloc 函数分配足够的内存空间,大小为 seq_list 结构体的大小// 将分配的内存地址强制转换为 seq_p 类型,并赋值给指针 Sseq_p S = (seq_p)malloc(sizeof(seq_list));// 检查内存分配是否成功if(S == NULL){// 若分配失败,输出错误信息并返回 NULLprintf("空间申请失败\n");return NULL;}// seq_list 类型结构体, len 表示为数组长度, 顺序表长度为 0// 初始化顺序表的长度为 0,表示当前顺序表中没有元素S->len = 0;// seq_list 类型结构体内的数组内的元素置零// 使用 bzero 函数将顺序表中存储元素的数组 data 全部置为 0// 第一个参数是要置零的内存块的起始地址,即 S->data// 第二个参数是要置零的内存块的大小,即 sizeof(S->data)bzero(S->data, sizeof(S->data));// 返回指向新创建并初始化好的顺序表的指针return S;
}
2.2判空
2.2.1函数功能概述
empty_seq
函数的主要功能是判断一个顺序表是否为空。顺序表是一种线性表的顺序存储结构,通常使用数组来实现。该函数通过检查顺序表的长度来确定其是否为空。
2.2.2函数参数
seq_p S
:指向顺序表的指针,seq_p
应该是自定义的指向顺序表结构体的指针类型。
2.2.3实现步骤
- 参数有效性检查:
- 首先检查传入的顺序表指针
S
是否为空。如果为空,说明传入的参数无效,输出错误信息并返回 -1。
- 首先检查传入的顺序表指针
- 判断顺序表是否为空:
- 使用三目运算符
S->len == 0? 1 : 0
来判断顺序表的长度是否为 0。 - 如果
S->len
等于 0,说明顺序表为空,函数返回 1。 - 如果
S->len
不等于 0,说明顺序表不为空,函数返回 0。
- 使用三目运算符
//判空
int empty_seq(seq_p S)
{// 入参合理性判断// 检查传入的顺序表指针是否为空if(S == NULL){// 若为空,输出错误信息并返回 -1printf("入参为空\n");return -1;}// 判断顺序表的长度是否为 0// 如果长度为 0,说明顺序表为空,返回 1// 如果长度不为 0,说明顺序表不为空,返回 0return S->len == 0? 1 : 0; // 空返回真,非空返回假也就是 0;
}
2.3判满
2.3.1函数功能概述
full_seq
函数用于判断顺序表是否已满。顺序表是一种线性表的顺序存储结构,通常使用数组来实现,有固定的最大容量。该函数通过比较顺序表当前元素个数和最大容量来确定顺序表是否已满。
2.3.2函数参数
seq_p S
:指向顺序表的指针,seq_p
应该是自定义的指向顺序表结构体的指针类型。
2.3.3实现步骤
- 参数有效性检查:
- 首先检查传入的顺序表指针
S
是否为空。若为空,表明传入的参数无效,输出错误信息并返回 -1。
- 首先检查传入的顺序表指针
- 判断顺序表是否已满:
- 使用三目运算符
S->len == MAX? 1 : 0
来比较顺序表当前元素个数S->len
和最大容量MAX
。 - 若
S->len
等于MAX
,意味着顺序表已满,函数返回 1。 - 若
S->len
不等于MAX
,表示顺序表未满,函数返回 0。
- 使用三目运算符
//判满
int full_seq(seq_p S)
{// 入参合理性检查// 检查传入的顺序表指针是否为空if(S == NULL){// 若为空,输出错误信息并返回 -1printf("入参为空\n");return -1;}// 判断顺序表是否已满// 通过比较顺序表当前元素个数 S->len 和最大容量 MAX// 如果两者相等,说明顺序表已满,返回 1// 如果不相等,说明顺序表未满,返回 0return S->len == MAX? 1 : 0; // 判断 data 实际元素个数的长度,是否等于 data 最大长度
}
2.4头插
头插的核心:元素循环后移,再头插
2.4.1函数功能概述
inser_head
函数的主要功能是在顺序表的头部插入一个新元素。顺序表是一种线性表的顺序存储结构,通常使用数组来实现。该函数会将顺序表中现有的元素依次向后移动一位,然后将新元素插入到顺序表的第一个位置。
2.4.2函数参数
seq_p S
:指向顺序表的指针,seq_p
应该是自定义的指向顺序表结构体的指针类型。datatype data
:要插入到顺序表头部的元素,datatype
是自定义的数据类型。
2.4.3实现步骤
- 参数有效性检查:
- 首先检查传入的顺序表指针
S
是否为空。如果为空,说明传入的参数无效,输出错误信息并返回。
- 首先检查传入的顺序表指针
- 判断顺序表是否已满:
- 调用
full_seq
函数判断顺序表是否已满。如果已满,输出提示信息并返回,因为无法再插入新元素。
- 调用
- 元素后移:
- 使用
for
循环从顺序表的最后一个元素开始,将每个元素依次向后移动一位,为新元素腾出第一个位置。
- 使用
- 插入新元素:
- 将新元素
data
插入到顺序表的第一个位置,即S->data[0]
。
- 将新元素
- 更新顺序表长度:
- 插入新元素后,将顺序表的长度
S->len
加 1,表示顺序表中元素的数量增加了一个。
- 插入新元素后,将顺序表的长度
//头插
//往哪插入的顺序表,例如seq_p类型 S是他的操作顺序表,datatype类型的datatype
//
void inser_head(seq_p S, datatype data)
{// 入参合理性检查// 检查传入的顺序表指针是否为空if(S == NULL){// 若为空,输出错误信息并返回printf("入参为空\n");return;}// 判满// 调用 full_seq 函数判断顺序表是否已满if(full_seq(S)){// 若已满,输出提示信息并返回printf("表已满,不能插入\n");return;}// 元素后移// 从顺序表的最后一个元素开始,将每个元素依次向后移动一位for(int i = S->len - 1; i >= 0; i--){// 将第 i 个元素移动到第 i + 1 个位置S->data[i + 1] = S->data[i];}// 第一位位置可以被覆盖// 将新元素插入到顺序表的第一个位置S->data[0] = data; // 第一个位置等于传过来的 data 就可以了// 顺序表长度自增// 插入新元素后,顺序表的长度加 1S->len++;
}
2.5输出顺序表
2.5.1函数功能概述
show
函数的主要功能是输出顺序表中的所有元素。顺序表是一种线性表的顺序存储结构,通常使用数组来实现。该函数会遍历顺序表中的每个元素并将其打印输出。
2.5.2函数参数
seq_p S
:指向顺序表的指针,seq_p
应该是自定义的指向顺序表结构体的指针类型。
2.5.3实现步骤
- 参数有效性检查:
- 首先检查传入的顺序表指针
S
是否为空。如果为空,说明传入的参数无效,输出错误信息并返回。
- 首先检查传入的顺序表指针
- 判断顺序表是否为空:
- 调用
empty_seq
函数判断顺序表是否为空。如果为空,输出提示信息并返回,因为空顺序表没有元素可输出。
- 调用
- 遍历并输出元素:
- 使用
for
循环遍历顺序表中的每个元素,从第一个元素(索引为 0)到最后一个元素(索引为S->len - 1
)。 - 在每次循环中,使用
printf
函数输出当前元素的值。
- 使用
// 输出顺序表
void show(seq_p S)
{// 入参合理性检查// 检查传入的顺序表指针是否为空if(S == NULL){// 若为空,输出错误信息并返回printf("入参为空\n");return; }// 判空// 调用 empty_seq 函数判断顺序表是否为空if(empty_seq(S)){// 若为空,输出提示信息并返回printf("入参为空\n");return;}// 遍历顺序表并输出元素for(int i = 0; i < S->len; i++){// 打印顺序表中的每个元素printf("输出顺序表%d\n", S->data[i]);}
}
2.6尾插
2.6.1函数功能概述
inser_tail
函数用于在顺序表的尾部插入一个新元素。顺序表是用连续的存储单元依次存储数据元素的线性结构,该函数会在顺序表的末尾添加新元素,并更新顺序表的长度。
2.6.2函数参数
seq_p S
:指向顺序表的指针,seq_p
应该是自定义的指向顺序表结构体的指针类型。datatype data
:要插入到顺序表尾部的元素,datatype
是自定义的数据类型。
2.6.3实现步骤
- 参数有效性检查:
- 检查传入的顺序表指针
S
是否为空。若为空,输出错误信息并终止函数执行。
- 检查传入的顺序表指针
- 判断顺序表是否已满:
- 调用
full_seq
函数判断顺序表是否已满。若已满,输出提示信息并终止函数执行。
- 调用
- 插入新元素:
- 若顺序表不为空且未满,将新元素
data
插入到S->data[S->len]
位置,即顺序表的尾部。
- 若顺序表不为空且未满,将新元素
- 更新顺序表长度:
- 插入新元素后,将顺序表的长度
S->len
加 1。
- 插入新元素后,将顺序表的长度
//尾插
void inser_tail(seq_p S, datatype data)
{// 入参合理性检查// 检查传入的顺序表指针是否为空if(S == NULL){// 若为空,输出错误信息并返回printf("入参为空\n");return; }// 判满// 调用 full_seq 函数判断顺序表是否已满if(full_seq(S)){// 若已满,输出提示信息并返回printf("表已满,不能插入\n");return;}// 在顺序表尾部插入新元素// S->len 表示当前顺序表的长度,也就是新元素要插入的位置S->data[S->len] = data;// 插入新元素后,顺序表长度加 1S->len++;
}
2.7头删
2.7.1函数功能概述
dele_head
函数的主要功能是删除顺序表的第一个元素。顺序表是一种线性表的顺序存储结构,通常使用数组来实现。该函数会将顺序表中除第一个元素外的其他元素依次向前移动一位,覆盖掉原来的第一个元素,从而实现删除操作。
2.7.2函数参数
seq_p S
:指向顺序表的指针,seq_p
应该是自定义的指向顺序表结构体的指针类型。
2.7.3实现步骤
- 参数有效性检查:
- 首先检查传入的顺序表指针
S
是否为空。如果为空,说明传入的参数无效,输出错误信息并返回。
- 首先检查传入的顺序表指针
- 判断顺序表是否为空:
- 调用
empty_seq
函数判断顺序表是否为空。如果为空,输出提示信息并返回,因为空顺序表没有元素可删除。
- 调用
- 元素前移:
- 使用
for
循环从顺序表的第二个元素(索引为 1)开始,将每个元素依次向前移动一位,覆盖掉原来的第一个元素。
- 使用
- 更新顺序表长度:
- 删除元素后,将顺序表的长度
S->len
减 1,表示顺序表中元素的数量减少了一个。
- 删除元素后,将顺序表的长度
//头删
void dele_head(seq_p S)
{// 入参合理性检查// 检查传入的顺序表指针是否为空if(S == NULL){// 若为空,输出错误信息并返回printf("入参为空\n");return;}// 判空// 调用 empty_seq 函数判断顺序表是否为空if(empty_seq(S)){// 若为空,输出提示信息并返回printf("表为空,无需删除\n");return;}// i:代表要移动的元素// 从顺序表的第二个元素开始,将每个元素依次向前移动一位for(int i = 1; i < S->len; i++){// i - 1 表示了 i 的前面的一个元素// 将第 i 个元素移动到第 i - 1 个位置S->data[i - 1] = S->data[i];}// 删除元素后,顺序表长度减 1S->len--;
}
2.8清空顺序表
2.8.1函数功能概述
clear_seq
函数的主要功能是清空顺序表。这里的清空操作并非真正释放顺序表占用的内存,而是将顺序表的长度置为 0,意味着顺序表中不再有有效元素。
2.8.2函数参数
seq_p S
:指向顺序表的指针,seq_p
应该是自定义的指向顺序表结构体的指针类型。
2.8.3实现步骤
- 参数有效性检查:
- 检查传入的顺序表指针
S
是否为空。若为空,输出错误信息并终止函数执行。
- 检查传入的顺序表指针
- 清空顺序表:
- 若指针有效,将顺序表的长度
S->len
置为 0。由于顺序表的有效元素是通过长度来界定的,长度为 0 就表示顺序表为空。
- 若指针有效,将顺序表的长度
//清空顺序表
void clear_seq(seq_p S)
{// 入参合理性检查// 检查传入的顺序表指针是否为空if(S == NULL){// 若为空,输出错误信息并返回printf("入参为空\n");return;}// 直接将长度置零// 把顺序表的长度 S->len 设为 0,这样顺序表就被视为没有有效元素了S->len = 0;
}
2.9按位置插入
2.9.1函数功能概述
insert_pos
函数用于在顺序表的指定位置插入一个新元素。顺序表是一种线性表的顺序存储结构,该函数会将指定位置及之后的元素依次向后移动一位,然后将新元素插入到指定位置。
2.9.2函数参数
seq_p S
:指向顺序表的指针,seq_p
应该是自定义的指向顺序表结构体的指针类型。datatype data
:要插入到顺序表中的元素,datatype
是自定义的数据类型。int pos
:要插入元素的位置,位置从 1 开始计数。
2.9.3实现步骤
//按位置插入
//需要三个参数,1.顺序表(S),数据(data),位置(pos)void insert_pos(seq_p S, datatype data, int pos)
{// 检查传入的顺序表指针是否为空if(S == NULL){// 如果为空,输出错误信息并返回printf("入参为空\n");return;}// 调用 full_seq 函数判断顺序表是否已满if(full_seq(S)){// 如果已满,输出错误信息并返回printf("表已满\n");return;}// 检查插入位置是否合理if(pos <= 0 || pos > S->len + 1){// 如果位置不合理(小于等于 0 或者大于当前长度加 1),输出错误信息并返回printf("位置不合理\n");return;}// 1. 从顺序表的最后一个元素开始,逐个向后移动元素,直到要插入的位置// 2. S->len - 1: 当前顺序表的最后一个元素的索引// 3. pos - 1: 要插入的位置的索引(从 0 开始)for(int i = S->len - 1; i >= pos - 1; i--){// 将第 i 个元素移动到第 i + 1 个位置// 通过循环将从 pos - 1 到 S->len - 1 的所有元素向后移动一位S->data[i + 1] = S->data[i];}// 循环结束后,插入位置已经空出// 将新元素插入到指定位置S->data[pos - 1] = data;// 顺序表的长度加 1S->len++;
}
2.10按位删除
2.10.1函数功能概述
dele_pos
函数的主要功能是从顺序表中删除指定位置的元素。顺序表是一种线性表的顺序存储结构,该函数会将指定位置之后的元素依次向前移动一位,覆盖掉要删除的元素,从而实现删除操作。
2.10.2函数参数
seq_p S
:指向顺序表的指针,seq_p
应该是自定义的指向顺序表结构体的指针类型。int pos
:要删除元素的位置,位置从 1 开始计数。
2.10.3实现步骤
- 参数有效性检查:
- 检查传入的顺序表指针
S
是否为空。如果为空,说明传入的参数无效,输出错误信息并返回。 - 调用
empty_seq
函数判断顺序表是否为空。如果为空,输出提示信息并返回,因为空顺序表没有元素可删除。 - 检查删除位置
pos
是否合理。如果pos
小于等于 0 或者大于顺序表的当前长度S->len
,说明位置不合理,输出错误信息并返回。
- 检查传入的顺序表指针
- 元素前移:
- 使用
for
循环从要删除元素的位置pos
开始,将该位置之后的元素依次向前移动一位,覆盖掉要删除的元素。
- 使用
- 更新顺序表长度:
- 删除元素后,将顺序表的长度
S->len
减 1,表示顺序表中元素的数量减少了一个。
- 删除元素后,将顺序表的长度
//按位删除
//简单理解:把len循环到要删除的下标后,把当前的数据赋值给当前前一位
void dele_pos(seq_p S, int pos)
{// 检查传入的顺序表指针是否为空if(S == NULL){// 若为空,输出错误信息并返回printf("入参为空\n");return;}// 调用 empty_seq 函数判断顺序表是否为空if(empty_seq(S)){// 若为空,输出提示信息并返回printf("表为空,无需删除\n");return;}// 位置合理性检查if(pos <= 0 || pos > S->len){// 若位置不合理(小于等于 0 或者大于当前顺序表长度),输出错误信息并返回printf("位置不合理\n");return;}// 循环前移for(int i = pos; i <= S->len - 1; i++){// 将第 i 个位置的元素前移到第 i - 1 个位置S->data[i - 1] = S->data[i];}// 顺序表长度减 1S->len--;
}
2.11顺序表去重
2.11.1函数功能概述
dele
函数的主要功能是对顺序表进行去重操作,即移除顺序表中重复的元素,只保留每个元素的一个副本。
2.11.2函数参数
seq_p S
:指向顺序表的指针,seq_p
应该是自定义的指向顺序表结构体的指针类型。
2.11.3实现步骤
- 参数有效性检查:
- 检查传入的顺序表指针
S
是否为空。若为空,输出错误信息并返回。 - 调用
empty_seq
函数判断顺序表是否为空。若为空,输出提示信息并返回。 - 检查顺序表的长度是否为 1。若为 1,说明顺序表中只有一个元素,无需去重,输出提示信息并返回。
- 检查传入的顺序表指针
- 去重操作:
- 使用外层
for
循环遍历顺序表中的每一个元素,索引为i
。 - 对于每个元素,使用内层
for
循环从i + 1
开始遍历剩余的元素,索引为j
。 - 比较
S->data[i]
和S->data[j]
是否相等。若相等,说明找到了重复元素。 - 调用
dele_pos
函数删除重复元素,注意传入的位置是j + 1
,因为位置从 1 开始计数。 - 删除元素后,由于后面的元素会前移,原来
j
位置的元素被新元素覆盖,需要将j
减 1,以便重新判断该位置的元素。
- 使用外层
//顺序表的去重
void dele(seq_p S)
{// 检查传入的顺序表指针是否为空if(S == NULL){// 若为空,输出错误信息并返回printf("入参为空\n");return;}// 调用 empty_seq 函数判断顺序表是否为空if(empty_seq(S)){// 若为空,输出提示信息并返回printf("表为空\n");return;}// 检查顺序表中是否只有一个元素if(S->len == 1){// 若只有一个元素,输出提示信息并返回printf("表中只有一个元素\n");return;}//找到重复元素,再去重// 先循环遍历顺序表表中的每一个元素for(int i = 0; i < S->len; i++){// 每拿到一个元素,和剩余的元素比较是否相同for(int j = i + 1; j < S->len; j++){// 判断元素是否相等if(S->data[i] == S->data[j]){// 拿到相同元素下标后,调用按位置删除函数dele_pos(S, j + 1);// 按位置删除后,原来已经判断过的位置,被新的元素覆盖了需要重新判断j--; }}}
}
2.12顺序表释放
2.12.1函数功能概述
free_seq
函数的主要功能是释放顺序表所占用的动态内存,并将指向顺序表的指针置为 NULL
,以避免悬空指针问题。该函数接收一个指向顺序表指针的指针(二级指针)作为参数,这样可以在函数内部修改原指针的值。
2.12.2函数参数
seq_p *S
:指向顺序表指针的指针(二级指针),seq_p
应该是自定义的指向顺序表结构体的指针类型。
2.12.3实现步骤
- 参数有效性检查:
- 检查传入的二级指针
S
是否为空,或者S
所指向的一级指针*S
是否为空。如果其中任何一个为空,说明入参无效,输出错误信息并返回,避免对空指针进行操作。
- 检查传入的二级指针
- 释放内存:
- 若参数有效,调用
free
函数释放*S
所指向的内存空间,即释放顺序表所占用的动态内存。
- 若参数有效,调用
- 避免悬空指针:
- 释放内存后,将
*S
置为NULL
,这样可以避免原指针成为悬空指针,提高程序的安全性。
- 释放内存后,将
//释放顺序表
//可以传一级指针,但是不能给主函数中的S置空
void free_seq(seq_p *S)
{// S==NULL 和 *S==NULL 不能交换位置,因为 S 是一个二级指针,要先判断二级指针不为空,再判断二级指针指向的内容不为空if(S == NULL || *S == NULL){// 若传入的二级指针 S 为空,或者 S 所指向的一级指针 *S 为空,说明入参无效// 输出错误信息并返回,避免对空指针进行操作printf("入参为空\n");return;}// 调用 free 函数释放 S 所指向的一级指针 *S 所指向的内存空间// 即释放顺序表所占用的动态内存free(*S);// 将 S 所指向的一级指针 *S 置为 NULL// 这样可以避免原指针成为悬空指针,提高程序的安全性*S = NULL;
}
3. 主函数
3.1代码功能概述
使用自定义顺序表库 seq_list.h
的测试程序,它展示了顺序表的各种操作,包括创建、判空、判满、插入(头插、尾插、按位置插入)、删除(头删、按位置删除)、去重、清空以及释放内存等操作,并在每次操作后打印相应的提示信息和顺序表的内容,方便观察操作结果。
3.2实现步骤
- 创建顺序表:调用
create_seq
函数创建一个顺序表,并将其指针赋值给S
。 - 初始状态检查:调用
empty_seq
和full_seq
函数分别判断顺序表是否为空和已满,并打印结果。然后调用show
函数打印顺序表的内容。 - 插入操作:
- 使用
inser_head
函数在顺序表头部插入多个元素。 - 使用
inser_tail
函数在顺序表尾部插入一个元素。 - 使用
insert_pos
函数在顺序表的指定位置插入一个元素。
- 使用
- 删除操作:
- 使用
dele_head
函数删除顺序表的第一个元素。 - 使用
dele_pos
函数删除顺序表的指定位置的元素。
- 使用
- 其他操作:
- 使用
clear_seq
函数清空顺序表。 - 使用
dele
函数对顺序表进行去重操作。
- 使用
- 释放内存:调用
free_seq
函数释放顺序表所占用的内存,并将指针置为NULL
,最后打印指针的值。
#include "seq_list.h"int main(int argc, const char *argv[])
{// 调用创建顺序表函数,创建一个顺序表并将其指针赋值给 Sseq_p S = create_seq(); // 调用 empty_seq 函数判断顺序表是否为空,并打印结果printf("判空%d\n", empty_seq(S));// 调用 full_seq 函数判断顺序表是否已满,并打印结果printf("判满%d\n", full_seq(S));// 调用 show 函数打印顺序表的内容show(S);// 多次调用 inser_head 函数在顺序表头部插入元素inser_head(S, 80);inser_head(S, 81);inser_head(S, 82);inser_head(S, 90);// 打印提示信息,表示接下来要打印现有顺序表的值printf("打印现有值---------\n");// 再次调用 show 函数打印顺序表的内容show(S);// 打印提示信息,表示接下来要进行尾插操作printf("打印尾插-------------\n");// 调用 inser_tail 函数在顺序表尾部插入元素 66inser_tail(S, 66); // 调用 show 函数打印顺序表的内容show(S);// 打印提示信息,表示接下来要进行头删操作printf("打印头删-------------\n");// 调用 dele_head 函数删除顺序表的第一个元素dele_head(S); // 调用 show 函数打印顺序表的内容show(S);// 打印提示信息,表示接下来要清空顺序表printf("清空顺序表------------\n");// 调用 clear_seq 函数清空顺序表clear_seq(S); // 调用 show 函数打印顺序表的内容show(S);// 再次调用 dele_head 函数尝试删除元素,此时顺序表可能为空dele_head(S); // 打印提示信息,表示接下来要进行按位置插入操作printf("按位置插入------------\n");// 调用 insert_pos 函数在顺序表的第 3 个位置插入元素 99insert_pos(S, 99, 3); // 调用 show 函数打印顺序表的内容show(S);// 打印提示信息,表示接下来要进行多次头插操作printf("头插几个数据------------\n");// 多次调用 inser_head 函数在顺序表头部插入元素inser_head(S, 99);inser_head(S, 98);inser_head(S, 20);inser_head(S, 99);// 调用 show 函数打印顺序表的内容show(S);// 打印提示信息,表示接下来要进行按位置删除操作printf("按位置删除3------------\n");// 调用 dele_pos 函数删除顺序表的第 3 个元素dele_pos(S, 3);// 调用 show 函数打印顺序表的内容show(S);// 打印提示信息,表示接下来要进行顺序表去重操作printf("顺序表去重------------\n");// 调用 dele 函数对顺序表进行去重操作dele(S);// 调用 show 函数打印顺序表的内容show(S);// 打印提示信息,表示接下来要释放顺序表的内存printf("释放内存------------\n");// 调用 free_seq 函数释放顺序表所占用的内存,并将指针置为 NULLfree_seq(&S);// 打印顺序表指针 S 的值,此时应为 NULLprintf("%p\n", S);return 0;
}
4. 全局函数声明
4.1代码功能概述
定义一个名为 seq_list.h
的头文件,它定义了顺序表的相关数据结构和操作函数的声明,用于实现顺序表的基本功能,如创建、插入、删除、判空、判满等操作。
4.2实现操作步骤
- 头文件保护:使用
#ifndef
、#define
和#endif
防止头文件被重复包含。 - 包含必要的头文件:包含了
stdio.h
、string.h
和stdlib.h
头文件,用于输入输出、字符串操作和内存管理。 - 定义常量和数据类型:
#define MAX 7
定义了顺序表的最大容量为 7。typedef int datatype
定义了顺序表中元素的数据类型为int
。
- 定义顺序表结构体:
typedef struct seq_list
定义了顺序表的结构体,包含一个存储元素的数组data
和一个记录长度的变量len
。 - 函数声明:声明了一系列用于操作顺序表的函数,包括创建、插入、删除、判空、判满等操作。
#ifndef __SEQ_LIST_H__
#define __SEQ_LIST_H__#include <stdio.h>
#include <string.h>
#include <stdlib.h>// 定义顺序表的最大容量为 7
#define MAX 7// 定义数据类型为 int
typedef int datatype;// 定义顺序表的结构体
typedef struct seq_list
{// 用于存储顺序表元素的数组datatype data[MAX];// 记录顺序表当前的长度int len;
} seq_list, *seq_p;// 创建顺序表
// 返回值:指向新创建顺序表的指针
seq_p create_seq();// 判空
// 参数 S:指向顺序表的指针
// 返回值:若顺序表为空返回 1,否则返回 0
int empty_seq(seq_p S);// 判满
// 参数 S:指向顺序表的指针
// 返回值:若顺序表已满返回 1,否则返回 0
int full_seq(seq_p S);// 头插
// 参数 S:指向顺序表的指针
// 参数 data:要插入的数据
void inser_head(seq_p S, datatype data);// 输出顺序表
// 参数 S:指向顺序表的指针
void show(seq_p S);// 尾插
// 参数 S:指向顺序表的指针
// 参数 data:要插入的数据
void inser_tail(seq_p S, datatype data);// 头删
// 参数 S:指向顺序表的指针
void dele_head(seq_p S);// 清空顺序表
// 参数 S:指向顺序表的指针
void clear_seq(seq_p S);// 按位置插入
// 参数 S:指向顺序表的指针
// 参数 data:要插入的数据
// 参数 pos:插入的位置
void insert_pos(seq_p S, datatype data, int pos);// 按位删除
// 参数 S:指向顺序表的指针
// 参数 pos:要删除元素的位置
void dele_pos(seq_p S, int pos);// 顺序表的去重
// 参数 S:指向顺序表的指针
void dele(seq_p S);// 释放顺序表
// 参数 S:指向顺序表指针的指针
// 说明:可以传一级指针,但不能给主函数中的 S 置空
void free_seq(seq_p *S);#endif
#ubuntu@GAOLANG:~/data/GQ1$
4.3 代码运行结果展现
相关文章:
《C语言动态顺序表:从内存管理到功能实现》
1.顺序表 1.1 概念 顺序存储的线性表,叫顺序表。 1.2顺序表存放的实现方式 可以使用数组存储数据,可以实现逻辑上相连,物理内存上也相连。也可以使用malloc在堆区申请一片连续的空间,存放数据,实现逻辑上相连&#…...
C++ 程序 return value 1 是什么原因
又是一次deepseek生成C 程序 return value 1 是什么原因 好的,用户问C程序返回值为1是什么原因。首先,我需要回想一下常见的导致程序返回非零值的情况。通常,返回1可能表示程序因为某种错误而终止。但具体原因可能有很多种,需要分…...
《DeepSeek 一站式工作生活 AI 助手》
最近国产AI工具DeepSeek在全球火出圈,登顶多个国家应用商店,下载量一路飙升。这匹AI “黑马” 到底凭什么征服全球用户?让我们全方位解锁DeepSeek——从基础入门到高阶玩法,从实用技巧到隐藏功能。 DeepSeek是一款功能强大的国产A…...
深入探索 DeepSeek 在数据分析与可视化中的应用
在数据驱动的时代,快速且准确地分析和呈现数据对于企业和个人都至关重要。DeepSeek 作为一款先进的人工智能工具,凭借其强大的数据处理和可视化能力,正在革新数据分析的方式。 1. 数据预处理与清洗 在进行数据分析前,数据预处理…...
【Python 学习 / 7】模块与文件操作
文章目录 前言一、导入模块1. 导入整个模块2. 导入模块中的特定函数3. 给模块或函数起别名 二、常用模块1. math 模块2. random 模块3. os 模块4. sys 模块 三、文件处理1. 打开文件2. 读取文件3. 写入文件4. 关闭文件5. 使用 with 语句管理文件 四、日期时间1. datetime 模块获…...
【DeepSeek】Mac m1电脑部署DeepSeek
一、电脑配置 个人电脑配置 二、安装ollama 简介:Ollama 是一个强大的开源框架,是一个为本地运行大型语言模型而设计的工具,它帮助用户快速在本地运行大模型,通过简单的安装指令,可以让用户执行一条命令就在本地运…...
计算机网络抄手 运输层
一、运输层协议概述 1. 进程之间的通信 从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。当网络边缘部分的两台主机使用网络核心部分的功能进行端到端的通信时&…...
激光雷达YDLIDAR X2 SDK安装
激光雷达YDLIDAR X2 SDK安装 陈拓 2024/12/15-2024/12/19 1. 简介 YDLIDAR X2官方网址https://ydlidar.cn/index.htmlYDLIDAR X2 YDLIDAR X2是一款高性能的激光雷达传感器,具有以下主要特点和规格参数: 测距频率:3000Hz 扫描频…...
DeepSeek-R1:使用KTransformers部署(保姆级教程)
1. 引言 KTransformers作为一个开源框架,专门为优化大规模语言模型的推理过程而设计。它支持GPU/CPU异构计算,并针对MoE架构的稀疏性进行了特别优化,可以有效降低硬件要求,允许用户在有限的资源下运行像DeepSeek-R1这样庞大的模型…...
什么是Spring Boot?
Spring Boot 是基于 Spring 框架的扩展工具,旨在简化 Spring 应用的初始搭建和开发流程。它通过约定优于配置和自动装配机制,减少了传统 Spring 开发中的繁琐配置,使开发者能快速构建独立运行、生产级别的应用。 Spring Boot 的核心特性 自动…...
C++ 学习路线:从入门到精通,全面掌握 C++ 编程
引言 C 是一种高性能的系统级编程语言,广泛应用于游戏开发、嵌入式系统、高性能计算等领域。尽管 C 的学习曲线较为陡峭,但掌握它将为你的职业发展带来巨大的优势。本文将为你提供一条清晰的 C 学习路线,帮助你从入门到精通,逐步…...
【算法精练】背包问题(01背包问题)
目录 1. 背包问题 2. 01背包问题 3. 优化 总结 1. 背包问题 经典的背包问题: 有一个背包,限制背包的体积;有一堆物品,从这堆物品中选择,在不超过背包容量的前提下,选出最大价值的物品; 从这个…...
宇树机器人G1 SDK实战和交付
最近客户有需求定制机宇树机器人G1 的功能,在接到需求后。进行了评估报价和开发。现在已经进入开发交付阶段 现在已经拿到了G1和H1版本的人型机器人。 需求是使用宇树机器G1 或H1在展馆进行路线移动,或指定移动路径,并且不能碰到小朋友&…...
使用EasyExcel和多线程实现高效数据导出
使用EasyExcel和多线程实现高效数据导出 1. 概述 在企业级应用中,数据导出是一个常见的需求。为了提高导出效率,尤其是在处理大量数据时,我们可以结合使用EasyExcel库和多线程技术。本文将详细介绍如何通过EasyExcel和多线程技术实现高…...
如何监控和优化 MySQL 中的慢 SQL
如何监控和优化 MySQL 中的慢 SQL 前言一、什么是慢 SQL?二、如何监控慢 SQL?1. 启用慢查询日志启用方法:日志内容: 2. 使用 mysqldumpslow 分析日志 三、如何分析慢 SQL?1. 使用 EXPLAIN 分析执行计划使用方法&#x…...
SPO(Self-Supervised Prompt Optimization)自我监督Prompt提示优化的全景指南
HuggingFace 链接:https://huggingface.co/spaces/XiangJinYu/SPO 作者也与国内的 ModelScope 魔搭社区官方进行了合作,现在可以体验由 Deepseek-V3 和 Qwen-2.5-72B 等开源模型驱动的 SPO。 ModelScope 链接: https://modelscope.cn/studios/AI-ModelScope/SPO 在大语言…...
【云安全】云原生-Docker(六)Docker API 未授权访问
Docker API 未授权访问 是一个非常严重的安全漏洞,可能导致严重的安全风险。 什么是 Docker API ? Docker API 是 Docker 容器平台提供的一组 RESTful API,用于与 Docker 守护程序进行通信和管理 Docker 容器。通过 Docker API,…...
9.PG数据库层权限管理(pg系列课程)第2遍
一、PostgreSQL数据库属主 Postgres中的数据库属主属于创建者,只要有createdb的权限就可以创建数据库,数据库属主不一定拥有存放在该数据库中其它用户创建的对象的访问权限。数据库在创建后,允许public角色连接,即允许任何人连接…...
Pytorch深度学习教程_3_初识pytorch
欢迎来到《PyTorch深度学习教程》系列的第三篇!在前面的两篇中,我们已经介绍了Python及numpy的基本使用。今天,我们将深入探索PyTorch的核心功能,帮助你更好地理解和使用这个强大的深度学习框架。 欢迎订阅专栏: 深度…...
个人博客5年回顾
https://huangtao01.github.io/ 五年前,看程序羊的b站视频做的blog,受限于网络,只能单向学习,没有人指导与监督,从来没有想过,有没有什么问题? 一、为什么要做个人博客? 二、我是怎么…...
DeepSeek与ChatGPT:会取代搜索引擎和人工客服的人工智能革命
云边有个稻草人-CSDN博客 在众多创新技术中,DeepSeek和ChatGPT无疑是最为引人注目的。它们通过强大的搜索和对话生成能力,能够改变我们与计算机交互的方式,帮助我们高效地获取信息,增强智能服务。本文将深入探讨这两项技术如何结合…...
SpringBoot高级-底层原理
目录 1 SpringBoot自动化配置原理 01-SpringBoot2高级-starter依赖管理机制 02-SpringBoot2高级-自动化配置初体验 03-SpringBoot2高级-底层原理-Configuration配置注解 04-SpringBoot2高级-底层原理-Import注解使用1 05-SpringBoot2高级-底层原理-Import注解使用2 06-S…...
百问网(100ask)的IMX6ULL开发板的以太网控制器(MAC)与物理层(PHY)芯片(LAN8720A)连接的原理图分析(包含各引脚说明以及工作原理)
前言 本博文承接博文 https://blog.csdn.net/wenhao_ir/article/details/145663029 。 本博文和博文 https://blog.csdn.net/wenhao_ir/article/details/145663029 的目录是找出百问网(100ask)的IMX6ULL开发板与NXP官方提供的公板MCIMX6ULL-EVK(imx6ull14x14evk)在以太网硬件…...
使用 PyTorch 实现标准卷积神经网络(CNN)
卷积神经网络(CNN)是深度学习中的重要组成部分,广泛应用于图像处理、语音识别、视频分析等任务。在这篇博客中,我们将使用 PyTorch 实现一个标准的卷积神经网络(CNN),并介绍各个部分的作用。 什…...
openGauss 3.0 数据库在线实训课程18:学习视图管理
前提 我正在参加21天养成好习惯| 第二届openGauss每日一练活动 课程详见:openGauss 3.0.0数据库在线实训课程 学习目标 掌握openGauss视图的管理:创建视图、删除视图、查询视图的信息、修改视图的信息。 课程作业 1.创建表,创建普通视图…...
nginx ngx_http_module(7) 指令详解
nginx ngx_http_module(7) 指令详解 nginx 模块目录 nginx 全指令目录 一、目录 1.1 模块简介 以下是您请求的Nginx HTTP相关模块的简述: ngx_http_proxy_protocol_vendor_module:这是一个商业订阅模块,允许从云平台的应用特定TLV&#…...
用DeepSeek零基础预测《哪吒之魔童闹海》票房——从数据爬取到模型实战
系列文章目录 1.元件基础 2.电路设计 3.PCB设计 4.元件焊接 5.板子调试 6.程序设计 7.算法学习 8.编写exe 9.检测标准 10.项目举例 11.职业规划 文章目录 **一、为什么要预测票房?****二、准备工作****三、实战步骤详解****Step 1:数据爬取与清洗&am…...
青少年编程都有哪些比赛可以参加
Python小学生可参加的赛事: 电子学会青少年编程考级、中国计算机学会编程能力等级认证、蓝桥杯、 信奥赛CSP-J/S初赛/NOIP(推荐C)、编程设计、信息素养、科技创新赛; 升学助力(科技特长生、大学)、企业、出国留学; python比赛&am…...
如何使用 Flutter DevTools 和 PerformanceOverlay 监控性能瓶颈
使用 Flutter DevTools 和 PerformanceOverlay 监控性能瓶颈:详细分析与实战 在开发 Flutter 应用时,性能问题可能会导致用户体验下降,比如页面卡顿、掉帧、内存泄漏等。为了定位和解决这些问题,Flutter 提供了强大的性能监控工具…...
拯救者电脑在重装系统之后电源计划丢失Fn+Q切换不了模式怎么恢复?
参考联想知识库的一下链接: https://iknow.lenovo.com.cn/detail/196192 其中下载的解压文件后的文件需要复制粘贴到D盘的根目录下,再来运行文件。若在生成的log文件中看到导入成功以及控制面板中看到已添加的电源计划即可 如果还是无效可是试试以下的…...
自动创建spring boot应用(eclipse版本)
使用spring starter project创建项目 设置Service URL 把Service URL设置为 https://start.aliyun.com/ 如下图: 使用这个网址,创建项目更快。 选择Spring Web依赖 项目结构 mvnw和mvnw.cmd:这是maven包装器(wrapper)脚本&…...
通过监督微调提升多语言大语言模型性能
引言 澳鹏助力一家全球科技公司提升其大语言模型(LLM)的性能。通过提供结构化的人工反馈形式的大语言模型训练数据,让该模型在30多种语言、70多种方言中的表现得到优化。众包人员们进行多轮对话,并依据回复的相关性、连贯性、准确…...
应急响应(linux 篇,以centos 7为例)
一、基础命令 1.查看已经登录的用户w 2.查看所有用户最近一次登录:lastlog 3.查看历史上登录的用户还有登录失败的用户 历史上所有登录成功的记录 last /var/log/wtmp 历史上所有登录失败的记录 Lastb /var/log/btmp 4.SSH登录日志 查看所有日志:…...
鹰角基于 Flink + Paimon + Trino 构建湖仓一体化平台实践项目
摘要:本文整理自鹰角大数据开发工程师,Apache Hudi Contributor 朱正军老师在 Flink Forward Asia 2024 生产实践(二)专场中的分享。主要分为以下四个部分: 一、鹰角数据平台架构 二、数据湖选型 三、湖仓一体建设 四、…...
探秘Transformer系列之(3)---数据处理
探秘Transformer系列之(3)—数据处理 接下来三篇偏重于工程,内容略少,大家可以当作甜点 _。 0x00 概要 有研究人员认为,大模型的认知框架看起来十分接近卡尔弗里斯顿(Karl Friston)描绘的贝叶斯大脑。基于贝叶斯概率…...
跨平台AES/DES加密解密算法【超全】
算法说明 要实现在 WinForm、Android、iOS、Vue3 中使用 相同的算法,确保各平台加密结果互通 一、统一加密参数 算法: AES-256-CBC 密钥: 32字节(示例中使用固定字符串生成) IV: 16字节 填充模式: PKCS7 字符编码: UTF-8 输出格式: Base64二、各平台实现代码...
XML DOM 高级
XML DOM 高级 引言 XML(可扩展标记语言)是一种用于存储和传输数据的标记语言,DOM(文档对象模型)是用于访问和操作XML文档的编程接口。在XML DOM中,我们可以对XML文档进行读取、修改、添加和删除等操作。本…...
MySQL智障离谱问题,删了库确还存在、也不能再创建同名库
1、问题 今天跟后端朋友接毕设单子的时候,后端穿过来的【weather.sql】这个文件没弄好,导致这个【weather】数据库的数据是错的,因此我用datagrip的GUI界面直接右键删除,结果就是tmd删不掉,ok,我只能在那新…...
网工项目实践2.6 广域网需求分析及方案制定
本专栏持续更新,整一个专栏为一个大型复杂网络工程项目。阅读本文章之前务必先看《本专栏必读》。 全网拓扑展示 一.广域网互联方式 1.专线 优点 稳定 独享。绝对安全。可靠性高,带宽高,完全取决于终端接口。 缺点: 费用高。建设时间长。难…...
11.编写前端内容|vscode链接Linux|html|css|js(C++)
vscode链接服务器 安装VScode插件 Chinese (Simplified) (简体中⽂) Language Pack for Visual Studio CodeOpen in BrowserRemote SSH 在命令行输入 remote-ssh接着输入 打开配置文件,已经配置好主机 点击远程资源管理器可以找到 右键链接 输入密码 …...
GITHUB的若干操作
GITHUB的若干操作 github又名代码仓库,是git的远程和线上延申,Git是一个分布式版本控制系统,用于跟踪文件的更改和协助多人合作开发。它由Linus Torvalds为更好地管理Linux内核开发而设计。git最原始是为Linux系统设计而生,不过后…...
网页制作04-html,css,javascript初认识のhtml如何使用列表
Html列表共有三种类型: 1.一种是无序列表,项目符号有几个符号组成; 2.一种是有序列表,项目符号由字母或数字进行排序; 3.一种是定义列表,它用作产生条件和描述的双重列表,可以对列表进行灵活定义 一、有序列表 1.有序列表ol 1)一般格式: <ol>…...
Linux:进程间通信(一.初识进程间通信、匿名管道与命名管道、共享内存)
目录 1.认识进程间通信 2.管道 2.1匿名管道 2.2pipe()函数 —创建匿名管道 2.3匿名管道的四种情况 2.4管道的特征 3.基于管道的进程池设计 4.命名管道 4.1引入与性质 4.2命令行创建 4.3程序中创建命名管道 写个小项目 项目规划 PipeClient.cpp PipeServe.cpp 5.…...
深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作
一、问题背景(传统爬虫的痛点) 数据采集是现代网络爬虫技术的核心任务之一。然而,传统爬虫面临多重挑战,主要包括: 反爬机制:许多网站通过检测请求头、IP地址、Cookie等信息识别爬虫,进而限制…...
Spring Boot中使用Flyway进行数据库迁移
文章目录 概要Spring Boot 集成 FlywayFlyway 其他用法bug错误Flyway版本不兼容数据库存在表了Flyway 的校验和(Checksum)不匹配 概要 在 Spring Boot 项目开发中,数据库的变更不可避免。手动执行 SQL 脚本不仅容易出错,也难以维…...
Conda 常用命令全解析
在 Windows 系统中,Conda 是一款功能强大的包管理和环境管理工具,尤其对于数据分析、科学计算等场景有着重要的作用。本文将详细介绍 Conda 在 Windows 系统中的常用命令,帮助你高效地管理虚拟环境和软件包。 一、环境管理命令 1.1 查看 Co…...
【Vue教程】使用Vite快速搭建前端工程化项目 Vue3 Vite Node.js
??大家好!我是毛毛张! ??个人首页: ??今天毛毛张分享的是关于如何快速??♂搭建一个前端工程化的项目的环境搭建以及流程?? 文章目录 1.前端工程化环境搭建?? 1.1 什么是前端工程化1.2 nodejs的简介和安装 1.2.1 什么是Nodejs1.2.2 如何安装…...
基于51单片机的定时器实现LED闪烁控制(CT107D)
引言 在嵌入式开发中,定时器是一个非常重要的外设,它可以用于实现精确的时间控制。本文将介绍如何在CT107D单片机综合训练平台上,利用51单片机的定时器T0实现LED灯的定时闪烁控制。具体功能如下: L1指示灯:每隔1秒闪烁…...
一键部署开源DeepSeek并集成到钉钉
一键部署开源DeepSeek并集成到钉钉 简介: DeepSeek发布了两款先进AI模型V3和R1,分别适用于对话AI、内容生成及推理任务。由于官方API流量限制,阿里云推出了私有化部署方案,无需编写代码即可完成部署,并通过计算巢AppF…...
Web后端 Tomcat服务器
一 Tomcat Web 服务器 介绍: Tomcat是一个开源的Java Servlet容器和Web服务器,由Apache软件基金会开发。它实现了Java Servlet和JavaServer Pages (JSP) 技术,用于运行Java Web应用程序。Tomcat轻量、易于配置,常作为开发和部署…...