当前位置: 首页 > news >正文

顺 序 表:数 据 存 储 的 “ 有 序 阵 地 ”

顺 序 表:数 据 存 储 的 “ 有 序 阵 地 ”

  • 线 性 表
  • 顺 序 表 - - - 顺 序 存 储 结 构
  • 顺 序 表 的 操 作 实 现
    • 代 码 全 貌 与 功 能 介 绍
    • 顺 序 表 的 功 能 说 明
    • 代 码 效 果 展 示
    • 代 码 详 解
      • SeqList.h
      • SeqList.c
      • test.c
  • 总 结

💻作 者 简 介:曾 与 你 一 样 迷 茫,现 以 经 验 助 你 入 门 数据 结 构。
💡个 人 主 页:@笑口常开xpr 的 个 人 主 页
📚系 列 专 栏:硬 核 数 据 结 构 与 算 法
✨代 码 趣 语:数 据 结 构 + 算 法 = 程 序 设 计。
💪代 码 千 行,始 于 坚 持,每 日 敲 码,进 阶 编 程 之 路。
📦gitee 链 接:gitee

在这里插入图片描述

         在 数 据 结 构 的 世 界 里,每 一 种 设 计 都 可 能 孕 育 出 惊 人 的 效 率 变 革。你 是 否 深 思 过,一 组 精 心 组 织 的 数 据 究 竟 能 创 造 怎 样 的 奇 迹?每 一 次 挖 掘 底 层 原 理,都 是 与 计 算 机 智 慧 的 巅 峰 对 话;每 一 次 剖 析 存 储 模 式,都 在 破 解 数 据 世 界 的 终 极 密 码。准 备 好 迎 接 这 场 盛 宴 了 吗?让 我 们 一 同 探 寻 数 据 结 构 的 顺 序 表 的 无 尽 奥 秘,见 证 它 如 何 重 塑 数 字 时 代 的 运 行 法 则!

线 性 表

定 义

         线 性 表 是 由 相 同 数 据 类 型 的 ​n(​n ≥ 0)个 数 据 元 素 的 有 限 序 列。若 将 线 性 表 记 为

在这里插入图片描述

相 关 概 念

表 长:其 中 n 为 表 长,当 n = 0 时,称 为 空 表;

表 头:当 n > 0 时,在 这 个 序 列 中,a1 是 第 一 个 元 素,被 称 为 表 头 元 素

表 尾:an 是 最 后 一 个 元 素,被 称 为 表 尾 元 素。

直 接 前 驱:a(i-1) 领 先 于 ai,称 a(i-1) 是 ai 的 直 接 前 驱 元 素。

直 接 后 继:ai 领 先 于 a(i+1),a(i+1) 是 ai 的 直 接 后 继 元 素。

当 i 为 1,2,…,n-1 时,ai 有 且 仅 有 一 个 直 接 后 继 元 素。

当 i 为 2,3,…,n 时,ai 有 且 仅 有 一 个 直 接 前 驱 元 素。

顺 序 表 - - - 顺 序 存 储 结 构

定 义

         顺 序 表 把 线 性 表 中 的 元 素 按 照 逻 辑 顺 序 依 次 存 储 在 一 组 地 址 连 续 的 存 储 单 元 中,通 过 数 组 来 实 现。这 种 存 储 方 式 让 元 素 的 逻 辑 顺 序 和 物 理 顺 序 保 持 一 致,利 用 元 素 的 下 标 可 以 快 速 访 问 到 任 何 一 个 元 素。

在这里插入图片描述

顺 序 表 示 和 实 现

         假 设 顺 序 表 的 每 个 元 素 占 用 l 个 存 储 单 元,并 以 所 占 的 第 一 个 单 元 的 存 储 地 址 作 为 数 据 元 素 的 存 储 位 置。

         线 性 表 中 第 i + 1 个 数 据 元 素 的 存 储 位 置 LOC(ai+1) 和 第 i 个 数 据 元 素 的 存 储 位 置 LOC(ai) 之 间 满 足 下 列 关 系:

在这里插入图片描述

线 性 表 的 第 i 个 数 据 元 素 ai 的 存 储 位 置 为:

在这里插入图片描述

         式 中 LOC(a1) 是 线 性 表 中 第 一 个 数 据 元 素 a1 的 存 储 位 置,通 常 称 作 线 性 表 的 起 始 地 址 或 基 地 址。

         每 一 个 数 据 元 素 的 存 储 位 置 都 和 顺 序 表 的 起 始 位 置 相 差 一 个 和 数 据 元 素 在 线 性 表 中 的 第 n 个 元 素 成 正 比 的 常 数。由 此,只 要 确 定 了 存 储 线 性 表 的 起 始 位 置,线 性 表 中 任 一 数 据 元 素 都 可 随 机 存 取,所 以 线 性 表 的 顺 序 存 储 结 构 是 一 种 随 机 存 取 的 存 储 结 构。

顺 序 表 的 操 作 实 现

         顺 序 表 有 静 态 顺 序 表 和 动 态 顺 序 表 两 种,这 里 以 动 态 顺 序 表 为 例 进 行 介 绍。

代 码 全 貌 与 功 能 介 绍


         整 个 顺 序表 由 三 个 主 要 文 件 构 成:SeqList.h、SeqList.c 和 test.c。这 种 多 文 件 的 架 构 设 计,有 助 于 将 不 同 功 能 模 块 分 离,提 高 代 码 的 可 读 性、可 维 护 性 与 可 扩 展 性。

SeqList.h

         SeqList.h 包 含 了 顺 序 表 所 需 的 头 文 件 引 用、常 量 定 义 以 及 函 数 声 明。

test.c

         test.c 是 顺 序 表 的 主 逻 辑 文 件,负 责 处 理 用 户 输 入 和 代 码 流 程 的 控 制。

SeqList.c

SeqList.c 则 实 现 了 顺 序 表 的 具 体 功 能 函 数。

下 面 展 示完 整 代 码

读 者 可 以 将 这 段 代 码 复 制 到 自 己 的 编 译 器 中 运 行。

SeqList.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define INIT_CAPACITY 4         //初始化的容量
typedef int SLDataType;
//动态顺序表 --- 按需申请
typedef struct SeqList
{SLDataType* a;int size;            //有效数据个数int capacity;        //空间容量
}SL;//增删查改//初始化
void SLInit(SL* ps);//释放空间
void SLDestory(SL* ps);//输出
void SLPrint(SL* ps);//扩容
void SLCheckCapacity(SL* ps);//尾插
void SLPushBack(SL* ps, SLDataType x);//尾删
void SLPopBack(SL* ps);//头插
void SLPushFront(SL* ps, SLDataType x);//头删
void SLPopFront(SL* ps);//某个数的后面插入
void SLBackInsert(SL* ps, int pos, SLDataType x);//某个数的前面插入
void SLFrontInsert(SL* ps, int pos, SLDataType x);//某个位置删除
void SLErase(SL* ps, int pos);//查找
int SLFind(SL* ps, SLDataType x);//函数指针数组
void SeqListValue(int(*pf)(SL* ps, SLDataType x), SL* ps);void SeqListInsert(int(*pf)(SL* ps, SLDataType x), SL* ps, int num);//保存数据到文件中
void SaveSeqList(SL* ps);//加载数据到文件中
void LoadSeqList(SL* ps);

test.c

#define _CRT_SECURE_NO_WARNINGS 0 #include "SeqList.h"
void menu()
{printf("*************************************************\n");printf("*****  1. SLPushBack     2. SLPopBack       *****\n");printf("*****  3. SLPushFront    4. SLPopFront      *****\n");printf("*****  5. SLBackInsert   6. SLFrontInsert   *****\n");printf("*****  7. SLErase        8. SLFind          *****\n");printf("*****  9. SLPrint        0. exit            *****\n");printf("*************************************************\n");
}
void test()
{SL s;SLInit(&s);int input = 0;do{menu();printf("请输入你想要的操作:>\n");scanf("%d", &input);switch (input){case 0:SaveSeqList(&s);SLDestory(&s);break;case 1:SeqListValue(SLPushBack, &s);break;case 2:SLPopBack(&s);SLPrint(&s);break;case 3:SeqListValue(SLPushFront, &s);break;case 4:SLPopFront(&s);SLPrint(&s);break;case 5:SeqListInsert(SLBackInsert, &s, 5);break;case 6:SeqListInsert(SLFrontInsert, &s, 6);break;case 7:SeqListInsert(SLErase, &s, 7);break;case 8:SeqListInsert(SLFind, &s, 8);break;case 9:SLPrint(&s);break;default:printf("输入错误,请重新输入\n");break;}} while (input);
}
int main()
{test();return 0;
}

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 0 
#include "SeqList.h"
void SLInit(SL* ps)
{assert(ps);ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);if (ps->a == NULL){perror("malloc fail");return;}ps->size = 0;ps->capacity = INIT_CAPACITY;LoadSeqList(ps);
}void SLDestory(SL* ps)
{assert(ps);//空间是野指针//数组指向的空间越界free(ps->a);ps->a = NULL;ps->capacity = 0;ps->size = 0;printf("销毁成功\n");
}void SLPrint(SL* ps)
{assert(ps);int i = 0;for (i = 0;i < ps->size;i++){printf("%d ", ps->a[i]);}printf("\n");
}void SLCheckCapacity(SL* ps)
{//扩容SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));if (tmp == NULL){perror("realloc fail");return;}ps->a = tmp;//不写这句代码的话是原地扩容,在原来的地址上增加ps->capacity *= 2;
}void SLPushBack(SL* ps, SLDataType x)
{printf("尾插\n");//方法1//assert(ps);//if (ps->size == ps->capacity)//{//	SLCheckCapacity(ps);//}//ps->a[ps->size++] = x;ps->a[ps->size] = x;ps->size++;//方法2SLBackInsert(ps, ps->size, x);
}//不释放空间,要释放空间只能一块一块释放
void SLPopBack(SL* ps)
{assert(ps);printf("尾删\n");//方法1//assert(ps->size > 0);//方法2if (ps->size == 0){return;}//ps->a[ps->size - 1] = 0;ps->size--;//方法2//SLErase(ps, ps->size);
}
void SLPushFront(SL* ps, SLDataType x)
{printf("头插\n");//方法1//assert(ps);//if (ps->size == ps->capacity)//{//	SLCheckCapacity(ps);//}//int end = ps->size - 1;//while (end >= 0)//{//	ps->a[end + 1] = ps->a[end];//	end--;//}//ps->a[0] = x;//ps->size++;//方法2SLBackInsert(ps, 0, x);
}void SLPopFront(SL* ps)
{printf("头删\n");//方法1//assert(ps);//assert(ps->size > 0);//int begin = 1;//while (begin < ps->size)//{//	ps->a[begin - 1] = ps->a[begin];//	begin++;//}//ps->size--;//方法2SLErase(ps, 0);
}void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos <= ps->size);int erase = pos - 1;while (erase <= ps->size - 1){ps->a[erase] = ps->a[erase + 1];erase++;}ps->size--;printf("消除成功\n");
}
int SLFind(SL* ps, SLDataType x)
{assert(ps);printf("查找\n");int i = 0;int flag = 0;for (i = 0; i < ps->size; i++){if (ps->a[i] == x){return i;}}return -1;
}void SeqListValue(int(*pf)(SL* ps, SLDataType x), SL* ps)
{int x = 0;printf("请输入1个操作数:>\n");scanf("%d", &x);pf(ps, x);SLPrint(ps);
}void SLFrontInsert(SL* ps, int pos, SLDataType x)
{assert(ps);if (ps->capacity == ps->size){SLCheckCapacity(ps);}int tmp = ps->size - 1;while (tmp >= pos - 1){ps->a[tmp + 1] = ps->a[tmp];tmp--;}ps->a[pos - 1] = x;ps->size++;
}
void SLBackInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);if (ps->capacity == ps->size){SLCheckCapacity(ps);}int tmp = ps->size - 1;while (tmp >= pos){ps->a[tmp + 1] = ps->a[tmp];tmp--;}ps->a[pos] = x;ps->size++;
}
void SeqListInsert(int(*pf)(SL* ps, SLDataType x), SL* ps, int num)
{int x = 0;int y = 0;if (num == 5){printf("请输入你要插入数的位置:>\n");scanf("%d", &x);printf("请输入你要插入的数字:>\n");scanf("%d", &y);SLBackInsert(ps, x, y);SLPrint(ps);}else if (num == 6){printf("请输入你要插入的数字:>\n");scanf("%d", &x);printf("请输入你要插入的数字的位置:>\n");scanf("%d", &y);SLFrontInsert(ps, y, x);SLPrint(ps);}else if (num == 7){printf("请输入你要擦除数的位置:>\n");scanf("%d", &x);pf(ps, x);SLPrint(ps);}else{printf("请输入你要查找的数字:>\n");scanf("%d", &x);int ret = pf(ps, x);if (ret != -1){printf("下标是:%d\n", ret);}else{printf("查找的数字不存在\n");}}
}void SaveSeqList(SL* ps)
{FILE* pf = fopen("SeqList.txt", "wb");if (pf == NULL){perror("SaveSeqList");return;}else{int i = 0;for (i = 0; i < ps->size; i++){fwrite(ps->a + i, sizeof(SLDataType), 1, pf);}fclose(pf);pf = NULL;printf("保存文件成功\n");}
}
void LoadSeqList(SL* ps)
{//打开文件FILE* pf = fopen("SeqList.txt", "rb");if (NULL == pf){perror("LoadSeqList");return;}else{//读数据SLDataType tmp = 0;int i = 0;while (fread(&tmp, sizeof(SLDataType), 1, pf)){if (ps->size == ps->capacity){SLCheckCapacity(ps);}ps->a[i] = tmp;ps->size++;i++;}fclose(pf);pf = NULL;}
}

顺 序 表 的 功 能 说 明

数 据 结 构 定 义:顺 序 表 是 用 物 理 地 址 连 续 的 存 储 单 元 依 次 存 储 数 据 元 素 的 线 性 结 构,逻 辑 顺 序 与 物 理 顺 序 一 致,基 于 数 组 实 现。使 用 动 态 数 组 存 储,通 过 malloc/realloc 动 态 管 理 内 存,支 持 扩 容,灵 活 性 高。

初 始 化:SLInit 函 数 为 动 态 数 组 分 配 初 始 内 存 ,大 小 是 4 * 4 = 16 个 字 节。初 始 化 大 小 是 0,容 量 为 4。

销 毁: SLDestory 函 数 释 放 动 态 数 组 内 存,避 免 内 存 泄 漏。重 置 大 小 和 容 量 都 是 0,标 记 顺 序 表 为 空。

扩 容:插 入 元 素 前 若 空 间 不 足(大 小 和 容 量 相 等 时),先 扩 容 再 操 作。SLCheckCapacity 函 数 自 动 扩 展 容 量(容 量 翻 倍),使 用 realloc 重 新 分 配 内 存,迁 移 数 据。这 里 因 为 容 量 翻 倍 会 进 行 异 地 扩 容。

数 据 插 入

操作类型函数时间复杂度功能说明
头插SLPushFrontO(N)移动全部元素
尾插SLPushBackO(1)直接插入
一个数的前面插入SLFrontInsertO(N)将 pos 及之后的元素后移一位
一个数的后面插入SLBackInsertO(N)将 pos-1 及之后的元素后移一位

数 据 删 除

操作类型函数时间复杂度功能说明
头删SLPopFrontO(N)移动全部元素
尾删SLPopBackO(1)直接调整 size,无需移动
指定位置删除SLEraseO(N)将pos+1及之后的元素前移一位

数 据 查 找:SLFind 函 数 顺 序 遍 历 数 组,查 找 元 素 x 的 首 次 出 现 位 置,返 回 下 标( 未 找 到 返 回 -1)。时 间 复 杂度:O(N)(平 均 情 况)。

数 据 持 久 化:SaveSeqList 函 数 用 于 将 顺 序 表 中 的 信 息 以 二 进 制 形 式 保 存 到 文 件 中,LoadSeqList 函 数 用 于 从 文 件 中 加 载 顺 序 表,实 现 数 据 的 持 久 化 存 储。

错 误 处 理:在 内 存 分 配 和 文 件 操 作 中 使 用 了 perror 等 方 式 进 行 错 误 处 理,当 操 作 失 败 时 输 出 相 应 的 错 误 信 息。


代 码 效 果 展 示

菜 单 展 示

         每 次 循 环 开 始 时 会 显 示 菜 单,内 容 包 括:
SLPushBack:尾 插
SLPopBack:尾 删
SLPushFront:头 插
SLPopFront:头 删
SLBackInsert:从 一 个 数 的 后 面 插 入
SLFrontInsert:从 一 个 数 的 前 面 插 入
SLErase:擦 除 某 个 指 定 的 数
SLFind:查 找 某 个 数
SLPrint:输 出 顺 序 表
exit:退 出 程 序 并 将 顺 序 表 保 存 到 文 件 中

在这里插入图片描述

尾 插(SLPushBack)

         输 入 1 后,程 序 会 提 示 用 户 输 入 插 入 的 数 字。输 入 完 成 后,数 字 被 添 加 到 顺 序 表 的 末 尾。如 果 顺 序 表 已 满,会 自 动 增 加 容 量。

在这里插入图片描述

尾 删(SLPopBack)

         输 入 2 后,顺 序 表 的 末 尾 的 一 个 数 字 会 被 删 除 并 输 出 删 除 后 的 顺 序 表。

在这里插入图片描述

头 插(SLPushFront)

         输 入 3 后,程 序 会 提 示 用 户 输 入 插 入 的 数 字。输 入 完 成 后,如 果 顺 序 表 已 满,会 自 动 增 加 容 量,然 后 数 字 被 添 加 到 顺 序 表 的 第 一 个 位 置。

在这里插入图片描述

头 删(SLPopFront)

         输 入 4 后,顺 序 表 的 第 一 个 位 置 的 数 字 会 被 删 除 并 输 出 删 除 后 的 顺 序 表。

在这里插入图片描述

从 某 一 个 数 字 的 后 面 插 入(SLBackInsert)

         输 入 5 后,程 序 会 提 示 用 户 输 入 插 入 的 数 字 和 要 插 入 数 字 的 位 置。输 入 完 成 后,数 字 被 添 加 到 顺 序 表 的 要 输 入 数 字 的 后 面。如 果 顺 序 表 已 满,会 自 动 增 加 容 量。

在这里插入图片描述

从 某 一 个 数 字 的 前 面 插 入(SLFrontInsert)

         输 入 6 后,程 序 会 提 示 用 户 输 入 插 入 的 数 字 和 要 插 入 数 字 的 位 置。输 入 完 成 后,数 字 被 添 加 到 顺 序 表 的 要 输 入 数 字 的 前 面。如 果 顺 序 表 已 满,会 自 动 增 加 容 量。

在这里插入图片描述

清 除 指 定 数 的 位 置(SLErase)

         输 入 7 后,程 序 会 提 示 用 户 输 入 清 除 数 字 的 位 置。输 入 完 成 后,输 入 位 置 上 的 数 字 会 被 清 除。

在这里插入图片描述

查 找 数 字(SLFind)

         输 入 8 后,程 序 会 提 示 用 户 要 查 找 的 数 字。输 入 完 成 后,程 序 会 查 找 数 字,如 果 找 到 会 输 出 数 字 的 下 标,如 果 没 有 找 到,则 输 出 “查 找 的 数 字 不 存 在”。

在这里插入图片描述

输 出 顺 序 表(SLPrint)

         输 入 9 后,程 序 会 在 屏 幕 上 显 示 目 前 的 顺 序 表。

在这里插入图片描述

退 出 顺 序 表(exit)

         输 入 0 后,程 序 会 将 顺 序 表 中 的 信 息 以 二 进 制 形 式 保 存 到 文 件 “SeqList.txt” 中。释 放 内 存 并 销 毁 顺 序 表, 然 后 退 出 程 序。

在这里插入图片描述


代 码 详 解

SeqList.h

#pragma once

         #pragma once 是 一 个 预 处 理 指 令,用 于 防 止 头 文 件 被 重 复 包 含。在 大 型 项 目 中,多 个 源 文 件 可 能 会 包 含 同 一 个 头 文 件,使 用 #pragma once 可 以 确 保 头 文 件 的 内 容 只 被 编 译 一 次,避 免 重 复 定 义 的 错 误。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

         #include 指 令 用 于 引 入 必 要 的 标 准 库 头 文 件:

stdio.h:提 供 标 准 输 入 输 出 函 数,如 printf、scanf 等。
assert.h:提 供 assert 宏,用 于 在 运 行 时 检 查 程 序 的 断 言 条 件。
stdlib.h:提 供 内 存 管 理 函 数(如 malloc、realloc、free)和 其 他 标 准 库 函 数。

#define INIT_CAPACITY 4         //初始化的容量
typedef int SLDataType;

         #define 指 令 用 于 定 义 一 些 常 量:

INIT_CAPACITY:定 义 顺 序 表 的 初 始 容 量 为 4。
typedef int SLDataType:将 int 重 新 定 义 成 SLDataType

typedef struct SeqList
{SLDataType* a;int size;            //有效数据个数int capacity;        //空间容量
}SL;

         定 义 了 一 个 名 为 SeqList 的 结 构 体 并 重 新 命 名 为 SL,用 于 表 示 整 个 顺 序 表:

a:指 向 结 构 体 的 指 针,用 于 动 态 分 配 内 存 来 存 储 顺 序 表 信 息。
size:整 数,记 录 当 前 顺 序 表 中 已 存 储 的 数 字 个 数。
capacity:整 数,记 录 当 前 顺 序 表 的 最 大 容 量。

//增删查改//初始化
void SLInit(SL* ps);//释放空间
void SLDestory(SL* ps);//输出
void SLPrint(SL* ps);//扩容
void SLCheckCapacity(SL* ps);//尾插
void SLPushBack(SL* ps, SLDataType x);//尾删
void SLPopBack(SL* ps);//头插
void SLPushFront(SL* ps, SLDataType x);//头删
void SLPopFront(SL* ps);//某个数的后面插入
void SLBackInsert(SL* ps, int pos, SLDataType x);//某个数的前面插入
void SLFrontInsert(SL* ps, int pos, SLDataType x);//某个位置删除
void SLErase(SL* ps, int pos);//查找
int SLFind(SL* ps, SLDataType x);//函数指针
void SeqListValue(int(*pf)(SL* ps, SLDataType x), SL* ps);void SeqListInsert(int(*pf)(SL* ps, SLDataType x), SL* ps, int num);//保存数据到文件中
void SaveSeqList(SL* ps);//加载数据到文件中
void LoadSeqList(SL* ps);

         函 数 声 明,定 义 了 对 顺 序 表 进 行 操 作 的 各 个 功 能 函 数:

SLInit:用 于 初 始 化 顺 序 表,分 配 内 存 并 设 置 初 始 状 态。
SLDestory:用 于 销 毁 顺 序 表,释 放 分 配 的 内 存。
SLPrint:用 于 显 示 顺 序 表 中 所 有 的 数 字。
SLCheckCapacity:检 查 通 讯 录 的 容 量,必 要 时 进 行 扩 容。
SLPushBack:用 于 对 顺 序 表 末 尾 添 加 数 字。
SLPopBack:用 于 对 顺 序 表 末 尾 删 除 数 字。
SLPushFront:用 于 对 顺 序 表 第 一 个 位 置 添 加 数 字。
SLPopFront:用 于 对 顺 序 表 第 一 个 位 置 删 除 数 字。
SLBackInsert:用 于 对 顺 序 表 的 指 定 位 置 的 后 面 插 入 数 字。
SLFrontInsert:用 于 对 顺 序 表 的 指 定 位 置 的 前 面 插 入 数 字。
SLErase:用 于 从 顺 序 表 中 删 除 指 定 的 数 字。
SLFind:根 据 输 入 的 数 字 查 找 顺 序 表 中 的 数 字,返 回 数 字 在 顺 序 表 中 的 下 标,找 不 到 返 回 特 定 值。
SeqListValue:函 数 指 针,传 递 函 数 地 址,用 于 程 序 中 相 同 的 部 分,节 省 代 码 量。
SeqListInsert:函 数 指 针,传 递 函 数 地 址,用 于 程 序 中 相 同 的 部 分,节 省 代 码 量。
SaveSeqList:将 顺 序 表 中 的 信 息 保 存 到 文 件 中。
LoadSeqList:从 文 件 中 加 载 信 息 到 顺 序 表 中。

SeqList.c

内 存 管 理 机 制

void SLInit(SL* ps)
{assert(ps);ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);if (ps->a == NULL){perror("malloc fail");return;}ps->size = 0;ps->capacity = INIT_CAPACITY;LoadSeqList(ps);
}
//扩容
void SLCheckCapacity(SL* ps)
{//扩容SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));if (tmp == NULL){perror("realloc fail");return;}ps->a = tmp;//不写这句代码的话是原地扩容,在原来的地址上增加ps->capacity *= 2;
}

初 始 化:使 用 calloc 分 配 初 始 空 间 并 将 所 有 数 据 初 始 化。
动 态 扩 容:每 次 容 量 不 足 时 增 加 原 来 空 间 数 的 2 倍。
内 存 安 全:通 过 realloc 确 保 数 据 连 续 性,失 败 时 输 出 错 误 信 息。

顺 序 表 核 心 操 作

尾 删

void SLPopBack(SL* ps)
{assert(ps);printf("尾删\n");//方法1//assert(ps->size > 0);//方法2if (ps->size == 0){return;}//ps->a[ps->size - 1] = 0;ps->size--;//方法2//SLErase(ps, ps->size);
}

         总 共 有 两 种 方 法 这 里 以 方 法 1 为 例,方 法 2 中 尾 删 是 任 意 位 置 删 除 的 特 例(pos = size)。使 用 方 法 1 时 间 复 杂 度 为 O(1),而 使 用 方 法 2 删 除 最 后 一 个 元 素 时,SLErase 仍 需 执 行 while 循 环(尽 管 循 环 体 不 执 行),效 率 略 低 于 方法 1。

删 除 处 理:直 接 减 小 有 效 长 度 即 可,将 数 字 置 为 0 没 有 意 义。

尾 插

void SLPushBack(SL* ps, SLDataType x)
{printf("尾插\n");//方法1assert(ps);if (ps->size == ps->capacity){SLCheckCapacity(ps);}ps->a[ps->size++] = x;//ps->a[ps->size] = x;//ps->size++;//方法2//SLBackInsert(ps, ps->size, x);
}

         总 共 有 两 种 方 法 这 里 以 方 法 1 为 例,方 法 2 中 尾 插 是 任 意 位 置 插 入 的 特 例(pos = size)。方 法 1 和 方 法 2 的 差 别 和 尾 删 类 似,这 里 不 再 描 述。

自 动 扩 容:添 加 前 检 查 容 量,不 足 时 自 动 扩 展。

输 入 处 理:直 接 插 入 数 字 即 可。

头 删

void SLPopFront(SL* ps)
{printf("头删\n");//方法1assert(ps);assert(ps->size > 0);int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;//方法2//SLErase(ps, 0);
}

插 入 处 理:将 所 有 位 置 的 数 字 前 移 一 位,大 小 减 1 即 可。

头 插

void SLPushFront(SL* ps, SLDataType x)
{printf("头插\n");//方法1assert(ps);if (ps->size == ps->capacity){SLCheckCapacity(ps);}int end = ps->size - 1;while (end >= 0){ps->a[end + 1] = ps->a[end];end--;}ps->a[0] = x;ps->size++;//方法2//SLBackInsert(ps, 0, x);
}

         总 共 有 两 种 方 法 这 里 以 方 法 1 为 例,方 法 2 中 头 插 是 任 意 位 置 插 入 的 特 例。

自 动 扩 容:添 加 前 检 查 容 量,不 足 时 自 动 扩 展。

输 入 处 理:将 所 有 位 置 的 数 字 后 移 一 位,直 接 插 入 数 字 即 可。

指 定 数 字 的 后(前) 面 插 入

void SLBackInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);if (ps->capacity == ps->size){SLCheckCapacity(ps);}int tmp = ps->size - 1;while (tmp >= pos){ps->a[tmp + 1] = ps->a[tmp];tmp--;}ps->a[pos] = x;ps->size++;
}
void SLFrontInsert(SL* ps, int pos, SLDataType x)
{assert(ps);if (ps->capacity == ps->size){SLCheckCapacity(ps);}int tmp = ps->size - 1;while (tmp >= pos - 1){ps->a[tmp + 1] = ps->a[tmp];tmp--;}ps->a[pos - 1] = x;ps->size++;
}

自 动 扩 容:添 加 前 检 查 容 量,不 足 时 自 动 扩 展。

输 入 处 理:将 指 定 位 置(前 面 插 入 包 括 指 定 位 置,后 面 插 入 不 包 括 指 定 位 置) 的 数 字 后 移 一 位,直 接 插 入 数 字 即 可。

删 除 指 定 位 置 的 数字

void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos <= ps->size);int erase = pos - 1;while (erase <= ps->size - 1){ps->a[erase] = ps->a[erase + 1];erase++;}ps->size--;printf("消除成功\n");
}

数 据 迁 移:删 除 后 将 后 续 元 素 前 移 覆 盖。

查 找 数 字

int SLFind(SL* ps, SLDataType x)
{assert(ps);printf("查找\n");int i = 0;int flag = 0;for (i = 0; i < ps->size; i++){if (ps->a[i] == x){return i;}}return -1;
}

函 数 功 能:在 顺 序 表 中 查 找 指 定 的 数 字,返 回 其 索 引(未 找 到 返 回 - 1)。

数 据 持 久 化

void SaveSeqList(SL* ps)
{FILE* pf = fopen("SeqList.txt", "wb");if (pf == NULL){perror("SaveSeqList");return;}else{int i = 0;for (i = 0; i < ps->size; i++){fwrite(ps->a + i, sizeof(SLDataType), 1, pf);}fclose(pf);pf = NULL;printf("保存文件成功\n");}
}
void LoadSeqList(SL* ps)
{//打开文件FILE* pf = fopen("SeqList.txt", "rb");if (NULL == pf){perror("LoadSeqList");return;}else{//读数据SLDataType tmp = 0;int i = 0;while (fread(&tmp, sizeof(SLDataType), 1, pf)){if (ps->size == ps->capacity){SLCheckCapacity(ps);}ps->a[i] = tmp;ps->size++;i++;}fclose(pf);pf = NULL;}
}

二 进 制 存 储:使 用 fwrite 和 fread 进 行 整 块 数 据 读 写。

自 动 加 载:初 始 化 时 自 动 从 文 件 恢 复 数 据。

容 量 管 理:加 载 时 动 态 扩 展 内 存 确 保 足 够 空 间。

test.c

菜 单 界 面

void menu()
{printf("*************************************************\n");printf("*****  1. SLPushBack     2. SLPopBack       *****\n");printf("*****  3. SLPushFront    4. SLPopFront      *****\n");printf("*****  5. SLBackInsert   6. SLFrontInsert   *****\n");printf("*****  7. SLErase        8. SLFind          *****\n");printf("*****  9. SLPrint        0. exit            *****\n");printf("*************************************************\n");
}

使 用 星 号 (*) 绘 制 边 框,提 供 清 晰 的 视 觉 界 面。
数 字 编 号 对 应 不 同 功 能,方 便 用 户 选 择。

主 循 环 逻 辑

void test()
{SL s;SLInit(&s);int input = 0;do{menu();printf("请输入你想要的操作:>\n");scanf("%d", &input);switch (input){case 0:SaveSeqList(&s);SLDestory(&s);break;case 1:SeqListValue(SLPushBack, &s);break;case 2:SLPopBack(&s);SLPrint(&s);break;case 3:SeqListValue(SLPushFront, &s);break;case 4:SLPopFront(&s);SLPrint(&s);break;case 5:SeqListInsert(SLBackInsert, &s, 5);break;case 6:SeqListInsert(SLFrontInsert, &s, 6);break;case 7:SeqListInsert(SLErase, &s, 7);break;case 8:SeqListInsert(SLFind, &s, 8);break;case 9:SLPrint(&s);break;default:printf("输入错误,请重新输入\n");break;}} while (input);
}

初 始 化:调 用 SLInit 分 配 内 存 并 加 载 文 件 数 据。
循 环 控 制:使 用 do-while 确 保 至 少 执 行 一 次 菜 单 选 择。
选 项 处 理:通 过 switch 分 支 调 用 不 同 功 能 函 数。
安 全 退 出:退 出 前 保 存 数 据 并 释 放 内 存,防 止 资 源 泄 漏。

程 序 入 口

int main()
{test();return 0;
}

         main 函 数 是 程 序 的 入 口 点,调 用 test 函 数 启 动 顺 序 表,最 后 返 回 0 表 示 程 序 正 常 结 束。

在这里插入图片描述

总 结

         至 此,关 于 数 据 结 构 顺 序 表 探 索 暂 告 一 段 落,但 你 的 编 程 征 程 才 刚 刚 启 航。编 写 代 码 是 与 计 算 机 逻 辑 深 度 对 话,过 程 中 虽 会 在 结 构 设 计、算 法 实 现 的 困 境 里 挣 扎,但 这 些 磨 砺 加 深 了 对 代 码 逻 辑 和 数 据 组 织 的 理 解。愿 你 合 上 电 脑 后,灵 感 不 断,在 数 据 结 构 的 世 界 里 持 续 深 耕,书 写 属 于 自 己 的 编 程 传 奇,下 一 次 开 启,定 有 全 新 的 精 彩 等 待。小 编 期 待 重 逢,盼 下 次 阅 读 时 见 证 你 们 更 大 的 进 步,共 赴 代 码 之 约!

相关文章:

  • 计算机网络概要
  • 牛客网NC276055:三根木棒能否组成三角形问题详解(ACM中的A题)
  • 【从基础到模型网络】深度学习-语义分割-ROI
  • OceanBase数据库-租户
  • 小米汽车:新能源赛道的破局者与变革者
  • UE5无法编译问题解决
  • 抖音视频下载工具 v1.1 自用分享
  • 【Python 算法零基础 4.排序 ① 选择排序】
  • 为何选择Python:全面解析其优势与发展前景
  • Linux下载国外软件镜像的加速方法(以下载Python-3.8.0.tgz为例)
  • Java可变参数与Collections工具类详解
  • 系统架构设计师考前冲刺笔记-第1章-系统工程与信息系统基础
  • 深入解析Java事件监听机制与应用
  • GOP模式调节画面质量讲解
  • 【ROS2】 核心概念6——通信接口语法(Interfaces)
  • 【QGIS二次开发】地图编辑-07
  • LWIP的NETCONN接口
  • 生产级编排AI工作流套件:Flyte全面使用指南 — Data input/output
  • 【常用算法:查找篇】9.AVL树深度解析:动态平衡二叉树的原理、实现与应用
  • USB传输速率 和 RS-232/RS-485串口协议速率 的倍数关系
  • 吴双评《发展法学》|穷国致富的钥匙:制度,还是产业活动?
  • 中国旅游日|上天当个“显眼包”!低空经济的“飞”凡魅力
  • 高途一季度净利润同比增长1108%: “与吴彦祖一起学英语”短时间内就实现了盈利
  • 上海国际碳中和博览会下月举办,首次打造民营经济专区
  • 阿联酋与美国达成超过2000亿美元协议
  • 乌克兰谈判代表团由12人组成,乌防长率领