C數據結構:二叉樹

目錄

二叉樹的數據結構

前序遍歷

中序遍歷

后序遍歷

二叉樹的創建

二叉樹的銷毀

二叉樹的節點個數

二叉樹葉子節點個數

二叉樹第K層節點個數

二叉樹的查找

層序遍歷

判斷二叉樹是否為完全二叉樹

完整代碼


二叉樹的數據結構

typedef char BTDataType;
typedef struct BinaryTreeNode
{BTDataType _data;struct BinaryTreeNode* _left;struct BinaryTreeNode* _right;
}BTNode;

這里二叉樹是使用了鏈式存儲

data負責存儲數據,left指針負責存儲左孩子節點,right負責存儲右孩子節點

前序遍歷

void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->_data);BinaryTreePrevOrder(root->_left);BinaryTreePrevOrder(root->_right);
}

前序遍歷的規則是先訪問根節點,然后訪問左子樹,最后訪問右子樹

根據規則我們在遍歷前先打印當前根節點的值(若是遇到NULL則打印N代替空節點),然后再往下遞歸左子樹、右子樹即可?

中序遍歷

void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreeInOrder(root->_left);printf("%d ", root->_data);BinaryTreeInOrder(root->_right);
}

中序遍歷的規則是先訪問左子樹,然后訪問根節點,最后訪問右子樹

?所以這里先遞歸到左子樹(最左邊),然后打印當前節點的值,然后再訪問右子樹(右子樹的左子樹),打印值,循環往復

后序遍歷

void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreePostOrder(root->_left);BinaryTreePostOrder(root->_right);printf("%d ", root->_data);
}

?后序遍歷的規則是先訪問左子樹,然后訪問右子樹,最后訪問根節點

跟前面的前序遍歷和中序遍歷基本一致,都只是順序不一樣

二叉樹的創建

BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{if (*pi >= n){(*pi)++;return NULL;}BTNode* root = (BTNode*)malloc(sizeof(BTNode));root->_data = a[(*pi)++];root->_left = BinaryTreeCreate(a, n, pi);root->_right = BinaryTreeCreate(a, n, pi);return root;
}

使用該函數需要傳一個數組,并根據數組里的元素當作前序遍歷構建起二叉樹

并需要傳一個數組的大小,和一個標記pi,在外面傳參的時候從數組開始的下標開始傳

這里為了讓函數在遞歸過程中能夠始終有一個變量能夠指向數組的某個元素來迭代(遍歷數組),不受遞歸變化而變化,所以需要一個指針變量,在下一次遞歸的時候只需要傳地址,就能獲得*pi的值,而不是通過傳參

?在每次遞歸過程中需要先創建一個根節點root并開辟一塊空間,并為該節點data賦值為當前走到的*pi的位置

接下來就要開始遞歸先從根的左子樹開始到右子樹,并分別賦值給root的左和右

這里的遞歸會一直遞歸,我們需要讓他遞歸到空為止,所以需要設定if語句限定遞歸次數

if語句限定了當*pi超過了數組的長度或等于數組長度時,則不能繼續遞歸獲取空間

所以這里是從最后一個節點開始往回返,先return最后一個節點給上一個遞歸的左或者右節點,依次往復即可

二叉樹的銷毀

void BinaryTreeDestory(BTNode* root)
{if (root == NULL)return;BinaryTreeDestory(root);BinaryTreeDestory(root);free(root);
}

銷毀我們需要用后序遍歷,因為前序和中序會先將根節點給銷毀了,這樣就不好往下找了,故此要使用后序遍歷來一個個free掉每一個節點

二叉樹的節點個數

int BinaryTreeSize(BTNode* root)
{if (root == NULL)return 0;return BinaryTreeSize(root->_left)+ BinaryTreeSize(root->_right) + 1;
}

控制好遞歸的次數?

只需要在遍歷每一層節點時+1,即可

二叉樹葉子節點個數

int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL)return 0;if (root->_left == NULL && root->_right == NULL)return 1;return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}

還是先控制遞歸的層數,當root等于空時往回返

若root的左和右都為空,則說明當前節點為葉子節點,返回1

最后返回左子樹葉子節點和右子樹葉子節點個數相加即可

二叉樹第K層節點個數

int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL)return 0;if (k == 1)return 1;return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}

?和前面的遞歸思路都差不多

這里返回1的條件是k == 1,因為只需要遞歸k-1次即可,當遞歸次數達到說明也到了第k層,則返回1即可

最后返回給外層的時候把左右子樹的結果返回起來相加即可

二叉樹的查找

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->_data == x)return root;BTNode* ret1 = BinaryTreeFind(root->_left, x);if (ret1)return ret1;BTNode* ret2 = BinaryTreeFind(root->_right, x);if (ret2)return ret2;return NULL;
}

?第一個if語句控制層數

第二個判斷查找結果,若找到則返回根節點root

找到的結果返回給下面的ret1指針或者ret2指針,通過這兩個指針返回給最外層

層序遍歷

void BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);printf("%d ", front->_data);if (front->_left)QueuePush(&q, front->_left);if (front->_right)QueuePush(&q, front->_right);}QueueDestroy(&q);
}

層序遍歷是一層一層從左到右遍歷,那么我們就需要借助隊列來完成(先進先出)

例如該圖層序遍歷后就是1,2,4,3,5,6

首先我們需要將根節點入隊列

然后進入循環,我們循環的條件是隊列為空則停止循環

所以我們還需要不斷入棧

這里第一層已經入棧了,這時候就可以拿到這個節點,我把它叫做front

后面我們就可以打印這個front節點的data

然后就可以刪除掉這個節點了,但是刪除的同時需要把它的左右孩子帶進來,但是左右孩子有可能為空,所以先判斷,若不為空則push入隊列,這樣第二層就入隊列了

接下來繼續pop2和4(pop的同時打印),然后push2和4的左右孩子

?最后不要忘記將隊列銷毀,防止造成內存泄漏

判斷二叉樹是否為完全二叉樹

int BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL)break;QueuePush(&q, front->_left);QueuePush(&q, front->_right);}while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL){QueueDestroy(&q);return 0;}}QueueDestroy(&q);return 1;
}

和前面層序遍歷差不多,我們也需要借用一個隊列來完成該函數

先入第一個根節點進隊列,然后循環的將二叉樹的全部節點按照層序遍歷都push進去?

push到最后隊列的頭節點front總會碰到空節點,所以我們碰到空節點就break出去循環,這是第一個循環的主要作用

例如該二叉樹,我們push2的時候就會把左節點3和右節點NULL給入隊列,那么我們的front肯定會接收到NULL從而跳出循環

如上并不是一個完全二叉樹,所以我們判斷它不是完全二叉樹的理由就是根據層序遍歷它的空節點后面還有一個節點6

所以我們第二個循環的任務就是pop掉隊列剩下的所有值,若pop的時候發現里面還有非空節點,則不為完全二叉樹,return 0

例如我們在把NULL節點接收給front時,我們肯定會經過4這個節點,然后4這個節點就會把它的左NULL和右6兩個節點入隊列

所以我們最后在把隊列全部出掉的時候肯定會碰到這個6,既然碰到了這個6就說明這不是一個完全二叉樹

完整代碼

#include"BinaryTree.h"
#include"Queue.h"BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{if (*pi >= n){(*pi)++;return NULL;}BTNode* root = (BTNode*)malloc(sizeof(BTNode));root->_data = a[(*pi)++];root->_left = BinaryTreeCreate(a, n, pi);root->_right = BinaryTreeCreate(a, n, pi);return root;
}void BinaryTreeDestory(BTNode* root)
{if (root == NULL)return;BinaryTreeDestory(root);BinaryTreeDestory(root);free(root);
}int BinaryTreeSize(BTNode* root)
{if (root == NULL)return 0;return BinaryTreeSize(root->_left)+ BinaryTreeSize(root->_right) + 1;
}int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL)return 0;if (root->_left == NULL && root->_right == NULL)return 1;return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL)return 0;if (k == 1)return 1;return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->_data == x)return root;BTNode* ret1 = BinaryTreeFind(root->_left, x);if (ret1)return ret1;BTNode* ret2 = BinaryTreeFind(root->_right, x);if (ret2)return ret2;return NULL;
}void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->_data);BinaryTreePrevOrder(root->_left);BinaryTreePrevOrder(root->_right);
}void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreeInOrder(root->_left);printf("%d ", root->_data);BinaryTreeInOrder(root->_right);
}void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreePostOrder(root->_left);BinaryTreePostOrder(root->_right);printf("%d ", root->_data);
}void BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);printf("%d ", front->_data);if (front->_left)QueuePush(&q, front->_left);if (front->_right)QueuePush(&q, front->_right);}QueueDestroy(&q);
}int BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL)break;QueuePush(&q, front->_left);QueuePush(&q, front->_right);}while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL){QueueDestroy(&q);return 0;}}QueueDestroy(&q);return 1;
}

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

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

相關文章

使用numpy手寫一個神經網絡

本文主要包含以下內容: 推導神經網絡的誤差反向傳播過程使用numpy編寫簡單的神經網絡,并使用iris數據集和california_housing數據集分別進行分類和回歸任務,最終將訓練過程可視化。 1. BP算法的推導過程 1.1 導入 前向傳播和反向傳播的總體…

Three.js——相機

在Three.js中,相機(Camera)是用于定義視圖和渲染場景的一個關鍵組件。相機決定了你從哪個角度和位置觀察場景中的物體,以及如何呈現這些物體。Three.js 提供了幾種不同類型的相機,每種相機都有其特定的用途和特性。以下…

Unity OutLine 模型外描邊效果

效果展示: 下載鏈接

【Rust日報】ratatui版本更新

[new ver] ratatui v0.26.3 一個構建終端用戶界面的庫。新版本包括: 修復Unicode 截斷 bug對顏色更好地序列化更快的渲染棄用assert_buffer_eq宏暴露錯誤類型常量函數和類型 官網: https://ratatui.rs/ 鏈接: https://ratatui.rs/highlights/v0263/ [new lib] ansi2…

618電商選品爆款攻略,誰掌握誰爆單

618電商節是各大電商平臺和品牌商家的重要促銷節點,選品和營銷策略對于銷售成績至關重要。以下是一些選品和營銷攻略的要點: 一、市場分析與目標定位 1、分析當前經營類目市場的流行趨勢、熱門品類以及消費者需求的變化。 目前市場上商品繁多&#xf…

Java 命令執行某一個特定類

在Java中,要執行一個特定的類(通常是包含main方法的類),你需要使用java命令,并指定類的完全限定名(包括包名)。通常,這還需要你設置正確的類路徑(classpath)&…

Apache Cassandra和Java:介紹如何在Java中連接和使用Apache Cassandra這款數據庫

1. Apache Cassandra簡介 Apache Cassandra是一個開源的分布式NoSQL數據庫系統,最初由Facebook開發,用來處理大量的結構化數據 across many commodity servers. Cassandra在高可用性和無單點故障的同時,提供了出色的數據分布策略。 Apache Cassandra的主要特點: 分布式…

超詳細避坑指南!OrangpiAIPro轉換部署模型全流程!

目錄 OrangepiPro初體驗 前述: 一、硬件準備 二、安裝CANN工具鏈(虛擬機) 三、配置模型轉換環境(虛擬機) 1.安裝miniconda 。 2.創建環境。 3.安裝依賴包 四、轉換模型 1. 查看設備號(開發板&…

一步一腳印:輕松掌握服務器硬件的奧秘

在這個信息化飛速發展的時代,無論是企業還是個人,對數據處理和存儲的需求日益增長。服務器,作為互聯網的基石,其重要性不言而喻。但對于大多數人來說,服務器的內部世界似乎既復雜又遙遠。不過,不用擔心&…

在Anaconda中修改查找和安裝軟件包的存儲庫的來源channels

以下是一些關鍵的步驟和命令&#xff0c;用于修改Anaconda的channels&#xff1a; 查看當前channels 使用命令 conda config --show channels 可以查看當前配置的channels。 添加新的channel 使用命令 conda config --add channels <channel_url> 來添加一個新的channel…

TIM定時器PWM輸出

tim.c #include "tim.h" #include "stm32mp1xx_tim.h" #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h"//tim4初始化(蜂鳴器) void tim4_init(){//1.使能GPIOB的外設時鐘RCC->MP_AHB4ENSETR | (0x1<<1);//使能TI…

辦公必備!一鍵拆分文件,效率翻倍的秘密

需求介紹 1、我有一張數據表“測試數據.xlsx” 2、我要根據A1“COUNTY_CODE”分類拆分成幾張數據表&#xff08;這里從9657到9658共12類&#xff0c;就是拆分成12張數據表&#xff09; 3、根據12個分類&#xff0c;發送數據郵件給對應的收件人 4、收件人及抄送人、共同抄送人…

Appium系列(2)元素定位工具appium-inspector

背景 如實現移動端自動化&#xff0c;依賴任何工具時&#xff0c;都需要針對于頁面中的元素進行識別&#xff0c;通過識別到指定的元素&#xff0c;對元素進行事件操作。 識別元素的工具為appium官網提供的appium-inspector。 appium-inspector下載地址 我這里是mac電腦需要下…

基于Cloudflare/CloudDNS/GitHub使用免費域名部署NewBing的AI服務

部署前準備&#xff1a; Cloudflare 賬號 https://dash.cloudflare.com/login CloudDNS 賬號 https://www.cloudns.net/ GitHub 賬號 https://github.com/Harry-zklcdc/go-proxy-bingai Cloudflare 部署 Worker CloudDNS 獲取免費二級域名 GitHub New Bing Ai 項目 https://git…

揭秘黃金分割數列:斐波那契數列的奇妙之旅

新書上架~&#x1f447;全國包郵奧~ python實用小工具開發教程http://pythontoolsteach.com/3 歡迎關注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目錄 一、黃金分割數列——斐波那契數列的簡介 二、實現斐波那契數列的函數 三、斐波那契數列在…

前端開發之xlsx的使用和實例,并導出多個sheet

前端開發之xlsx的使用和實例 前言效果圖1、安裝2、在頁面中引用3、封裝工具類&#xff08;excel.js&#xff09;4、在vue中使用 前言 在實現業務功能中導出是必不可少的功能&#xff0c;接下來為大家演示在導出xlsx的時候的操作 效果圖 1、安裝 npm install xlsx -S npm inst…

Discuz!X3.4論壇網站公安備案號怎樣放到網站底部?

Discuz&#xff01;網站的工信部備案號都知道在后臺——全局——站點信息——網站備案信息代碼填寫&#xff0c;那公安備案號要添加在哪里呢&#xff1f;并沒有看到公安備案號填寫欄&#xff0c;今天馳網飛飛和你分享 1&#xff09;工信部備案號和公安備案號統一填寫到網站備案…

數據預處理

數據預處理 引入一.配置java , hadoop , maven的window本機環境變量1.配置2.測試是否配置成功 二.創建一個Maven項目三.導入hadoop依賴四.數據清洗1.數據清洗的java代碼2.查看數據清洗后的輸出結果 引入 做數據預處理 需要具備的條件 : java,hadoop,maven環境以及idea軟件 一…

斯坦福2024人工智能指數報告 2

《人工智能指數報告》由斯坦福大學、AI指數指導委員會及業內眾多大佬Raymond Perrault、Erik Brynjolfsson 、James Manyika、Jack Clark等人員和組織合著&#xff0c;旨在追蹤、整理、提煉并可視化與人工智能&#xff08;AI&#xff09;相關各類數據&#xff0c;該報告已被大多…

靜態網站部署指南

一、資源準備 1.1 服務器 # 當前的服務器,公網ip:127.0.0.1 # 通過ssh協議連接訪問服務器1.2 域名 目前個人擁有的域名有: 域名所有者有效期wujinet.top個人2029-04-151.3 網站代碼 純靜態網站,網站源碼由筆者自行開發并提供發布部署的技術支持。 二、技術棧 2.0 源碼…