數據結構【二叉樹的遍歷實現】

📘考研數據結構基礎:二叉樹的存儲、遍歷與隊列輔助實現詳

在這里插入圖片描述

在數據結構的學習中,二叉樹作為一種結構清晰、應用廣泛的樹形結構,是考研計算機專業課中重點內容之一。本文將以實際代碼為基礎,介紹二叉樹的存儲結構遍歷方式,以及在遍歷過程中為何要使用隊列結構,并解答一個常見疑問:“為什么不能用 char 類型直接代替隊列的元素類型”。

🧩一、二叉樹的存儲方式:鏈式存儲結構

在實際開發或算法設計中,二叉樹常采用鏈式存儲結構。其基本定義如下:

typedef struct BiTNode {char data;struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
  • 每個結點由一個字符 data 表示數據域。
  • lchildrchild 分別指向該結點的左、右子樹。
  • BiTree 是指向 BiTNode 的指針,代表一個樹的根結點。

🧪二、二叉樹的遍歷方式

? 1. 先序遍歷(PreOrder)

void PreOrder(BiTree T) {if (T) {cout << T->data;PreOrder(T->lchild);PreOrder(T->rchild);}
}

先訪問根結點,再遞歸遍歷左子樹和右子樹。


? 2. 中序遍歷(InOrder)

void InOrder(BiTree T) {if (T) {InOrder(T->lchild);cout << T->data;InOrder(T->rchild);}
}

先訪問左子樹,再訪問根結點,最后遍歷右子樹。


? 3. 后序遍歷(PostOrder)

void PostOrder(BiTree T) {if (T) {PostOrder(T->lchild);PostOrder(T->rchild);cout << T->data;}
}

先遍歷左右子樹,最后訪問根結點。


? 4. 層序遍歷(LevelOrder)

層序遍歷不同于上面三種遞歸遍歷,它需要用輔助隊列實現。

void LevelOrder(BiTree T) {LinkQueue Q;InitQ(Q);EntQ(Q, T);while (!EmptyQ(Q)) {BiTree p;DelQ(Q, p);cout << p->data;if (p->lchild)EntQ(Q, p->lchild);if (p->rchild)EntQ(Q, p->rchild);}
}

🚩三、輔助隊列結構及其核心設計

為了支持層序遍歷的廣度優先訪問,我們需要一個隊列,隊列中存放的是樹結點的指針而非字符:

typedef BiTree ElemType;  // 關鍵設計:定義隊列的元素類型為 BiTree(即指向樹結點的指針)

隊列的基本操作如下:

bool EntQ(LinkQueue &Q, ElemType x);    // 入隊
bool DelQ(LinkQueue &Q, ElemType &x);   // 出隊

?為什么不能直接將 ElemType 改為 char?

這是許多初學者常見的疑惑。解釋如下:

  • char 僅能存儲字符,比如 'A',卻無法提供關于該字符結點的結構信息。

  • 層序遍歷時,我們需要訪問一個結點的左右孩子:

    if (p->lchild) EntQ(Q, p->lchild);
    

    這里 p 是一個指向結構體的指針,如果你僅保存了 char,根本無法訪問 p->lchild

? 所以,隊列中必須保存的是 BiTree 類型的指針,從而能繼續遞歸或迭代處理其子樹。


🧵四、二叉樹的構建

構建過程通常采用先序遞歸建樹法,使用 '#' 表示空結點:

void CreateTree(BiTree &T) {char ch;cin >> ch;if (ch == '#')T = NULL;else {T = new BiTNode;T->data = ch;CreateTree(T->lchild);CreateTree(T->rchild);}
}

輸入示例(先序):

AB#D##C##

表示結構如下的樹:

    A/ \B   C\D

🔚五、總結與考研建議

知識點內容
存儲結構常用鏈式存儲,結構清晰,動態性強
遍歷方法先序、中序、后序、層序,掌握遞歸與非遞歸實現
輔助結構層序遍歷需要隊列,存儲的是結點指針 BiTree
設計技巧使用 typedef ElemType 抽象數據類型,增強復用性

完整代碼《僅供參考》

function.h

 //層次建樹   借助一個輔助隊列//          a//        b   c//    d   e   f   g
    #ifndef LEVELIRDER3_FUNCTION_H#define LEVELIRDER3_FUNCTION_H#include <stdio.h>#include <stdlib.h>#include <ostream>using namespace std;//樹的結構體定義typedef struct BiTNode{char data;struct BiTNode *lchild,*rchild;}BiTNode , * BiTree;//隊列的結構體的聲明typedef BiTree ElemType;typedef struct LinkNode{ElemType datac;//在進行入隊的時候 這里使用的是 int 類型的的數據 然而樹存儲的是一個char  類型的這時候就體現出的了 typedef 的作用了 不用頻繁的修改數據struct LinkNode * next;}LinkNode;typedef struct {  //聲明一個結構體類型的指針LinkNode * front, * rear;}LinkQueue;void InitQ(LinkQueue &Q);bool EmptyQ(LinkQueue Q);//這里出入隊列 實際上是對 樹 的結點進行 的一個操作 所以應該使用 樹的 結構體類型bool EntQ(LinkQueue &Q,ElemType x);bool DelQ(LinkQueue &Q, ElemType &x);// 建立一個輔助隊列 tag  進行層序建樹typedef struct tag{//    BiTree p;  //樹的某一結點的地址值BiTNode *p;struct tag *pnext;}tag_t , *ptag_t;#endif //LEVELIRDER3_FUNCTION_H

queue.cpp

   //// Created by Yhame on 2025/5/11.//#include "function.h"//初始化void InitQ(LinkQueue &Q){//這里的結構體類型  LinkNodeQ.front = Q.rear =(LinkNode*) malloc(sizeof(LinkNode));Q.front->next =NULL; //隊頭指向NULL}//判空 這里可以不用判斷隊列是否會滿bool EmptyQ(LinkQueue Q){if(Q.front == Q.rear)return true;//    Q.front->next =NULL;//    return true;}//入隊bool EntQ(LinkQueue &Q,ElemType x){//插入LinkNode *s =(LinkNode*)malloc(sizeof(LinkNode)); //申請新的結點 插入隊尾if(!s)return false;s->datac =x;   //尾巴插入Q.rear->next =s;   //尾部入隊  尾指針的指向ss->next =NULL;  //s的指向NULLQ.rear =s;  //更新尾指針return true;}//出隊bool DelQ(LinkQueue &Q,ElemType &x){ //判空 從頭開始刪除if(Q.front ==Q.rear){return false;}LinkNode *q ;x = Q.front->next->datac; //返回要刪除的數據q = Q.front->next;  //q指向第一個數據結點  隊頭出Q.front->next =q ->next;  //斷開q 使front 指向后一個元素if(Q.rear==q){Q.rear = Q.front; // rear也回到front(空隊列狀態)}free(q);//如果q 為最后一個結點  使front 和rear 相等return true;}

main.cpp

     #include <iostream>#include "function.h"//前序遍歷void PreOrder(BiTree p){if(p!=NULL){printf("%c",p->data);PreOrder(p->lchild);PreOrder(p->rchild);}}//中序遍歷void InOrder(BiTree p){if(p!=NULL){InOrder(p->lchild);printf("%c",p->data);InOrder(p->rchild);}}//后序遍歷void PostOrder(BiTree p){if(p!=NULL){PostOrder(p->lchild);PostOrder(p->rchild);printf("%c",p->data);}}//層次遍歷void LevelOrder(BiTree T){LinkQueue Q; //聲明一個 輔助隊列InitQ(Q);BiTree p;  //記錄樹的當前結點//    BiTNode * p;EmptyQ(Q);EntQ(Q,T);  //樹根入隊當隊列不為空進行 隊頭出隊打印   之后判斷 該點的 左右孩子是否為空  進行出入隊操作puts("層序");while(!EmptyQ(Q)){DelQ(Q,p); //出隊當前結點 并打印putchar(p->data);  //printf("%c,c);if(p->lchild!=NULL){EntQ(Q,p->lchild);}if(p->rchild!=NULL){EntQ(Q,p->rchild);}}}int main() {BiTree pnew; //用來指向新申請的數結點BiTree tree =NULL; //tree 是指向樹根的,代表樹ptag_t phead= NULL,ptail =NULL, listpnew =NULL, pre =NULL; //初始化隊列 定義一個pre 指向執行的當前元素char c;這里使用的是 tag 的方法去建立一棵樹,通過輔助隊列來實現的 層序遍歷//abcdefwhile(scanf("%c",&c)){if(c=='\n'){break;}//calloc申請空間  大小是兩個參數相乘,并對空間進行初始化  賦值為0;//malloc 申請以后還需要對其進行賦值 malloc 返回的是 void * 類型的 也需要進行強制轉換樹申請結點pnew =(BiTree) calloc(1,sizeof(BiTNode));pnew->data = c;//隊列結點申請空間listpnew = (ptag_t) calloc(1,sizeof(tag_t));  //申請一個結構體類型的結點 返回一個指針類型的listpnew->p =pnew;//如果是數的第一個結點if(tree==NULL){tree = pnew;  //tree 指向根的頭結點//第一個結點 即是隊列頭也是 隊列尾phead = ptail = listpnew;pre = listpnew; //  用來判斷當前結點 的左右孩子是否滿了}else {//元素直接入隊ptail ->pnext = listpnew;ptail =listpnew;//接下來把元素放入樹中if(pre->p->lchild ==NULL){pre ->p ->lchild =pnew;  // pre -> p 左孩子為空 就放入左孩子}else if(pre->p->rchild==NULL){pre->p->rchild =pnew;pre = pre->pnext;  // !!! 左右孩子都滿了,指向下一個節點}}}puts("前序");PreOrder(tree);printf("\n");puts("中序");InOrder(tree);printf("\n");puts("后序");PostOrder(tree);printf("\n");LevelOrder(tree);return 0;//這沒有對樹進行相應的輸出  ,使用調試發現建樹完成}//abcdefg//        前序//abdecfg//        中序//dbeafcg//        后序//debfgca//        層序//abcdefg

這個代碼實現了通過層次輸入字符數據來構建一棵二叉樹,并對這棵二叉樹進行前序、中序、后序、層序遍歷,完整地展示了樹的構建與遍歷過程。


? 具體功能如下:

1. 層次建樹(用輔助隊列實現)

  • 利用自定義的tag_t 輔助隊列結構體進行層次建樹。
  • 每次輸入一個字符就創建一個二叉樹結點。
  • 如果當前樹為(即首次輸入),設置為根節點;
  • 后續的結點依次作為上一結點的左孩子右孩子插入;
  • 每插入完一個結點,就將其作為隊列中的一個元素排隊,繼續等待為它的孩子分配子節點。

📘寫在最后

學習數據結構尤其是二叉樹,最重要的是掌握“結構 + 操作”的關系。每一次遍歷、每一次入隊出隊,背后都是指針、結構體、遞歸這些基礎能力的體現。希望本文結合實際代碼的講解能為你的學習提供實用幫助。

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

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

相關文章

無人機俯視風光攝影Lr調色預設,手機濾鏡PS+Lightroom預設下載!

調色詳情 無人機俯視風光攝影 Lr 調色是利用 Adobe Lightroom 軟件&#xff0c;對無人機從俯視角度拍攝的風光照片進行后期處理的調色方式。通過調整色彩、對比度、光影等多種參數&#xff0c;能夠充分挖掘并強化畫面獨特視角下的壯美與細節之美&#xff0c;讓原本平凡的航拍風…

【springcloud學習(dalston.sr1)】Eureka服務端集群的搭建(含源代碼)(二)

該系列項目整體介紹及源代碼請參照前面寫的一篇文章【springcloud學習(dalston.sr1)】項目整體介紹&#xff08;含源代碼&#xff09;&#xff08;一&#xff09; 這篇文章主要介紹多個eureka服務端的集群環境是如何搭建的。 &#xff08;一&#xff09;eureka的簡要說明 Eu…

互聯網大廠Java求職面試實戰:Spring Boot微服務與數據庫優化詳解

&#x1f4aa;&#x1f3fb; 1. Python基礎專欄&#xff0c;基礎知識一網打盡&#xff0c;9.9元買不了吃虧&#xff0c;買不了上當。 Python從入門到精通 &#x1f601; 2. 畢業設計專欄&#xff0c;畢業季咱們不慌忙&#xff0c;幾百款畢業設計等你選。 ?? 3. Python爬蟲專欄…

事件驅動reactor的原理與實現

fdset 集合&#xff1a;&#xff08;就是說&#xff09; fd_set是一個位圖&#xff08;bitmap&#xff09;結構 每個位代表一個文件描述符 0表示不在集合中&#xff0c;1表示在集合中 fd_set結構&#xff08;簡化&#xff09;&#xff1a; [0][1][2][3][4][5]...[1023] …

一分鐘在Cherry Studio和VSCode集成火山引擎veimagex-mcp

MCP的出現打通了AI模型和外部數據庫、網頁API等資源&#xff0c;成倍提升工作效率。近期火山引擎團隊推出了 MCP Server SDK&#xff1a; veimagex-mcp。本文介紹如何在Cherry Studio 和VSCode平臺集成 veimagex-mcp。 什么是MCP MCP&#xff08;Model Context Protocol&…

掌控隨心 - 服務網格的流量管理藝術 (Istio 實例)

掌控隨心 - 服務網格的流量管理藝術 (Istio 實例) 想象一下,沒有服務網格的時候,我們要實現像“將 1% 的用戶流量導入到新版本應用”、“根據用戶設備類型訪問不同后端”、“模擬下游服務故障”這類高級流量策略,通常需要在代碼、負載均衡器、API 網關等多個地方進行復雜且分…

[ARM][匯編] 01.基礎概念

目錄 1.全局標號 1.1.使用方法 1.1.1.聲明全局標號 1.1.2.定義全局標號 1.1.3.引用全局標號 1.2.全局標號與局部標號的區別 1.3.注意事項 2.局部標號 2.1.使用方法 2.1.1.定義局部標號 2.1.2.跳轉引用 2.2.局部標號與全局標號的對比 2.3.注意事項 3.符號定義偽指…

如何使用遠程桌面控制電腦

目的&#xff1a; 通過路由器使用pc控制臺式機&#xff0c;實現了有線/無線pc與臺式機的雙向遠程桌面控制 最核心就兩條&#xff1a;get ip地址與被控制機器的賬戶與密碼。 現象挺神奇&#xff1a;被控制電腦的電腦桌面處于休眠模式&#xff0c;此時強行喚醒被控電腦會導致中斷…

Hive表JOIN性能問

在處理100TB的Hive表JOIN性能問題時&#xff0c;需采用分層優化策略&#xff0c;結合數據分布特征、存儲格式和計算引擎特性。以下是系統性優化方案&#xff1a; 1. 數據傾斜優化&#xff08;Skew Join&#xff09; 1.1 識別傾斜鍵 方法&#xff1a;統計JOIN鍵的分布頻率&…

MongoDB 的核心概念(文檔、集合、數據庫、BSON)是什么?

MongoDB 是一個面向文檔的數據庫&#xff0c;它的核心概念與傳統的關系型數據庫&#xff08;RDBMS&#xff09;有所不同。以下是它的四個主要核心概念&#xff1a; 文檔 (Document) 定義&#xff1a; 文檔是 MongoDB 中的基本數據單元。它類似于關系型數據庫中的一行記錄&#…

AI智慧公園管理方案:用科技重塑市民的“夜游體驗”

AI智慧公園管理方案&#xff1a;多場景智能巡檢與安全防控 一、背景與痛點分析 夏季夜間&#xff0c;公園成為市民休閑娛樂的核心場所&#xff0c;但管理難度隨之激增&#xff1a; 寵物管理失控&#xff1a;未牽繩寵物進入園區&#xff0c;隨地排泄、驚擾游客&#xff0c;甚…

Spring Cloud Gateway 聚合 Swagger 文檔:一站式API管理解決方案

前言 在微服務架構中&#xff0c;隨著服務數量的增加&#xff0c;API文檔管理變得越來越復雜。每個微服務都有自己的Swagger文檔&#xff0c;開發人員需要記住每個服務的文檔地址&#xff0c;這無疑增加了開發難度。本文將介紹如何使用Spring Cloud Gateway聚合所有微服務的Sw…

尼康VR鏡頭防抖模式NORMAL和ACTIVE的區別(私人筆記)

1. NORMAL 模式&#xff08;常規模式&#xff09; 適用場景&#xff1a;一般手持拍攝&#xff0c;比如人像、靜物、風景或緩慢平移鏡頭&#xff08;如水平追拍&#xff09;等。工作特性&#xff1a; 補償手抖引起的小幅度震動&#xff08;比如手持時自然的不穩&#xff09;&am…

Babylon.js學習之路《四、Babylon.js 中的相機(Camera)與視角控制》

文章目錄 1. 引言&#xff1a;為什么相機是 3D 場景的“眼睛”&#xff1f;1.1 相機的核心作用1.2 常見相機類型概覽 2. 相機基礎參數解析2.1 通用屬性2.2 相機坐標系 3. 詳解常用相機類型3.1 自由相機&#xff08;FreeCamera&#xff09;3.2 弧形旋轉相機&#xff08;ArcRotat…

【Python】普通方法、類方法和靜態方法的區分

Python 中普通方法、類方法和靜態方法的區分 下面我將從多個維度對這三種方法進行詳細對比&#xff0c;并通過示例說明它們的使用場景和區別。 1. 核心區別總結 特性普通方法(實例方法)類方法(classmethod)靜態方法(staticmethod)定義裝飾器無classmethodstaticmethod第一個…

geoserver發布arcgis瓦片地圖服務(最新版本)

第一步&#xff1a;下載geoserver服務&#xff0c;進入bin目錄啟動 需要提前安裝好JDK環境&#xff0c;1.8及以上版本 安裝完成&#xff0c;頁面訪問端口&#xff0c;進入控制臺界面,默認用戶名密碼admin/geoserver 第二步&#xff1a;下載地圖 破解版全能電子地圖下載器&…

Linux服務之lvs集群與dr模式部署

目錄 一.lvs相關概述 1.lvs集群的工作模式 2.lvs調度算法 3.ipvsadm工具 二.DR模式部署 一.lvs相關概述 1.lvs集群的工作模式 lvs-nat&#xff1a;修改請求報文的目標IP,多目標IP的DNAT lvs-dr&#xff1a;操縱封裝新的MAC地址&#xff08;直接路由&#xff09;lvs-tu…

OFCMS代碼審計-freemaker注入sql注入xxexss文件上傳

環境搭建 下載地址&#xff1a;https://gitee.com/oufu/ofcms/repository/archive/V1.1.2?formatzip SSTI模板注入&#xff08;freemaker) FreeMarker模板注入實現遠程命令執行 - Eleven_Liu - 博客園 在admin中找到這個 發現請求的是這個 找到他 <#assign value"f…

一鍵部署NSFW檢測模型:快速識別并過濾敏感圖片內容

以下是對nsfw_detector的簡單介紹&#xff1a; nsfw_detector是一個 NSFW 內容檢測器&#xff0c;支持快速docker私有部署&#xff0c;提供API服務低資源消耗&#xff0c;2GB內存即可運行該模型&#xff0c;多核CPU自動調度加速推理 - 可以識別多種文件類型&#xff1a;圖片、…

【Redis】緩存穿透、緩存雪崩、緩存擊穿

1.緩存穿透 是指客戶端請求的數據在緩存中和數據庫中都不存在&#xff0c;這樣緩存永遠不會生效&#xff0c;導致請求直接穿透緩存到達數據庫&#xff0c;給數據庫帶來壓力的情況。 常見的解決方案有兩種&#xff1a; 緩存空對象&#xff1a;實現簡單&#xff0c;維護方便&am…