數據結構:二叉樹oj練習

在講今天的題目之前,我們還需要講一下二叉樹的以下特點:

對任意一顆二叉樹,如果度為0的節點個數是n0,度為2的節點個數是n2,則有n0=n2+1.

證明:二叉樹總的節點個數是n,那么有n=n0+n1+n2

? ? ? ? ? ?二叉樹的度為n-1=n1*1+n2*2

結合上面兩個式子,就有:n0=n2+1

完全二叉樹中,度為1的結點數只有0或1兩種可能

說明:因為完全二叉樹的結點是連續編號的,最后一層的結點要么是滿的,要么缺少右邊的若干結點,所以度為1的結點最多有1個。

選擇題

題目1

某二叉樹共有 399 個結點,其中有 199 個度為 2 的結點,則該二叉樹中的葉子結點數為( )
A 不存在這樣的二叉樹
B 200
C 198
D 199

解釋:葉子結點的個數等于度為2的節點的個數+1,所以結果是200

題目2

在具有 2n 個結點的完全二叉樹中,葉子結點個數為( )
A n
B n + 1
C n - 1
D n / 2

度為2的節點個數=度為0的節點個數-1,即n2=n0-1

由于是完全二叉樹,度為1的節點個數只有0或1兩種可能。

如果度為1的節點個數為1,那么1+n0+n0-1=2n,就能得到n0=n,即A可選

如果度為1的節點個數為0,那么n0+n0-1=2n,就會得到n0=(2n+1)/ 2,這是一個小數,所以不合理。

綜上,這道題的答案選A。

題目 3

一棵完全二叉樹的結點數為 531 個,那么這棵樹的高度為( )
A 11
B 10
C 8
D 12

我們知道,二叉樹第k層節點個數為2^(k-1),前k層節點個數為2^(k)-1

假設完全二叉樹的高度為h,那么完全二叉樹節點個數的范圍是: 2^(h-1)再到2^(h)-1.

這個范圍是咋來的呢?首先第一個范圍,既然一共有h層,那么根據公式,前h-1層就一共有2^(h-1)-1個節點,而第h層最少有1各節點,所以前h層應該至少是有2^(h-1)個節點。當這個樹為滿二叉樹時,節點個數達到最大,前h層節點個數一共是:2^(h)-1。

結合這個范圍,我們就可以求得答案是10,即選B

題目 4

一個具有 767 個結點的完全二叉樹,其葉子結點個數為( )
A 383
B 384
C 385
D 386

假設節點個數是n,那么結合結論,n=2*n0-1+n1,我們知道,完全二叉樹的節點個數要么是0,要么是1,帶入公式中我們可以得到,n0=384,此時n1=0

題目 5

二叉樹的先序遍歷和中序遍歷如下:前序遍歷:EFHIGJK;中序遍歷:HFIEJKG。則二叉樹后續遍歷序列:()

如果我們知道前序遍歷+中序遍歷? 或者? 中序遍歷+后序遍歷,就可以推導出二叉樹的結構。

題目 6

設一棵二叉樹的中序遍歷序列:badce,后序遍歷序列:bdeca,則二叉樹前序遍歷序列為____。 A.?adbce

B.?decab

C.?debac

D.?abcde

編程題

144. 二叉樹的前序遍歷 - 力扣(LeetCode)

這道題就是簡單的前序遍歷,我們之前在二叉樹的實現方法中已經寫過了,只需要將代碼稍加修改就可以咯:

 void preorder(struct TreeNode* root,int*res, int* returnSize){if(root==NULL){return ;}//先存根節點res[(*returnSize)++]=root->val;preorder(root->left,res,returnSize);preorder(root->right,res,returnSize);}
int* preorderTraversal(struct TreeNode* root, int* returnSize) 
{*returnSize=0;//樹中節點的數目在100內int*res=(int*)malloc(sizeof(int)*100);//前序遍歷preorder(root,res,returnSize);return res;
}

145. 二叉樹的后序遍歷 - 力扣(LeetCode)

void postorder(struct TreeNode* root, int* res, int* returnSize)
{if (root == NULL){return;}postorder(root->left, res, returnSize);postorder(root->right, res, returnSize);res[(*returnSize)++] = root->val;
}int* postorderTraversal(struct TreeNode* root, int* returnSize) {*returnSize = 0;//樹中節點的數目在100內int* res = (int*)malloc(sizeof(int) * 100);//后序遍歷postorder(root, res, returnSize);return res;
}

94. 二叉樹的中序遍歷 - 力扣(LeetCode)

 void inorder(struct TreeNode* root, int* res, int* returnSize)
{if (root == NULL){return;}inorder(root->left, res, returnSize);res[(*returnSize)++] = root->val;inorder(root->right, res, returnSize);}int* inorderTraversal(struct TreeNode* root, int* returnSize) {*returnSize = 0;//樹中節點的數目在100內int* res = (int*)malloc(sizeof(int) * 100);//中序遍歷inorder(root, res, returnSize);return res;}

965. 單值二叉樹 - 力扣(LeetCode)

這一道題的簡單思路也是遞歸,如果一棵樹是單值樹,那么他的子樹也是單值樹,那我們就可以把大問題拆分成若干個子問題了:

bool isUnivalTree(struct TreeNode* root) 
{if(root==NULL){return true;}if(root->left){if(root->left->val!=root->val){return false;}}if(root->right){if(root->right->val!=root->val){return false;}}return  isUnivalTree(root->left) &&  isUnivalTree(root->right);
}

我們可以模擬一下遞歸過程:

100. 相同的樹 - 力扣(LeetCode)

這道題的思路也是利用遞歸,如果兩顆樹的根節點相同,那就只需要再比較兩顆樹的左右子樹是否相同即可:

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{if(p==NULL&&q==NULL){return true;}if(p==NULL){return false;}if(q==NULL){return false;}if(p->val!=q->val){return false;}//表示根節點不為空且指向的值相等return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

我們可以模擬一下遞歸過程:

101. 對稱二叉樹 - 力扣(LeetCode)

如圖,判斷一個樹是否是對稱二叉樹,就是要比較根節點的左右子樹,我們可以把根節點的左右子樹看成兩棵獨立的二叉樹,問題就轉換為比較這兩棵樹是否對稱。

兩棵樹是否互為對稱樹,就是比較樹A上某個節點的左孩子節點的值與樹B上對應節點的右孩子節點的值以及樹A上某個節點的右孩子節點的值與樹B上對應節點的左孩子節點的值是否相等,如果相等的話,就繼續遞歸比較孩子節點的值。

 bool isSameTree(struct TreeNode*p,struct TreeNode*q){if(p==NULL&&q==NULL){return true;}if(p==NULL||q==NULL){return false;}if(p->val!=q->val){return false;}//兩棵樹根節點相同,再比較樹A的左孩子與樹B的右孩子是否相同,以及樹A的右孩子與樹B的左孩子是否相同return isSameTree(p->left,q->right)&&isSameTree(p->right,q->left);}
bool isSymmetric(struct TreeNode* root)
{return  isSameTree(root->left,root->right);
}

模擬遞歸過程:

572. 另一棵樹的子樹 - 力扣(LeetCode)

這一體的思路比較好想,我們可以先比較subroot是否與整棵樹相同,如果相同,那就可以直接返回了,如果不相同,說明subroot可能是樹的子樹,就需要遍歷整棵樹的節點,看是否存在以某一個節點為根的樹與subroot相同:

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{if(p==NULL&&q==NULL){return true;}if(p==NULL){return false;}if(q==NULL){return false;}if(p->val!=q->val){return false;}//表示根節點不為空且指向的值相等return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot) 
{if(subRoot==NULL){return true;}if(root==NULL){return false;}if(isSameTree(root,subRoot)){return true;}return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
}

二叉樹遍歷_牛客題霸_牛客網

我們之前說過,如果知道前序遍歷+中序遍歷? 或者? 中序遍歷+后序遍歷,就可以推導出二叉樹的結構。但是現在題目中只給了我們前序遍歷的結果,我們還能根據這個去構建二叉樹的結構嗎?

在這一題中是可以的,因為題中給我們的字符串是帶有'#'的,這表示空指針,前序遍歷的順序是按照根節點->左子樹->右子樹,當我們遇到‘#’的時候,就無法繼續往下遍歷,而是要回到原來子樹的根,這沒說這可能有點抽象,我們利用題目中給的測試樣例來手動還原二叉樹的結構:

利用遍歷結果構建二叉樹聽起來好像挺難的,但其實就是對二叉樹進行遍歷,我們在寫前序遍歷的代碼的時候,將訪問二叉樹的節點的操作寫成了打印二叉樹的節點值,在這里,無非就是讓我們在前序遍歷過程中將訪問二叉樹的節點的操作寫成了創建節點呀,具體思路還是沒有變呀,那我們就繼續寫一下代碼吧:

//二叉樹的構建與遍歷
#include<stdio.h>
#include<stdlib.h>
//二叉樹的節點的定義
typedef struct btnode {char data;struct btnode* left;struct btnode* right;
} btnode;btnode* buynode(char x) {btnode* newnode = (btnode*)malloc(sizeof(btnode));newnode->data = x;newnode->left = newnode->right = NULL;return newnode;
}//最后返回根節點
//pi表示指向的字符在字符數組中的下標,由于形參的改變需要影響實參,所以我們這里采用傳址調用
btnode* precreattree(char* ch, int* pi) {if (ch[*pi] == '#') {(*pi)++;return NULL;}//先創建根節點btnode* root = buynode(ch[(*pi)++]);//再創建左子樹root->left = precreattree(ch, pi);//創建右子樹root->right = precreattree(ch, pi);//返回根節點return root;
}
//中序遍歷樹的節點
void inorder(btnode* root) {if (root == NULL) {return;}//先遍歷左子樹inorder(root->left);//再訪問根節點printf("%c ", root->data);//再遍歷右子樹inorder(root->right);
}
int main() {char ch[100];//輸入字符串scanf("%s", ch);//輸入的字符串是二叉樹前序遍歷的結果,我們需要根據這個結果去創建二叉樹int i = 0;btnode* root = precreattree(ch, &i);//中序遍歷inorder(root);return 0;
}

今天的內容還是比較豐富的,這些算法題也是比較經典的,能看到這里的兄弟們我真的覺得你們很棒,大家在自己的電腦上也要好好把代碼敲一下,把圖畫一下,把思路整理一下哦!!

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

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

相關文章

RabbitMQ高級特性——TTL、死信隊列、延遲隊列、事務、消息分發

目錄 一、TTL 1.1設置消息的TTL 1.2設置隊列的TTL 1.3兩者之間的區別 二、死信隊列 2.1死信的概念 2.2死信產生的條件&#xff1a; 2.3死信隊列的實現 死信隊列的工作原理 2.4常??試題 三、延遲隊列 3.1概念 3.2應用場景 3.3RabbitMQ 實現延遲隊列的核心原理 1…

神經網絡設計中關于BN歸一化(Normalization)的討論

在神經網絡的結構中&#xff0c;我們常常可以看見歸一化&#xff08;Normalization&#xff09;如BN的出現&#xff0c;無論是模型的backbone或者是neck的設計都與它有著重大的關系。 因此引發了我對它的思考&#xff0c;接下來我將從 是什么&#xff08;知識領域&#xff0c;誕…

MacOS 安全機制與“文件已損壞”排查完整指南

1. 背景說明macOS 為了保護系統安全&#xff0c;內置了多個安全機制&#xff1a;機制作用是否影響第三方 AppSIP (System Integrity Protection)保護系統關鍵文件/目錄不被篡改高風險 App/驅動可能受限Gatekeeper限制未簽名/未認證 App 運行阻止“未知開發者” App文件隔離屬性…

package.json文件中的devDependencies和dependencies對象有什么區別?

前端項目的package.json文件中&#xff0c;dependencies和devDependencies對象都用于指定項目所依賴的軟件包&#xff0c;但它們在項目的開發和生產環境中的使用有所不同。1.dependencies&#xff1a;dependencies是指定項目在生產環境中運行所需要的依賴項。這些依賴項通常包括…

【最新版】CRMEB Pro版v3.4系統源碼全開源+PC端+uniapp前端+搭建教程

一.系統介紹 crmebPro版 v3.4正式發布&#xff0c;智能任務推送、動態標簽管理、商城AI生產力&#xff0c;煥然一新&#xff0c;不負期待&#xff01;頁面DIY設計功能全面升級&#xff0c;組件更豐富&#xff0c;樣式設計更全面&#xff1b;移動端商家管理&#xff0c;讓商城管…

AI 浪潮下 IT 從業者的職業展望:替代之惑與轉型之道

一、引言1.1 科技變革的浪潮&#xff1a;AI 崛起與 IT 行業震蕩在當今科技飛速發展的時代&#xff0c;人工智能&#xff08;AI&#xff09;無疑是最具影響力的變革力量之一。從實驗室的前沿研究到廣泛的商業應用&#xff0c;AI 以驚人的速度滲透到各個領域&#xff0c;徹底改變…

DSP音頻算法移植優化工程師實戰

以下以音頻FIR濾波器算法為例&#xff0c;完整演示從MATLAB原型 → Python驗證 → TI DSP C語言移植優化的全流程&#xff0c;包含關鍵代碼和優化技巧&#xff1a;關鍵優化技術解析&#xff1a; 內存訪問優化使用#pragma DATA_ALIGN確保64位對齊&#xff08;滿足LDDW指令要求&a…

Spark 運行流程核心組件(三)任務執行

一、啟動模式 1、standalone資源申請&#xff1a;Driver向Master申請Executor資源Executor啟動&#xff1a;Master調度Worker啟動Executor注冊通信&#xff1a;Executor直接向Driver注冊 2、YARNDriver向YARN ResourceManager(RM)申請AM容器RM分配NodeManager(NM)啟動AM&#x…

rabbitmq發送的延遲消息時間過長就立即消費了

RabbitMQ延遲消息在設置過長時間后被立即消費的問題&#xff0c;通常與以下原因有關&#xff1a; TTL限制問題 RabbitMQ對消息TTL(Time To Live)有32位整數限制(0-4294967295毫秒)&#xff0c;約49.7天。超過該值的延遲時間會導致消息立即被消費解決方案&#xff1a;確保設置的…

kafka的pull的依據

1. 每次 pull() 是否必須在提交上一批消息的 offset 之后&#xff1f;絕對不需要&#xff01; 提交 offset 和調用 poll() (拉取消息) 是兩個完全獨立的行為。消費者可以連續調用 poll() 多次&#xff0c;期間完全不提交任何 offset。 這是 Kafka 消費者的正常工作模式。提交 o…

學習嵌入式的第二十一天——數據結構——鏈表

單向鏈表特點&#xff1a;存儲的內存空間不連續 。為了彌補順序存儲存劣勢。優勢 插入&#xff0c;刪除 O(1) 動態存儲 &#xff0c;在程序運行期間決定大小。劣勢&#xff1a; 不能隨機訪問 O(N) 節點-> 數據域指針域 順序表(數組) 只有數據域鏈表的操作代碼&#xff1…

Rust Web 全棧開發(十三):發布

Rust Web 全棧開發&#xff08;十三&#xff09;&#xff1a;發布Rust Web 全棧開發&#xff08;十三&#xff09;&#xff1a;發布發布 teacher_service發布 svr測試 teacher_service 和 svr發布 wasm-client測試 wasm-clientRust Web 全棧開發&#xff08;十三&#xff09;&a…

Zephyr 中的 bt_le_per_adv_set_data 函數的介紹和應用方法

目錄 概述 1 函數接口介紹 1.1 函數原型 1.2 功能詳解 2 使用方法 2.1 創建流程 2.1.1 創建擴展廣播實例 2.1.2 設置周期性廣播數據 2.1.3 配置周期性廣播參數 2.1.4 啟動廣播 2.2 主流程函數 2.3 關鍵配置 (prj.conf) 3 高級用法 3.1 大數據分片傳輸 3.2 動態數…

Ansible 角色管理指南

Ansible 角色管理指南 實驗環境設置 以下命令用于準備實驗環境&#xff0c;創建一個工作目錄并配置基本的Ansible設置&#xff1a; # 創建web工作目錄并進入 [azurewhiskycontroller ~]$ mkdir web && cd web# 創建Ansible配置文件 [azurewhiskycontroller web]$ cat &…

【補充】數據庫中有關系統編碼和校驗規則的簡述

一、字符集和校驗規則&#xfeff;1.創建數據庫案例數據庫創建方法&#xff1a;使用CREATE DATABASE語句創建數據庫字符集指定方式&#xff1a;通過CHARACTER SETutf8指定數據庫編碼格式默認配置說明&#xff1a;未指定字符集時默認使用utf8和utf8_general_ci配置文件位置&…

計算機網絡 HTTP1.1、HTTP2、HTTP3 的核心對比及性能分析

以下是 HTTP/1.1、HTTP/2、HTTP/3 的核心對比及性能分析&#xff0c;重點關注 HTTP/3 的性能優勢&#xff1a;&#x1f4ca; HTTP 協議演進對比表特性HTTP/1.1 (1997)HTTP/2 (2015)HTTP/3 (2022)傳輸層協議TCPTCPQUIC (基于 UDP)連接建立TCP 三次握手 TLS 握手 (高延遲)同 HTT…

【計算機視覺與深度學習實戰】07基于Hough變換的答題卡識別技術:原理、實現與生物識別拓展(有完整代碼)

1. 引言 在人工智能和計算機視覺快速發展的今天,自動化圖像識別技術已經滲透到社會生活的各個角落。從工業質檢到醫學影像分析,從自動駕駛到教育評估,計算機視覺技術正在重塑我們與數字世界的交互方式。在這眾多應用中,答題卡識別技術作為教育信息化的重要組成部分,承載著…

《WASM驅動本地PDF與Excel預覽組件的深度實踐》

WASM為何能成為本地文件解析的核心載體,首先需要跳出“前端只能處理輕量任務”的固有認知,從“性能與兼容性平衡”的角度切入。PDF與Excel這類文件格式的解析,本質是對復雜二進制數據的解碼與重構——PDF包含嵌套的對象結構、字體渲染規則和矢量圖形描述,Excel則涉及單元格…

Oracle Free 實例重裝系統操作指南

之前申請了兩臺 x86 架構的 Oracle 機器&#xff0c;偶爾用來部署開源項目測試&#xff0c;有一臺在測試 SSH 相關功能時 “變磚”&#xff0c;網上看重裝系統發現很繁瑣就沒去打理&#xff0c;近期又想到這個機器&#xff0c;發現去年就有了官方重裝方法&#xff0c;簡單配置下…

Linux 基礎指令與權限管理

一、Linux 操作系統概述1.1 操作系統的核心價值操作系統的本質是 "使計算機更好用"。它作為用戶與硬件之間的中間層&#xff0c;負責內存管理、進程調度、文件系統管理和設備驅動管理等核心功能&#xff0c;讓用戶無需直接操作硬件即可完成復雜任務。在服務器領域&am…