數據結構中的寶藏秘籍之廣義表

廣義表,也被稱作列表(Lists),是一種遞歸的數據結構。它就像一個神秘的盒子,既可以裝著單個元素(原子),也可以嵌套著其他的盒子(子列表)。比如廣義表?(a (b c) d),其中?a?和?d?是原子,而?(b c)?則是一個子列表。這種嵌套結構使得廣義表能夠輕松表示各種復雜的關系,就像一位萬能的畫家,能描繪出樹形結構、圖結構等多樣的 “畫作”。

與普通的線性表相比,廣義表的元素類型更加豐富多樣,不僅可以是相同類型的元素,還能包含不同類型的元素,甚至可以嵌套其他的廣義表。這種靈活性讓廣義表在處理復雜數據時游刃有余,成為了數據結構中的 “多面手”。

先上代碼:

#include <stdio.h>
#include <stdlib.h>// 定義原子類型為字符型
typedef char AtomType;// 定義元素標簽類型,用于區分原子和列表
typedef enum { ATOM, LIST } ElemTag;// 定義廣義表節點結構體
typedef struct GLNode 
{ElemTag tag;  // 標記該節點是原子還是列表union {AtomType atom;  // 如果是原子,存儲原子的值struct GLNode *child;  // 如果是列表,指向子列表} UNION;struct GLNode *next;  // 指向下一個節點
} GLNODE;// 定義元素標志類型,用于讀取字符串時識別不同元素
typedef enum { LP = 1, RP = 2, Atom = 3, End = 4 } ElemFlag;// 從 str[*pi] 開始讀入一個元素
ElemFlag GetElem(char str[], int *pi, AtomType *pe)
{while (str[*pi] == ' ') (*pi)++;// 跳過空格if (str[*pi] == '\0') return End;// 如果到達字符串末尾,返回 End 標志if (str[*pi] == '(')// 如果遇到左括號,返回 LP 標志,并將指針后移{		(*pi)++;return LP;}if (str[*pi] == ')') // 如果遇到右括號,返回 RP 標志,并將指針后移{(*pi)++;return RP;}// 如果是原子,將字符賦值給 pe,并將指針后移,返回 Atom 標志*pe = str[*pi];(*pi)++;return Atom;
}// 建廣義表
GLNODE *Glist_Create(char str[], int *pi) 
{GLNODE *p;AtomType e;// 根據讀取的元素類型進行不同處理switch (GetElem(str, pi, &e)) {case Atom:// 為原子節點分配內存p = (GLNODE *)malloc(sizeof(GLNODE));if (p == NULL) {fprintf(stderr, "內存分配失敗\n");exit(EXIT_FAILURE);}p->tag = ATOM;p->UNION.atom = e;p->next = Glist_Create(str, pi);// 遞歸創建下一個節點return p;case LP:// 為列表節點分配內存p = (GLNODE *)malloc(sizeof(GLNODE));if (p == NULL) {fprintf(stderr, "內存分配失敗\n");exit(EXIT_FAILURE);}p->tag = LIST;p->UNION.child = Glist_Create(str, pi);// 遞歸創建子列表p->next = Glist_Create(str, pi);// 遞歸創建下一個節點return p;case RP:return NULL;case End:return NULL;}return NULL;
}// 求表深度
int GList_Depth(GLNODE *L) 
{GLNODE *p;int depth1, max = 0;if (L == NULL || L->tag == ATOM) return 0;// 如果是原子節點,深度為 0for (p = L->UNION.child; p; p = p->next) // 遍歷子列表{depth1 = GList_Depth(p);// 遞歸計算子列表的深度if (depth1 > max) max = depth1;}return max + 1;// 列表深度為子列表最大深度加 1
}// 遍歷廣義表,打印層次括號
void GList_Traverse(GLNODE *L) 
{GLNODE *p;for (p = L; p != NULL; p = p->next) {if (p->tag == ATOM) {printf("%c ", p->UNION.atom);// 打印原子節點的值} else {printf("(");// 遇到列表節點,打印左括號GList_Traverse(p->UNION.child);// 遞歸遍歷子列表printf(")");// 打印右括號}}
}// 復制廣義表
GLNODE *GList_Copy(GLNODE *L) 
{GLNODE *head = NULL, *p, *newNode, *tail = NULL;if (!L) return NULL;for (p = L; p != NULL; p = p->next) {// 為新節點分配內存newNode = (GLNODE *)malloc(sizeof(GLNODE));if (newNode == NULL) {fprintf(stderr, "內存分配失敗\n");exit(EXIT_FAILURE);}if (head == NULL) {head = tail = newNode;} else {tail->next = newNode;tail = newNode;}if (p->tag == ATOM) {newNode->tag = ATOM;// 復制原子節點newNode->UNION.atom = p->UNION.atom;} else {newNode->tag = LIST;// 復制列表節點,遞歸復制子列表newNode->UNION.child = GList_Copy(p->UNION.child);}}if (tail) {tail->next = NULL;}return head;
}int main() 
{char str[30] = "(a (b c) d)";  // 廣義表的字符串表示int i = 0;GLNODE *L1, *L2;L1 = Glist_Create(str, &i);		// 創建廣義表 L1GList_Traverse(L1);				// 遍歷并打印廣義表 L1printf("%d\n", GList_Depth(L1));// 計算并打印廣義表 L1 的深度L2 = GList_Copy(L1);			// 復制廣義表 L1 到 L2GList_Traverse(L2);				// 遍歷并打印廣義表 L2printf("%d\n", GList_Depth(L2));// 計算并打印廣義表 L2 的深度return 0;
}

(一)數據結構定義:搭建廣義表的基石

typedef struct GLNode 
{ElemTag tag;  // 標記該節點是原子還是列表union {AtomType atom;  // 如果是原子,存儲原子的值struct GLNode *child;  // 如果是列表,指向子列表} UNION;struct GLNode *next;  // 指向下一個節點
} GLNODE;

這段代碼定義了廣義表的節點結構?GLNODEtag?字段就像一個神奇的標簽,能夠區分節點是原子還是列表。UNION?聯合體則根據?tag?的值,巧妙地存儲原子或指向子列表的指針。next?指針則負責將各個節點連接起來,形成一個有序的鏈條。這種設計讓廣義表能夠靈活地表示不同類型的元素和復雜的嵌套結構,為后續的操作奠定了堅實的基礎。

(二)廣義表的創建:從字符串到數據結構的神奇轉變

GLNODE *Glist_Create(char str[], int *pi) 
{// ...
}

Glist_Create?函數是廣義表創建的核心。它通過?GetElem?函數從輸入的字符串中逐個讀取元素,就像一位細心的工匠,根據元素的類型(原子、左括號、右括號、字符串結束)進行不同的處理。遇到原子時,為其創建一個原子節點;遇到左括號時,創建一個列表節點,并遞歸地創建子列表。遞歸的方式讓代碼簡潔而高效,能夠輕松應對廣義表的嵌套結構,就像一位技藝高超的魔術師,將字符串神奇地轉化為廣義表的數據結構。

(三)廣義表的深度計算:探索廣義表的 “深度” 秘密

int GList_Depth(GLNODE *L) 
{// ...
}

GList_Depth?函數用于計算廣義表的深度。對于原子節點,其深度為 0;對于列表節點,則遞歸地計算子列表的深度,并取子列表最大深度加 1 作為當前列表的深度。遞歸的思想在這里再次發揮了重要作用,讓我們能夠輕松地探索廣義表的 “深度” 秘密,就像一位勇敢的探險家,深入廣義表的內部,測量其嵌套的層次。

(四)廣義表的遍歷:揭開廣義表的 “廬山真面目”

void GList_Traverse(GLNODE *L) 
{// ...
}

GList_Traverse?函數就像一位導游,帶領我們遍歷廣義表并打印其層次括號表示。遇到原子節點時,直接打印原子的值;遇到列表節點時,先打印左括號,遞歸地遍歷子列表,再打印右括號。通過遞歸遍歷,我們能夠清晰地看到廣義表的層次結構,揭開它的 “廬山真面目”,仿佛置身于一個神秘的迷宮中,一步步揭開它的神秘面紗。

(五)廣義表的復制:克隆一個一模一樣的廣義表

GLNODE *GList_Copy(GLNODE *L) 
{// ...
}

GList_Copy?函數用于復制廣義表。它遍歷原廣義表的每個節點,為新節點分配內存,并根據節點類型復制原子或遞歸地復制子列表。這樣,我們就可以得到一個與原廣義表結構完全相同的新廣義表,就像克隆技術一樣,復制出一個一模一樣的 “雙胞胎”。

運行:

四、廣義表的應用場景:無處不在的 “魔法工具”

(一)編譯器設計:解析代碼的得力助手

在編譯器中,廣義表可以用于表示語法樹。語法樹是源代碼的一種抽象表示,它反映了代碼的語法結構。廣義表的嵌套結構正好可以用來表示語法樹的層次關系,方便編譯器進行語法分析和代碼生成。就像一位聰明的翻譯官,將源代碼翻譯成計算機能夠理解的機器語言。

(二)人工智能:構建知識圖譜的強大武器

在人工智能領域,廣義表可以用于表示知識圖譜。知識圖譜是一種語義網絡,用于表示實體之間的關系。廣義表可以將實體和關系表示為節點和子列表,從而方便進行知識的存儲和推理。就像一位智慧的導師,幫助人工智能系統更好地理解和處理知識。

(三)圖形處理:繪制復雜圖形的神奇畫筆

在圖形處理中,廣義表可以用于表示復雜的圖形結構。例如,一個三維模型可以由多個子模型組成,每個子模型又可以由多個基本圖形組成。廣義表可以很好地表示這種層次結構,方便進行圖形的渲染和處理。就像一位天才的畫家,用神奇的畫筆繪制出絢麗多彩的圖形世界。

五、總結與展望

通過遞歸的方式,我們可以方便地實現廣義表的創建、深度計算、遍歷和復制等操作。

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

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

相關文章

【jenkins】首次配置jenkins

第一步&#xff0c;輸入管理員密碼 cat /var/jenkins_home/secrets/initialAdminPassword第二步&#xff0c;點擊安裝推薦的插件 第三步&#xff0c;創建管理員用戶 第四步&#xff0c;返回實例 第五步&#xff0c; 升級jenkins 第六步&#xff0c; 修復提示 第七步&#xff0c…

Android studio—socketIO庫return與emit的使用

文章目錄 一、Socket.IO庫簡單使用說明1. 后端 Flask Flask-SocketIO2. Android 客戶端集成 Socket.IO3. 布局文件注意事項 二、接受服務器消息的二種方法1. 客戶端接收通過 emit 發送的消息功能使用場景后端代碼&#xff08;Flask-SocketIO&#xff09;客戶端代碼&#xff08…

用Prompt 技術【提示詞】打造自己的大語言智能體

機器如何按照人類的指令執行任務的探索 機器需具備理解任務敘述的能力&#xff0c;以便能夠按照人類的指令執行任務&#xff0c;為機器提供一些范例作為參考&#xff0c;使其能夠理解該執行的任務類型。這樣的學習方式稱為“Instruction learning”&#xff0c;透過精心設計的…

Node.js 數據庫 事務 項目示例

1、參考&#xff1a;JavaScript語言的事務管理_js 函數 事務性-CSDN博客 或者百度搜索&#xff1a;Nodejs控制事務&#xff0c; 2、實踐 2.1、對于MySQL或MariaDB&#xff0c;你可以使用mysql或mysql2庫&#xff0c;并結合Promise或async/await語法來控制事務。 使用 mysql2…

【Mamba】MambaVision論文閱讀

文章目錄 MambaVision一、研究背景&#xff08;一&#xff09;Transformer vs Mamba?&#xff08;二&#xff09;Mamba in CV? 二、相關工作?&#xff08;一&#xff09;Transformer 在計算機視覺領域的進展?&#xff08;二&#xff09;Mamba 在計算機視覺領域的探索? 三、…

前端面試寶典---原型鏈

引言----感謝大佬的講解 大佬鏈接 原型鏈示意圖 原型鏈問題中需要記住一句話&#xff1a;一切變量和函數都可以并且只能通過__proto__去找它所在原型鏈上的屬性與方法 原型鏈需要注意的點 看上圖可以發現 函數&#xff08;構造函數&#xff09;也可以通過__proto__去找到原…

C語言---FILE結構體

一、FILE 結構體的本質與定義 基本概念 FILE 是 C 語言標準庫中用于封裝文件操作的結構體類型&#xff0c;定義于 <stdio.h> 中。它代表一個“文件流”&#xff0c;可以是磁盤文件、標準輸入輸出&#xff08;stdin/stdout/stderr&#xff09;或其他輸入輸出設備。 實現特…

基于大模型的直腸息肉診療全流程風險預測與方案優化研究報告

目錄 一、引言 1.1 研究背景與意義 1.2 研究目的與創新點 二、大模型技術概述 2.1 大模型原理簡介 2.2 大模型在醫療領域應用現狀 三、直腸息肉術前預測與準備 3.1 基于大模型的術前風險預測 3.1.1 息肉性質預測 3.1.2 手術難度預測 3.2 基于預測結果的術前準備 3.…

華為OD機試真題——MELON的難題(2025A卷:200分)Java/python/JavaScript/C++/C語言/GO六種最佳實現

2025 A卷 200分 題型 本文涵蓋詳細的問題分析、解題思路、代碼實現、代碼詳解、測試用例以及綜合分析&#xff1b; 并提供Java、python、JavaScript、C、C語言、GO六種語言的最佳實現方式&#xff01; 2025華為OD真題目錄全流程解析/備考攻略/經驗分享 華為OD機試真題《MELON的…

AI數據分析與BI可視化結合:解鎖企業決策新境界

大家好&#xff0c;今天我們來聊聊一個前沿而熱門的話題——AI數據分析與BI可視化結合&#xff0c;如何攜手推動企業決策邁向新高度。在數據爆炸的時代&#xff0c;企業如何高效利用這些數據&#xff0c;成為制勝的關鍵。AI數據分析與BI可視化的結合&#xff0c;正是解鎖這一潛…

克服儲能領域的數據處理瓶頸及AI拓展

對于儲能研究人員來說&#xff0c;日常工作中經常圍繞著一項核心但有時令人沮喪的任務&#xff1a;處理實驗數據。從電池循環儀的嗡嗡聲到包含電壓和電流讀數的大量電子表格&#xff0c;研究人員的大量時間都花在了提取有意義的見解上。長期以來&#xff0c;該領域一直受到對專…

【SpringBoot+Vue自學筆記】002 SpringBoot快速上手

跟著這位老師學習的&#xff1a;https://www.bilibili.com/video/BV1nV4y1s7ZN?vd_sourceaf46ae3e8740f44ad87ced5536fc1a45 最好和老師的idea版本完全一致&#xff01;截至本文寫的當日最新的idea好像默認jdk17&#xff0c;配置時遇到很多bug。 &#x1f33f; Spring Boot&a…

SpringAI+DeepSeek大模型應用開發——2 大模型應用開發架構

目錄 2.大模型開發 2.1 模型部署 2.1.1 云服務-開放大模型API 2.1.2 本地部署 搜索模型 運行大模型 2.2 調用大模型 接口說明 提示詞角色 ?編輯 會話記憶問題 2.3 大模型應用開發架構 2.3.1 技術架構 純Prompt模式 FunctionCalling RAG檢索增強 Fine-tuning …

藍橋杯12. 日期問題

日期問題 原題目鏈接 題目描述 小明正在整理一批歷史文獻。這些歷史文獻中出現了很多日期。 小明知道這些日期都在 1960 年 1 月 1 日 至 2059 年 12 月 31 日 之間。 令小明頭疼的是&#xff0c;這些日期采用的格式非常不統一&#xff1a; 有的采用 年/月/日有的采用 月…

STM32使用rand()生成隨機數并顯示波形

一、隨機數生成 1、加入頭文件&#xff1a;#include "stdlib.h" 2、定義一個用作生成隨機數種子的變量并加入到滴答定時器中不斷自增&#xff1a;uint32_t run_times 0; 3、設置種子&#xff1a;srand(run_times);//每次生成隨機數前調用一次為佳 4、生成一個隨…

『前端樣式分享』聯系我們卡片式布局 自適應屏幕 hover動效 在wikijs中使用 (代碼拿來即用)

目錄 預覽效果分析要點響應式網格布局卡片樣式&#xff1a;陰影和過渡效果 代碼優化希望 長短不一的郵箱地址在左右居中的同時,做到左側文字對齊(wikijs可用)總結 歡迎關注 『前端布局樣式』 專欄&#xff0c;持續更新中 歡迎關注 『前端布局樣式』 專欄&#xff0c;持續更新中…

【ubuntu】在Linux Yocto的基礎上去適配Ubuntu的wifi模塊

一、修改wifi的節點名 1.找到wifi模塊的PID和VID ifconfig查看wifi模塊網絡節點的名字&#xff0c;發現是wlx44876393bb3a&#xff08;wlxmac地址&#xff09; 通過udevadm info -a /sys/class/net/wlx44876393bba路徑的命令去查看wlx44876393bba的總線號&#xff0c;端口號…

健康養生:開啟活力生活新篇章

在當代社會&#xff0c;熬夜加班、久坐不動、外賣快餐成為許多人的生活常態&#xff0c;隨之而來的是各種亞健康問題。想要擺脫身體的疲憊與不適&#xff0c;健康養生迫在眉睫&#xff0c;它是重獲活力、擁抱美好生活的關鍵。? 應對不良飲食習慣帶來的健康隱患&#xff0c;飲…

【verilog】多個 if 控制同一個變量(后面會覆蓋前面)非阻塞賦值真的并行嗎?

非阻塞賦值 (<) 是“并行”的&#xff0c;但是代碼順序會影響結果&#xff1f;”這正是 Verilog 的硬件描述本質 vs 行為語義之間的微妙之處。 &#x1f4a1;1. 非阻塞賦值真的并行嗎&#xff1f; 是的&#xff01;非阻塞賦值 < 從行為上是并行的&#xff0c;也就是說&a…

前沿篇|CAN XL 與 TSN 深度解讀

引言 1. CAN XL 標準演進與設計目標 2. CAN XL 物理層與幀格式詳解 3. 時間敏感網絡 (TSN) 關鍵技術解析 4. CAN XL + TSN 在自動駕駛領域的典型應用