順 序 表:數 據 存 儲 的 “ 有 序 陣 地 ”

順 序 表:數 據 存 儲 的 “ 有 序 陣 地 ”

  • 線 性 表
  • 順 序 表 - - - 順 序 存 儲 結 構
  • 順 序 表 的 操 作 實 現
    • 代 碼 全 貌 與 功 能 介 紹
    • 順 序 表 的 功 能 說 明
    • 代 碼 效 果 展 示
    • 代 碼 詳 解
      • 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 表 示 程 序 正 常 結 束。

在這里插入圖片描述

總 結

?????????至 此,關 于 數 據 結 構 順 序 表 探 索 暫 告 一 段 落,但 你 的 編 程 征 程 才 剛 剛 啟 航。編 寫 代 碼 是 與 計 算 機 邏 輯 深 度 對 話,過 程 中 雖 會 在 結 構 設 計、算 法 實 現 的 困 境 里 掙 扎,但 這 些 磨 礪 加 深 了 對 代 碼 邏 輯 和 數 據 組 織 的 理 解。愿 你 合 上 電 腦 后,靈 感 不 斷,在 數 據 結 構 的 世 界 里 持 續 深 耕,書 寫 屬 于 自 己 的 編 程 傳 奇,下 一 次 開 啟,定 有 全 新 的 精 彩 等 待。小 編 期 待 重 逢,盼 下 次 閱 讀 時 見 證 你 們 更 大 的 進 步,共 赴 代 碼 之 約!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80400.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80400.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80400.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡安全深度解析:21種常見網站漏洞及防御指南

一、高危漏洞TOP 10 1. SQL注入(SQLi) 原理:通過構造惡意SQL語句突破系統過濾機制 典型場景: - 聯合查詢注入: union select 1,version(),3--+ - 布爾盲注:and (select substr(user(),1,1)=r) - 時間盲注:;if(now()=sysdate(),sleep(5),0)/ 防御方案: - 嚴格參數化查…

代碼上傳gitte倉庫

把代碼push上去就行

創建型:單例模式

目錄 1、核心思想 2、實現方式 2.1 餓漢式 2.2 懶漢式 2.3 枚舉&#xff08;Enum&#xff09; 3、關鍵注意事項 3.1 線程安全 3.2 反射攻擊 3.3 序列化與反序列化 3.4 克隆保護 4、適用場景 1、核心思想 目的&#xff1a;確保一個類僅有一個實例 功能&#xff1a;…

副業小程序YUERGS,從開發到變現

文章目錄 我為什么寫這個小程序網站轉小程序有什么坑有什么推廣渠道個人開發者如何變現簡單介紹YUERGS小程序給獨立開發者一點小建議 我為什么寫這個小程序 關注我的粉絲應該知道&#xff0c;我在碩士階段就已經掌握了小程序開發技能&#xff0c;并寫了一個名為“約球online”…

React路由(React學習筆記_09)

React路由 1,路由基礎 現代的前端應用大多都是SPA(單頁應用程序)&#xff0c;也就是只有一個HTML頁面的應用程序。因為它的用戶體驗更好、對服務器的壓力更小&#xff0c;所以更受歡迎。為了有效的使用單個頁面來管理原來多個頁面的功能&#xff0c;前端路由應運而生。 1, 安裝…

2009-2025計算機408統考真題及解析

整理2009-2025 年計算機408統考真題及解析PDF 目錄樹&#xff1a; └── 2025考研計算機408統考真題及答案&#xff08;回憶版&#xff09;.pdf ├── 2009-2024計算機408真題解析 │ ├── 2009年計算機408統考真題解析.pdf │ ├── 2010年計算機408統考真題解析.pdf …

Mysql、Oracle、Sql Server、達夢之間sql的差異

1&#xff1a;分頁查詢 Sql Server&#xff1a; <bind name"startRow" value"(page - 1) * limit 1"/> <bind name"endRow" value"page * limit"/> SELECT *FROM (SELECT ROW_NUMBER() OVER (<if test"sortZd!…

SQL Server 常用函數

一、字符串處理函數 1. CONCAT&#xff1a;拼接字符串 語法&#xff1a;CONCAT(string1, string2, ..., stringN) 實例&#xff1a; SELECT CONCAT(Hello, , World) AS Result; 輸出&#xff1a; Result ------------- Hello World 2. SUBSTRING&#xff1a;截取子字符串 …

【通用大模型】Serper API 詳解:搜索引擎數據獲取的核心工具

Serper API 詳解&#xff1a;搜索引擎數據獲取的核心工具 一、Serper API 的定義與核心功能二、技術架構與核心優勢2.1 技術實現原理2.2 對比傳統方案的突破性優勢 三、典型應用場景與代碼示例3.1 SEO 監控系統3.2 競品廣告分析 四、使用成本與配額策略五、開發者注意事項六、替…

ABP vNext 多租戶系統實現登錄頁自定義 Logo 的最佳實踐

&#x1f680; ABP vNext 多租戶系統實現登錄頁自定義 Logo 的最佳實踐 &#x1f9ed; 版本信息與運行環境 ABP Framework&#xff1a;v8.1.5.NET SDK&#xff1a;8.0數據庫&#xff1a;PostgreSQL&#xff08;支持 SQLServer、MySQL 等&#xff09;BLOB 存儲&#xff1a;本地…

FastDFS分布式文件系統架構學習(一)

FastDFS分布式文件系統架構學習 1. FastDFS簡介 FastDFS是一個開源的輕量級分布式文件系統&#xff0c;由淘寶資深架構師余慶設計并開發。它專為互聯網應用量身定制&#xff0c;特別適合以中小文件&#xff08;如圖片、文檔、音視頻等&#xff09;為載體的在線服務。FastDFS不…

基于單片機的防盜報警器設計與實現

標題:基于51單片機的防盜報警器設計 內容:1.摘要 本文圍繞基于51單片機的防盜報警器設計展開。背景在于現代社會安全需求不斷提高&#xff0c;傳統防盜方式存在諸多不足。目的是設計一款成本低、可靠性高且易于使用的防盜報警器。方法上&#xff0c;以51單片機為核心控制單元&…

IDE/IoT/搭建物聯網(LiteOS)集成開發環境,基于 LiteOS Studio + GCC + JLink

文章目錄 概述LiteOS Studio不推薦&#xff1f;安裝和使用手冊呢?HCIP實驗的源碼呢&#xff1f; 軟件和依賴安裝軟件下載軟件安裝插件安裝依賴工具-方案2依賴工具-方案1 工程配置打開或新建工程板卡配置組件配置編譯器配置-gcc工具鏈編譯器配置-Makefile腳本其他配置編譯完成 …

【高斯擬合最終篇】Levenberg-Marquardt(LM)算法

Levenberg-Marquardt(LM)算法是一種結合高斯-牛頓法和梯度下降法的優化方法,特別適合非線性最小二乘問題,如高斯函數擬合。它通過引入阻尼因子(damping factor)平衡高斯-牛頓法的快速收斂和梯度下降法的穩定性。以下是基于之前的 gaussian_fit.py,加入 LM 算法實現高斯擬…

信道編碼技術介紹

信息與通信系統中的編碼有4 種形式&#xff1a;信源編碼、信道編碼、密碼編碼和多址編碼。 其中信道編碼的作用是對信源經過壓縮后的數據加一定數量受到控制的冗余&#xff0c;使得數據在傳輸中或接收中發生的差錯可以被糾正或被發現&#xff0c;從而可以正確恢復出原始數據信息…

線性回歸策略

一種基于ATR(平均真實范圍)、線性回歸和布林帶的交易策略。以下是對該策略的全面總結和分析: 交易邏輯思路 1. 過濾條件: - 集合競價過濾:在每個交易日的開盤階段,過濾掉集合競價產生的異常數據。 - 價格異常過濾:排除當天開盤價與最高價或最低價相同的情況,這…

WordPress Relevanssi插件時間型SQL注入漏洞(CVE-2025-4396)

免責聲明 本文檔所述漏洞詳情及復現方法僅限用于合法授權的安全研究和學術教育用途。任何個人或組織不得利用本文內容從事未經許可的滲透測試、網絡攻擊或其他違法行為。使用者應確保其行為符合相關法律法規,并取得目標系統的明確授權。 對于因不當使用本文信息而造成的任何直…

支持selenium的chrome driver更新到136.0.7103.94

最近chrome釋放新版本&#xff1a;136.0.7103.94 如果運行selenium自動化測試出現以下問題&#xff0c;是需要升級chromedriver才可以解決的。 selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only su…

附加:TCP如何保障數據傳輸

附加&#xff1a;TCP如何保障數據傳輸 LS-NET-012-TCP的交互過程詳解 TCP 如何保障數據傳輸 TCP&#xff08;Transmission Control Protocol&#xff0c;傳輸控制協議&#xff09;是互聯網核心協議之一&#xff0c;負責在IP網絡上提供可靠的、面向連接的數據傳輸服務。它位于T…

Unity 批量將圖片從默認類型改為Sprite類型

先將該腳本放到Editor目錄下 如何使用:選中目錄,然后點擊Tool里面的批量修改按鈕 using System; using UnityEngine; using UnityEditor; using System.IO; using System.Linq;/// <summary> /// 此工具可以批量將圖片類型修改為精靈 /// </summary> public clas…