《C语言动态顺序表:从内存管理到功能实现》

news2025/4/8 13:39:38

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 类型,并赋值给指针 S
    seq_p S = (seq_p)malloc(sizeof(seq_list));
    // 检查内存分配是否成功
    if(S == NULL)
    {
        // 若分配失败,输出错误信息并返回 NULL
        printf("空间申请失败\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)
    {
        // 若为空,输出错误信息并返回 -1
        printf("入参为空\n");
        return -1;
    }
    // 判断顺序表的长度是否为 0
    // 如果长度为 0,说明顺序表为空,返回 1
    // 如果长度不为 0,说明顺序表不为空,返回 0
    return 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)
    {
        // 若为空,输出错误信息并返回 -1
        printf("入参为空\n");
        return -1;
    }
    // 判断顺序表是否已满
    // 通过比较顺序表当前元素个数 S->len 和最大容量 MAX
    // 如果两者相等,说明顺序表已满,返回 1
    // 如果不相等,说明顺序表未满,返回 0
    return 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 就可以了
    // 顺序表长度自增
    // 插入新元素后,顺序表的长度加 1
    S->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;
    // 插入新元素后,顺序表长度加 1
    S->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];
    }
    // 删除元素后,顺序表长度减 1
    S->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;
    // 顺序表的长度加 1
    S->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];
    }
    // 顺序表长度减 1
    S->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[])
{
    // 调用创建顺序表函数,创建一个顺序表并将其指针赋值给 S
    seq_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 函数在顺序表尾部插入元素 66
    inser_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 个位置插入元素 99
    insert_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 函数释放顺序表所占用的内存,并将指针置为 NULL
    free_seq(&S);
    // 打印顺序表指针 S 的值,此时应为 NULL
    printf("%p\n", S);

    return 0;
}

4. 全局函数声明

4.1代码功能概述

        定义一个名为 seq_list.h 的头文件,它定义了顺序表的相关数据结构和操作函数的声明,用于实现顺序表的基本功能,如创建、插入、删除、判空、判满等操作。

4.2实现操作步骤

  • 头文件保护:使用 #ifndef#define 和 #endif 防止头文件被重复包含。
  • 包含必要的头文件:包含了 stdio.hstring.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 代码运行结果展现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2301409.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通过API 调用本地部署 deepseek-r1 模型

如何本地部署 deepseek 请参考&#xff08;windows 部署安装 大模型 DeepSeek-R1&#xff09; 那么实际使用中需要开启API模式&#xff0c;这样可以无拘无束地通过API集成的方式&#xff0c;集成到各种第三方系统和应用当中。 上遍文章是基于Ollama框架运行了deepSeek R1模型…

DeepSeek-学习与实践

1.应用场景 主要用于学习与使用DeepSeek解决问题, 提高效率. 2.学习/操作 1.文档阅读 文档 DeepSeek -- 官网, 直接使用 --- 代理网站 --- 极客智坊 https://poe.com/DeepSeek-R1 https://time.geekbang.com/search?qdeepseek -- 搜索deepseek的资料 资料 20250209DeepSeekC…

撕碎QT面具(6):调节窗口大小后,控件被挤得重叠的解决方法

问题&#xff1a;控件重叠 分析原因&#xff1a;因为设置了最小大小&#xff0c;所以界面中的大小不会随窗口的变化而自动变化。 处理方案&#xff1a;修改mimumSize的宽度与高度为0&#xff0c;并设置sizePolicy为Expanding&#xff0c;让其自动伸缩。 结果展示&#xff08;自…

解锁机器学习核心算法 | K-平均:揭开K-平均算法的神秘面纱

一、引言 机器学习算法种类繁多&#xff0c;它们各自有着独特的优势和应用场景。前面我们学习了线性回归算法、逻辑回归算法、决策树算法。而今天&#xff0c;我们要深入探讨的是其中一种经典且广泛应用的聚类算法 —— K - 平均算法&#xff08;K-Means Algorithm&#xff09…

【Linux】匿名管道的应用场景-----管道进程池

目录 一、池化技术 二、简易进程池的实现&#xff1a; Makefile task.h task.cpp Initchannel函数&#xff1a; 创建任务&#xff1a; 控制子进程&#xff1a; 子进程执行任务&#xff1a; 清理收尾&#xff1a; 三、全部代码&#xff1a; 前言&#xff1a; 对于管…

PostgreSQL的学习心得和知识总结(一百六十九)|深入理解PostgreSQL数据库之 Group By 键值消除 的使用和实现

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

Python基于循环神经网络的情感分类系统(附源码,文档说明)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

Zookeeper应用案例-分布式锁-实现思路

以下是具体实现代码 第一步&#xff1a;注册锁节点 第二步&#xff1a;获取锁节点&#xff0c;如果自己是最小的节点&#xff0c;就获取权限 第三步&#xff1a;拿到锁就开始自己的业务逻辑 第四步&#xff1a;业务逻辑好了就要释放这把锁 第五步&#xff1a;重新注册监听&…

java练习(32)

ps&#xff1a;题目来自力扣 环形链表 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表…

伯克利 CS61A 课堂笔记 10 —— Trees

本系列为加州伯克利大学著名 Python 基础课程 CS61A 的课堂笔记整理&#xff0c;全英文内容&#xff0c;文末附词汇解释。 目录 01 Trees 树 Ⅰ Tree Abstraction Ⅱ Implementing the Tree Abstraction 02 Tree Processing 建树过程 Ⅰ Fibonacci tree Ⅱ Tree Process…

让编程变成一种享受-明基RD320U显示器

引言 作为一名有着多年JAVA开发经验的从业者&#xff0c;在工作过程中&#xff0c;显示器的重要性不言而喻。它不仅是我们与代码交互的窗口&#xff0c;更是影响工作效率和体验的关键因素。在多年的编程生涯中&#xff0c;我遇到过各种各样的问题。比如&#xff0c;在进行代码…

10分钟上手DeepSeek开发:SpringBoot + Vue2快速构建AI对话系统

作者&#xff1a;后端小肥肠 目录 1. 前言 为什么选择DeepSeek&#xff1f; 本文技术栈 2. 环境准备 2.1. 后端项目初始化 2.2. 前端项目初始化 3. 后端服务开发 3.1. 配置文件 3.2. 核心服务实现 4. 前端服务开发 4.1. 聊天组件ChatWindow.vue开发 5. 效果展示及源…

Linux环境开发工具

Linux软件包管理器yum Linux下安装软件方式&#xff1a; 源代码安装rpm安装——Linux安装包yum安装——解决安装源、安装版本、安装依赖的问题 yum对应于Windows系统下的应用商店 使用Linux系统的人&#xff1a;大部分是职业程序员 客户端怎么知道去哪里下载软件&#xff1…

JupyterNotebook高级使用:常用魔法命令

%%writefile test.py def Test(name):print("Test",name,"success")运行结果&#xff1a;就是在我们的文件目录下面创建了这个test.py文件&#xff0c;主要是认识一下这个里面的%%writefile表示创建新的文件&#xff0c;这个文件里面的内容就是上面我们定义…

C++ Primer 类的作用域

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

50页PDF|数字化转型成熟度模型与评估(附下载)

一、前言 这份报告依据GBT 43439-2023标准&#xff0c;详细介绍了数字化转型的成熟度模型和评估方法。报告将成熟度分为五个等级&#xff0c;从一级的基础转型意识&#xff0c;到五级的基于数据的生态价值构建与创新&#xff0c;涵盖了组织、技术、数据、资源、数字化运营等多…

机器学习实战(8):降维技术——主成分分析(PCA)

第8集&#xff1a;降维技术——主成分分析&#xff08;PCA&#xff09; 在机器学习中&#xff0c;降维&#xff08;Dimensionality Reduction&#xff09; 是一种重要的数据处理技术&#xff0c;用于减少特征维度、去除噪声并提高模型效率。主成分分析&#xff08;Principal C…

前端插件使用xlsx-populate,花样配置excel内容,根据坐添加标替换excel内容,修改颜色,合并单元格...。

需求要求&#xff1a;业务人员有个非常复杂得excel表格&#xff0c;各种表头等&#xff0c;但是模板是固定得。当然也可以实现在excel上搞出各种表格&#xff0c;但是不如直接用已有模板替换其中要动态得内容方便&#xff0c;这里我们用到CSDN得 xlsx-populate 插件。 实列中我…

分布式大语言模型服务引擎vLLM论文解读

论文地址&#xff1a;Efficient Memory Management for Large Language Model Serving with PagedAttention 摘要 大语言模型&#xff08;LLMs&#xff09;的高吞吐量服务需要一次对足够多的请求进行批处理。然而&#xff0c;现有系统面临困境&#xff0c;因为每个请求的键值…

如何开发一个大模型应用?

1. 背景 AIGC技术的突破性进展彻底改变了技术开发的范式&#xff0c;尤其是以GPT为代表的LLM&#xff0c;凭借其强大的自然语言理解与生成能力&#xff0c;迅速成为全球科技领域的焦点。2023年末&#xff0c;随着ChatGPT的爆火&#xff0c;AIGC技术从实验室走向规模化应用&…