探索數據結構:樹與二叉樹

?? 歡迎大家來到貝蒂大講堂??

🎈🎈養成好習慣,先贊后看哦~🎈🎈

所屬專欄:數據結構與算法
貝蒂的主頁:Betty’s blog

1. 樹

1.1. 樹的定義

是一種非線性的數據結構,它是由n(n >= 0)個有限結點組成一個具有層次關系的集合。把它叫做樹是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。

img

在樹中有一個特殊的結點,稱為根結點,根節點沒有前驅結點

除根節點外,其余結點被分成M(M > 0)個互不相交的集合T1、T2、……、Tm,其中每一個集合Ti(1 <= i<= m)又是一棵結構與樹類似的子樹。每棵子樹的根結點有且只有一個前驅,可以有0個或多個后繼因此,樹是遞歸定義的。

img

注意:樹形結構中,子樹之間不能有交集,否則就不是樹形結構

img

1.2. 樹的基本概念

術語定義
節點的度一個節點含有的子樹的個數稱為該節點的度,比如說節點1的度為2
葉節點度為0的節點,比如說4,5,6節點
分支節點度不為0的節點,比如說2,3節點
雙親節點若一個節點含有子節點,則這個節點稱為其子節點的父節點。比如說2是4,5的雙親節點
子節點一個節點含有的子樹的根節點稱為該節點的子節點,比如說4,5是2的子節點
兄弟節點具有相同父節點的節點互稱為兄弟節點,比如說4,5就是兄弟節點
樹的度一棵樹中,最大的節點的度稱為樹的度,比如說上面這棵樹的度為2
節點的層次從根開始定義起,根為第1層,根的子節點為第2層,以此類推
樹的高度或深度樹中節點的最大層次,比如說上面這棵樹的高度為3
堂兄弟節點雙親在同一層的節點互為堂兄弟,比如說5,6節點
節點的祖先從根到該節點所經分支上的所有節點,比如說1就是所有節點的祖先
子孫以某節點為根的子樹中任一節點都稱為該節點的子孫,比如說所有節點都是1的子孫
森林由m(m>0)棵互不相交的樹的集合稱為森林

1.3. 樹的表示方法

下面我們將采用三種方式表示下面這課樹:

img

1.3.1. 雙親表示法

雙親表示法采用順序表的方式存儲,即用順序表存儲各個節點的數據,并且同時存儲其雙親節點的下標。注意:根節點沒有雙親節點,所以特別記為-1。

#define MAX_SIZE 10
typedef int DataType;
typedef struct Node
{DataType data;//數據域int parent; //雙親結點在數組中的位置下標
}Node;
typedef struct PTree
{//存放樹中所有結點Node tnode[MAX_SIZE];//當前結點個數int n;
}PTree;

img

1.3.2. 樹的孩子表示法

樹的孩子表示法就是采用順序表與鏈表結合的形式,用順序表存儲樹的值與鏈表的頭節點,而鏈表的頭節點存儲其孩子節點在順序表中的下標,若沒有則記為空(N)。

#define MAX_SIZE 10
#define DataType int
typedef struct ListNode 
{int child;struct ListNode* next;
}ListNode;
typedef struct TNode
{DataType data;//孩子鏈表的頭指針ListNode* firstchild;
}TNode;
typedef struct PTree{//存儲結點的數組TNode nodes[MAX_SIZE];int n; //結點數量
}PTree;

img

1.3.3. 左孩子右兄弟表示法

最常用表示樹的的方法就是左孩子右兄弟表示法,即定義兩個指針,讓左指針指向子節點,右指針指向兄弟節點。

如果沒有節點,則都指向空。

typedef int DataType;
struct Node
{struct Node* leftChild1; // 孩子結點struct Node* rightBrother; // 指向其下一個兄弟結點DataType _data; // 結點中的數據域
};

img

1.4. 樹的實際應用

在linux環境下目錄結構就是有一顆樹構成,而在Windows環境下,目錄許多內容并不交叉,所以是由森林構成。

img

2. 二叉樹

2.1. 二叉樹的定義

一棵二叉樹是結點的一個有限集合,該集合可能為空,也可以由一個根節點加上兩棵別稱為左子樹和右子樹的二叉樹組成。

注意:

  1. 二叉樹不存在度大于2的結點
  2. 二叉樹的子樹有左右之分,次序不能顛倒,因此二叉樹是有序樹

img

img

2.2. 特殊的二叉樹

2.2.1. 滿二叉樹

滿二叉樹:一個二叉樹,如果每一個層的結點數都達到最大值,則這個二叉樹就是滿二叉樹。也就是說,如果一個二叉樹的層數為K,且結點總數是N=2k -1,則它就是滿二叉樹。

img

2.2.2. 完全二叉樹

**完全二叉樹:**完全二叉樹是效率很高的數據結構,完全二叉樹是由滿二叉樹而引出來的。對于深度為K的,有n個結點的二叉樹,當且僅當其每一個結點都與深度為K的滿二叉樹中編號從1至n的結點一一對應時稱之為完全二叉樹。 要注意的是滿二叉樹是一種特殊的完全二叉樹。

img

2.3. 二叉樹的特點

  1. 若規定根節點的層數為1,則一棵非空二叉樹的第i層上最多有2i -1個結點。
  2. 若規定根節點的層數為1,則深度為h的二叉樹的最大結點數N=1+2+4+…+2i -1=2h -1
  3. 對任何一棵二叉樹, 如果度為0其葉結點個數為N0, 度為2的分支結點個數為N2, 則有 N0=N2+1

證明如下:

假設節點總數為N,如果度為0其葉結點個數為N0, 度為1的分支結點個數為N1,度為2的分支結點個數為N2

節點總數:N=N0 + N1+ N2 又因為二叉樹的邊比節點樹少1,所以N= N1 +2N2+1=>N0 + N1+ N2= N1 +2N2+1=>N0=N2+1

  1. 若規定根節點的層數為1,具有n個結點的滿二叉樹的深度,h =log2 (n+1) 。

  2. 對于具有n個結點的完全二叉樹,如果按照從上至下從左至右的數組順序對所有節點從0開始編號,則對

? 于序號為i的結點有:

? 1. 若i > 0,i位置節點的雙親序號:(i - 1) / 2;i = 0,i為根節點編號,無雙親節點。

? 2. 若2i + 1 < n,左孩子序號:2i + 1,2i + 1 >= n否則無左孩子。

? 3. 若2i + 2 < n,右孩子序號:2i + 2,2i + 2 >= n否則無右孩子。

2.4. 二叉樹的存儲

2.4.1. 數組存儲

我們可以通過雙親節點與子節點下標之間的映射關系將二叉樹存儲在數組中,如果節點為空,我們以INT_MAX來標記。

img

2.4.2. 鏈式存儲

除了數組存儲,我們也可以鏈式存儲二叉樹。

typedef struct BinaryTreeNode
{struct BinTreeNode* left; // 左孩子struct BinTreeNode* right; // 右孩子DataType data; // 當前節點值域
}BTree;

2.5. 二叉樹的遍歷

二叉樹的遍歷一般有四種方法:前序遍歷,中序遍歷,后序遍歷,層序遍歷。

img

2.5.1. 前序遍歷

前序遍歷:先遍歷根節點,再依次遍歷左子樹,右子樹。而遍歷左子樹,又要先遍歷根節點,再依次遍歷左子樹,右子樹…直至遍歷到空樹。

  1. 遞歸實現
void PreOrder(BTree*root)
{if (root == NULL){return;}printf("%d ", root->data);//根節點PreOrder(root->left);//左子樹PreOrder(root->right);//右子樹
}
  1. 非遞歸實現

非遞歸實現樹的前序遍歷我們需要借助棧這個數據結構,來達到與遞歸一樣的深度優先遍歷的目的。并且棧中存儲元素為BTree*

  typedef BTree* STDataType;void PreOrder(BTree* root){Stack s;				InitStack(&s);			  BTree*p = root;// p為遍歷指針while (p || !IsEmpty(&s))  // 棧不為空或p不為空時循環{if(p!=NULL)//入棧{printf("%d ", p->data);//根節點StackPush(&s, p);p = p->left;}else//出棧,訪問右子樹{p = StackTop(&s);//訪問原本雙親節點StackPop(&s);	  // 棧頂元素出棧p = p->right; //訪問}					 }}
2.5.2. 中序遍歷

中序遍歷:先遍歷左子樹,再依次遍歷根節點,右子樹。而遍歷左子樹,又要先遍歷左子樹,再依次遍歷根節點,右子樹…直至遍歷到空樹。

  1. 遞歸實現
void Inorder(BTree*root)
{if (root == NULL){return;}PreOrder(root->left);//左子樹printf("%d ", root->data);//根節點PreOrder(root->right);//右子樹
}
  1. 非遞歸實現

非遞歸實現樹的中序遍歷我們需要借助棧這個數據結構,來達到與遞歸一樣的深度優先遍歷的目的。并且棧中存儲元素為BTree*

  typedef BTree* STDataType;void Inorder(BTree* root){Stack s;InitStack(&s);BTree* p = root;// p為遍歷指針while (p || !IsEmpty(&s))  // 棧不為空或p不為空時循環{if (p != NULL)//入棧{StackPush(&s, p);p = p->left;}else//出棧,訪問右子樹{p = StackTop(&s);//訪問原本雙親節點StackPop(&s);	  // 棧頂元素出棧printf("%d ", p->data);p = p->right; //訪問}}}
2.5.3. 后序遍歷

后序遍歷:先遍歷左子樹,再依次遍歷右子樹,根節點。而遍歷左子樹,又要先遍歷左子樹,再依次遍歷右子樹,根節點…直至遍歷到空樹。

  1. 遞歸實現
void Postorder(BTree*root)
{if (root == NULL){return;}PreOrder(root->left);//左子樹PreOrder(root->right);//右子樹printf("%d ", root->data);//根節點
}
  1. 非遞歸實現

非遞歸實現樹的后序遍歷我們需要借助棧這個數據結構,來達到與遞歸一樣的深度優先遍歷的目的。并且棧中存儲元素為BTree*

void Postorder(BTree* root)
{Stack s;InitStack(&s);BTree* p = root;// p為遍歷指針BTree* v = root;// v標記已訪問節點while (p || !IsEmpty(&s))  // 棧不為空或p不為空時循環{while(p != NULL)//入棧{StackPush(&s, p);p = p->left;}p = StackTop(&s);//訪問雙親節點if (p->right && p->right != v)//存在右子樹,且沒有被訪問{p = p->right;//訪問}else//沒有右子樹或者右子樹已被訪問{printf("%d ", p->data);v = p;//記錄當前訪問的節點p = NULL;//防止重復訪問左子樹StackPop(&s);// 棧頂元素出棧}}
}
2.5.4. 層序遍歷

img

層序遍歷顧名思義就是一層一層地遍歷,這時就需要借助一個數據結構:隊列來輔助實現。

void leverOrder(BTree* root, Queue* pq)
{if (root == NULL)//為空直接返回{return;}QueuePush(pq, root);//插入第一個節點while (!QueueEmpty(pq))//隊列不為空{BTree* p = QueueFront(pq);printf("%d ", p->val);QueuePop(pq);if (p->left != NULL)//帶入左孩子{QueuePush(pq, p->left);}if (p->right != NULL)//帶入右孩子{QueuePush(pq, p->right);}}
}

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

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

相關文章

ORA-609頻繁出現在alert.log,如何解決?

ORA-609就alertlog中比較常見的一個報錯&#xff0c;雖然并沒有太大的影響&#xff0c;但是頻繁的出現在alert log也是很讓人厭煩的事情&#xff0c;本文介紹如何排查解決ORA-609問題。 1.ORA-609官方定義 could not attach to incoming connection Cause Oracle process cou…

【SRC實戰】前端脫敏信息泄露

挖個洞先 https://mp.weixin.qq.com/s/xnCQQCAneT21vYH8Q3OCpw “ 以下漏洞均為實驗靶場&#xff0c;如有雷同&#xff0c;純屬巧合 ” 01 — 漏洞證明 一、前端脫敏&#xff0c;請求包泄露明文 “ 前端脫敏處理&#xff0c;請求包是否存在泄露&#xff1f; ” 1、獲取驗…

|Python新手小白中級教程|第二十八章:面向對象編程(類定義語法私有屬性類的繼承與多態)(4)

文章目錄 前言一、類定義語法二、私有方法和私有屬性1.私有屬性2.私有方法 三、類“繼承”1.初識繼承2.使用super函數調用父類中構造的東西 四、類“多態”1.多態基礎2.子類不同形態3.使用isinstance函數與多態結合判斷類型 總結 前言 大家好&#xff0c;我是BoBo仔吖&#xf…

6818Linux內核開發移植

Linux內核開發移植 Linux內核版本變遷及其獲得 Linux是最受歡迎的自由電腦操作系統內核&#xff0c; 是一個用C語言寫成&#xff0c; 并且符合POSIX標準的類Unix操作系統 Linux是由芬蘭黑客Linus Torvalds開發的&#xff0c; 目的是嘗試在英特爾x86架構上提供自由免費的類Un…

Task Office for Mac v9.0激活版:任務管理新境界

還在為繁瑣的任務管理而煩惱嗎&#xff1f;Task Office for Mac為您帶來全新的任務管理體驗。簡潔明了的界面設計&#xff0c;讓您輕松上手&#xff1b;強大的任務管理和項目管理功能&#xff0c;讓您輕松掌握任務進度&#xff1b;多用戶協作功能&#xff0c;讓團隊協作更加高效…

ubuntu24.04安裝ros

ubuntu24.04安裝ros 踩坑 踩坑 目前安裝人數比較少&#xff0c;沒有較為詳細的博客&#xff0c;參考官網的鏈接 http://docs.ros.org/en/rolling/Installation/Ubuntu-Install-Debians.html 同時在如下的一步中會找不到網址報錯&#xff0c;此時可以參考https://blog.51cto.c…

Excel辦公技巧之下拉菜單

在日常辦工中&#xff0c;經常需在單元格中輸入特定的值&#xff0c;此時我們可以使用下拉菜單解決&#xff0c;輸入錯誤和錯誤值&#xff0c;可以一勞永逸的解決固定數據輸入問題。 使用Excel下拉菜單時&#xff0c;它在數據輸入和驗證方面發揮著重要作用通過點擊單元格的下拉…

學習筆記-Vue3中Hook函數

什么是Hook函數 Hook翻譯過來是鉤子的意思&#xff0c;其本質上是一組可復用的函數。簡單理解來說&#xff0c;你能夠在不同的組件中&#xff0c;實現相同的代碼邏輯&#xff0c;以達到代碼復用、提高維護性的效果。那為何叫’鉤子’呢&#xff0c;我的理解是&#xff1a; 它可…

商業數據分析--時間序列圖及趨勢分析

繪制時間序列圖,并指出存在什么樣的狀態如上兩圖: 可見狀態:從時間序列圖可以看出,這些數據存在明顯的季節性波動,每年的第4季度值都最高,而第2季度值最低。同時也存在一些下降的趨勢。 通過引進虛擬變量,建立多元線性回歸模型。答: 通過引入虛擬變量,我們可以建立如下的…

Oracle數據庫之多表查詢、層次查詢(五)

目錄 前言 Oracle 的連接條件的類型 多表查詢 1. 使用JOIN關鍵字 2. 使用WHERE子句進行多表查詢 3. 子查詢 4. EXISTS關鍵字 5. 集合運算 6. 注意事項&#xff1a; 層次查詢 前言 Oracle 的連接條件的類型 等值連接不等值連接外連接自連接 多表查詢 在Oracle數據…

商場學習之微服務

前言 寒假前在新電腦上配置了java環境&#xff0c;maven倉庫&#xff0c;node,js&#xff0c;navicat&#xff0c;MySQL&#xff0c;linux&#xff0c;vmware等環境&#xff0c;創建了6個mysql數據庫&#xff0c;77張表。 如此多的表&#xff0c;字段&#xff0c;去手寫基礎…

Web入門——三欄布局頁面

前置知識 內外邊距 內邊距(padding)&#xff1a; padding是元素邊框與其內容之間的空間。也就是說&#xff0c;如果你給一個元素設置了內邊距&#xff0c;這個空間會作為元素內容與元素邊框之間的緩沖區域。設置內邊距會使元素本身變大。例如padding:10px就創建了10像素的空間…

Qt之QMqtt 發送圖片數據

簡述 MQTT(消息隊列遙測傳輸)是ISO標準下基于發布/訂閱范式的消息協議;它工作在TCP/IP協議族上,是為硬件性能低下的遠程設備以及網絡狀況糟糕的情況下而設計的發布/訂閱型消息協議,為此,它需要一個消息中間件; MQTT是一個基于客戶端-服務器的消息發布/訂閱傳輸協議;MQT…

Ubuntu設置中午輸入法

本篇博客將指導您如何在Ubuntu系統中設置中文輸入法&#xff0c;讓您能夠輕松地進行中文輸入。 準備工作 在開始之前&#xff0c;請確保您的系統已經更新到最新版本。這可以通過以下命令來完成&#xff1a; sudo apt update && sudo apt upgrade這將幫助確保所有的軟…

Docker in Docker(DinD)原理與實戰

&#x1f407;明明跟你說過&#xff1a;個人主頁 &#x1f3c5;個人專欄&#xff1a;《Docker幻想曲&#xff1a;從零開始&#xff0c;征服容器宇宙》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目錄 一、引言 1、Docker簡介 2、Docker …

使用 AI Assistant for Observability 和組織的運行手冊增強 SRE 故障排除

作者&#xff1a;Almudena Sanz Oliv, Katrin Freihofner, Tom Grabowski 通過本指南&#xff0c;你的 SRE 團隊可以實現增強的警報修復和事件管理。 可觀測性 AI 助手可幫助用戶使用自然語言界面探索和分析可觀測性數據&#xff0c;利用自動函數調用來請求、分析和可視化數據…

Harmony 添加library依賴庫步驟

在Harmony添加library依賴庫步驟如下&#xff1a; 1、在library中定義名字 在library中的oh-package.json5中定義library對外的名字是什么&#xff1a;格式是 “name”:“ohos/名字” {"name": "ohos/library_name" //名字 }2、在項目目錄build-profi…

windows系統安裝Ubuntu子系統

安裝前先在 控制面板 中打開 程序與功能選項 &#xff0c;點擊 啟用或關閉Windows功能&#xff1a; 勾選 適用于 Linux的Windows子系統 和 虛擬機平臺 、 Hyper-v 。 重啟電腦后再 Microsoft Store Windows應用商店 中下載合適的Ubuntu版本。 運行Ubuntu程序&#xff0c;如出現…

【實戰】算法思路總結

面試過程中&#xff0c;總是被拷打&#xff0c;信心都要沒了。但是也慢慢摸索出一些思路&#xff0c;希望對大家有幫助。 &#xff08;需要多用一下ACM模式&#xff0c;力扣模式提供好了模板&#xff0c;自己在IDEA里面寫的話&#xff0c;還是會有些陌生&#xff09; 0、基本…

僵尸進程111

Linux 系統中的進程可能處于如下狀態中的一種&#xff1a; D 不可中斷的休眠 I 空閑 R 運行中 S 休眠 T 被調度信號終止 t 被調試器終止 Z 僵尸狀態 Interruptible Sleep&#xff0c;可中斷睡眠&#xff0c;在 ps 命令中顯示 S。處在這種睡眠狀態的進程是可以通過給它…