二叉樹結點個數、葉子結點個數、樹的高度、第k層結點個數的計算(C語言)

目錄

前言

分治算法

模擬二叉樹代碼

結點個數計算

錯誤方法

不便利方法

基于分治思想的方法

葉子結點個數

樹的高度

第k層結點的個數


前言

????????在鏈式二叉樹的前序、中序、后續遍歷中我們模擬了一棵二叉樹,并實現了它的前、中、后序遍歷,現在我們來解決設計與二叉樹相關的計算問題。

分治算法

概念:是一種將問題劃分為更小的子問題,并通過解決子問題來解決原始問題的算法設計策略

分治算法的基本思想:

  1. 分解:將原始問題劃分成若干個規模較小且相互獨立的子問題。這里關鍵是要找到一個適當的方式將原始問題切割成更小規模的子問題,使得每個子問題都與原始問題具有相同或類似結構。

  2. 解決:遞歸地求解各個子問題。對于規模較小而直接可求解的情況,直接給出答案;對于規模較大而無法直接求解時,則繼續應用該算法來進一步劃分為更小的子問題并進行求解。

  3. 合并:將各個子結果合并成最終結果。在所有子任務都被獨立地處理和求得結果之后,需要把這些局部結果合并起來以獲得整體上正確且有效率的最終輸出。

可以應用分治算法來解決的問題的特點:

1、原問題可以分解為多個子問題

子問題與原問題相比,只是問題的規模有所降低,其結構和求解方法與原問題相同或相似

2、原問題在分解過程中,遞歸地求解子問題

由于遞歸都必須有一個終止條件,故當分解后的子問題規模足夠小時,應能夠直接求解

3、在求解并得到各個子問題的解后

應能夠采用某種方式、方法合并或構造出原問題的解

結論:不難發現,在分治策略中,由于子問題與原問題在結構和解法上的相似性,用分治方法解決的問題,大都采用了遞歸的形式🥰

模擬二叉樹代碼

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int BTDataType;typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}TreeNode;TreeNode* BuyTreeNode(int x)
{TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));assert(node);node->data = x;node->left = NULL;node->right = NULL;return node;
}TreeNode* CreatTree()
{TreeNode* node1 = BuyTreeNode(1);TreeNode* node2 = BuyTreeNode(2);TreeNode* node3 = BuyTreeNode(3);TreeNode* node4 = BuyTreeNode(4);TreeNode* node5 = BuyTreeNode(5);TreeNode* node6 = BuyTreeNode(6);node1->left = node2;node1->right = node4;node2->left = node3;//node2->right = NULL;//node3->left = NULL;//node3->right = NULL;node4->left = node5;node4->right = node6;//node5->left = NULL;//node5->right = NULL;//node6->left = NULL;//node6->right= NULL;return node1;
}int main()
{TreeNode* root = CreatTree();return 0;
}

結點個數計算

錯誤方法

int TreeSize(TreeNode* root)
{if (root == NULL)return;int size = 0;++size;TreeSize(root->left);TreeSize(root->right);return size;
}

????????這是因為每一次的遞歸都會開辟出一個幀棧,而每一塊的幀棧中都會有一個size且聲明周期僅只在自己的幀棧范圍內,在調用返回時所有的size并不會相加然后一起返回,簡單來說就是生命周期有限

不便利方法

//二叉樹代碼
.....static int size = 0;
int TreeSize(TreeNode* root)
{if (root == NULL)return;++size;TreeSize(root->left);TreeSize(root->right);return size;
}int main()
{TreeNode* root = CreatTree();printf("TreeSize:%d\n", TreeSize(root));printf("TreeSize:%d\n", TreeSize(root));printf("TreeSize:%d\n", TreeSize(root));printf("TreeSize:%d\n", TreeSize(root));return 0;
}

????????基于上次生命周期的問題,我們想到了用static來延長局部變量的生命周期,此時size的生命周期就是整個程序,但是當我們連續三次打印時發現三次的結果都不一樣,每次都比上次的結果增加了6?這也是使用static的副作用,因為被static修飾的變量(靜態變量)在整個程序中只會初始化一次,當第二次使用該靜態變量時,此次的結果與上次的結果疊加,從而出現意料之外的問題

我們需要在首次打印后,后續的每次打印前將該靜態變量人為置空后才能正常使用:

//二叉樹代碼
.....static int size = 0;
int TreeSize(TreeNode* root)
{if (root == NULL)return;++size;TreeSize(root->left);TreeSize(root->right);return size;
}int main()
{TreeNode* root = CreatTree();printf("TreeSize:%d\n", TreeSize(root));size = 0;printf("TreeSize:%d\n", TreeSize(root));size = 0;printf("TreeSize:%d\n", TreeSize(root));size = 0;printf("TreeSize:%d\n", TreeSize(root));return 0;
}


使用全局變量也是一樣的效果,只需要對代碼進行簡單的更改即可:

//二叉樹代碼
.....int size = 0;
void TreeSize(TreeNode* root)
{if (root == NULL)return;++size;TreeSize(root->left);TreeSize(root->right);
}int main()
{TreeNode* root = CreatTree();TreeSize(root);printf("TreeSize:%d\n", size);size = 0;TreeSize(root);printf("TreeSize:%d\n", size);size = 0;TreeSize(root);printf("TreeSize:%d\n", size);size = 0;TreeSize(root);printf("TreeSize:%d\n", size);return 0;
}

基于分治思想的方法

//二叉樹總結點個數
int TreeSize(TreeNode* root)
{return root == NULL ? 0 :TreeSize(root->left) +TreeSize(root->right) + 1;
}

解釋:主體邏輯就是判斷此時所處結點的值是否為空,若不為空則進行左遞歸,左遞歸結束后進行右遞歸,每一次左右遞歸完全結束后就會返回一個1,每次返回的結果可以疊加

葉子結點個數

//葉子結點個數
int TreeLeafSize(TreeNode* root)
{//空樹 返回0if (root == NULL)return 0;//非空樹,但是沒有左右子樹(葉子結點/僅有一個結點的樹)返回1if (root->left == NULL && root->right == NULL)return 1;//不是空 也不是葉子結點return TreeLeafSize(root->left) +TreeLeafSize(root->right);
}

解釋:主體邏輯與獲取結點總數時沒有區別,但是這里增加了一個用于判斷葉子結點的判斷條件,因為葉子結點的特殊性(沒有左右子樹),所以我們的返回1的操作操作必須要在確定該結點為葉子結點時才會返回

樹的高度

//樹的高度
int TreeHeight(TreeNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->left);int rightHeight = TreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

設計思想:

  1. 如果即當前子樹為空,則返回 0,表示該子樹沒有任何結點,因此高度為 0
  2. 如果傳入的?root?指針不為空,則執行以下操作:
    a)調用遞歸函數?TreeHeight(root->left)?來計算左子樹中結點到達最底層所需經過的邊數,并將結果賦值給變量?leftHeight
    b)調用遞歸函數?TreeHeight(root->right)?來計算右子樹中結點到達最底層所需經過邊數,并將結果賦值給變量?rightHeight
    c)返回左右子樹兩者中較大者加上當前節點本身所代表邊數(加1)作為該子問題下一級別解答(理解這里十分重要)

解釋: 1、某個結點的左子樹遞歸的三目運算符的運算結果都會在最后賦值給leftHeight,右子樹遞歸的三目運算符的運算結果都會在最后賦值給rightHeight

2、每次調用?TreeHeight?函數時都會進行三目運算符的比較,如果是葉子結點,由于沒有左右子樹為空所以兩次遞歸返回的值均為0,即leftHeight和rightHeight的值均為0(因為0>0為假,故:rightHeight+1,此時rightHeight+1里的+1是為了加上3結點本身的高度,不可能因為左右子樹均為空就沒有高度了,當前結點也算一個高度)比較后會返回1它被賦值給leftHeight,因為它是2結點的左子樹遞歸得到的,同時它也告訴了2結點你的左子樹高度只有1,然后2結點又會遞歸調用它的右子樹但是由于右子樹為NULL所以會返回0,所以此時leftHeight和rightHeight的值分別為1和0(因為1>0為真所以leftHeight+1,表明2結點的左子樹大于右子樹,左子樹的高度可以代表2結點的高度)比較后會返回2它被賦值給leftHeight,因為它是1結點的左子樹遞歸得到的,同時它也告訴了1結點你的左子樹高度為2

3、然后1結點會遞歸它的右子樹,剩余步驟與上面描述的大致相似,最后右遞歸會告訴1結點你的右子樹高度為2(因為2>2為假所rightHeight+1,此時rightHeight+1里的+1是為了加上1結點本身的高度,不可能左右子樹高度相等就沒有高度了,當前結點也算一個高度,所以當前結點的左右子樹結點高度相等,將當前左右結點子樹的高度+1就是整個樹的高度)

第k層結點的個數

//第k層結點的個數,k==2
int TreeLevelK(TreeNode* root,int k)
{assert(k > 0);if (root == NULL)return 0;if (k == 1)return 1;return TreeLevelK(root->left, k - 1) +TreeLevelK(root->right,k-1);
}

?設計思想:

  1. 樹為空,返回0
  2. 樹不為空且是第一層結點個數,返回1
  3. 樹不為空且是第n(n>1)層結點的個數,返回(左子樹的k-1層 + 右子樹的k-1層)

k-1而不是k,k相當于判斷條件count,當count==1的時候就相當于找到了我們要找的那一層,如果為k,那么遞歸的返回條件就不存在

解釋:

1、查找第3層結點個數,即k == 3?

2、樹不為空,并且k != 1,所以遞歸結點1的左子樹,結點2不為空,此時k-1?= 2?!= 1,所以可以繼續遞歸結點2的左子樹,結點3不為空,此時k-1 = 1?== 1,所以返回1,即遞歸結點2左子樹的返回值為1,然后遞歸結點2的右子樹,右子樹為空返回0,最后0+1=1,即遞歸結點1左子樹的返回值為1,這說明結點1左子樹第3層的結點個數為1

3、然后遞歸結點1的右子樹,結點4不為空,此時k-1 = 2 != 1,所以可以繼續遞歸結點4的左子樹,結點5不為空,此時k - 1 =1 == 1,所以返回1,即遞歸結點4的左子樹的返回值為1,然后遞歸結點4的右子樹,結點6不為空,此時k - 1 =1 == 1(這是因為此時處于結點4的TreeLevelK函數中,此時的k為2),所以返回1,即遞歸結點4的右子樹的返回值為1,最后1+1=2,即遞歸結點1右子樹的返回值為2,這說明結點1右子樹第3層的結點個數為2

4、最后結點1的左右子樹均遞歸完璧,1+2=3,即該二叉樹第3層的結點個數為3

?~over~

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

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

相關文章

UE4 .ini文件使用

在需要給配置文件的類中加上config標簽&#xff0c;當然變量也要加 在項目的Config下&#xff0c;新建一個Default類的UCLASS中config等于的名字&#xff0c;這里結合上面截圖就是DefaultTest 在下面寫入 [/Script/項目名/類名] 然后寫變量以及對應的值即可

【Angular 開發】Angular 信號的應用狀態管理

自我介紹 做一個簡單介紹&#xff0c;年近48 &#xff0c;有20多年IT工作經歷&#xff0c;目前在一家500強做企業架構&#xff0e;因為工作需要&#xff0c;另外也因為興趣涉獵比較廣&#xff0c;為了自己學習建立了三個博客&#xff0c;分別是【全球IT瞭望】&#xff0c;【架構…

智能機器人在新材料方面遇到的挑戰

智能機器人在新材料方面面臨的挑戰包括但不限于以下幾點&#xff1a; 新材料的研發&#xff1a;機器人需要使用新材料來提高其性能和功能。然而&#xff0c;新材料的研發需要大量的時間和資金&#xff0c;同時還需要具備高超的技術和專業知識. 材料的可靠性&#xff1a;機器人…

GO面試題系列

1.GO有哪些關鍵字 2.GO有哪些數據類型 3.Go方法與函數的區別 在Go語言中&#xff0c;方法和函數是兩個不同的概念&#xff0c;盡管它們在某些方面有相似之處。下面是它們的主要區別&#xff1a; 定義位置&#xff1a; 函數&#xff1a; 函數是獨立聲明的&#xff0c;它們不…

python數據分析總結(pandas)

目錄 前言 df導入數據 df基本增刪改查 數據清洗 ?編輯 索引操作 數據統計 行列操作 ?編輯 df->types 數據格式化 ?編輯 日期數據處理 前言 此篇文章為個人python數據分析學習總結&#xff0c;總結內容大都為表格和結構圖方式&#xff0c;僅供參考。 df導入數…

Vue3使用vue-baidu-map-3x百度地圖

安裝vue-baidu-map-3x&#xff1a; // vue3 $ npm install vue-baidu-map-3x --save// vue2 $ npm install vue2-baidu-map --save 全局注冊/局部注冊&#xff1a; import { createApp } from vue import App from ./App.vue import BaiduMap from vue-baidu-map-3xconst app …

綜述 2017-Genome Biology:Alignment-free sequence comparison

Zielezinski, Andrzej, et al. "Alignment-free sequence comparison: benefits, applications, and tools." Genome biology 18 (2017): 1-17. https://genomebiology.biomedcentral.com/articles/10.1186/s13059-017-1319-7 被引次數&#xff1a;476應用問題&…

curl 18 HTTP/2 stream

cd /Users/haijunyan/Desktop/CustomKit/KeepThreadAlive/KeepThreadAlive //Podfile所在文件夾 git config --global https.postBuffer 10485760000 git config --global http.postBuffer 10485760000 pod install https://blog.csdn.net/weixin_41872403/article/details/86…

linux命令積累

1.查找指定目錄下第二層目錄&#xff0c;一年前的文件 find $dir -maxdepth 1 -type d -mtime 365 2./data/att/dir1軟連接到/data1/att/dir1 硬連接和軟連接的區別 硬連接 ln file1 file2 1.硬連接不能對目錄進行鏈接。 2.硬連接修改一個文件&#xff08;不論修改哪方文件&…

top K問題(借你五分鐘)

目錄 前言 top K問題 模擬數據 建堆 驗證&#xff08;簡單了解即可&#xff09; 最終代碼 調試部分 前言 在大小堆的實現&#xff08;C語言&#xff09;中我們討論了堆的實際意義&#xff0c;在看了就會的堆排序&#xff08;C語言&#xff09;中我們完成了堆排序&#…

銀河麒麟本地軟件源配置方法

軟件源介紹 軟件源可以理解為軟件倉庫&#xff0c;當需要安裝軟件時則會根據源配置去相應的軟件源下載軟件包&#xff0c;此方法的優點是可以自動解決軟件包的依賴關系。常見的軟件源有光盤源、硬盤源、FTP源、HTTP源&#xff0c;本文檔主要介紹本地軟件源的配置方法&#xff…

功能強大的屏幕錄制和剪輯工具Camtasia Studio 2024 中文版

Camtasia Studio 2024 是一款功能強大的屏幕錄像工具&#xff0c;集視頻錄制、剪輯、編輯和播放于一體的多功能屏幕錄制軟件&#xff0c;Camtasia Studio 2024操作簡單&#xff0c;它能夠輕松為您將屏幕上的所有聲音、影音、鼠標移動的軌跡和麥克風聲音全部錄制下來&#xff0c…

分布式架構原理與實踐讀書筆記

分布式架構原理與實踐讀書筆記 IT 軟件架構的更迭&#xff1a;從單體架構&#xff0c;到集群架構&#xff0c;到現在的分布式和微服務架構。 分布式架構具有分布性、自治性、并行性、全局性等特點。 為了應對請求的高并發和業務的復雜性&#xff0c;需要對應用服務進行合理拆…

springboot(ssm暢游游戲銷售平臺 游戲電商系統Java系統

springboot(ssm暢游游戲銷售平臺 游戲電商系統Java系統 開發語言&#xff1a;Java 框架&#xff1a;ssm/springboot vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服務器&#xff1a;tomcat 數據庫&#xff1a;mysql 5.7&#xff08;或8.0&#xff09; 數…

使用Jmeter做性能測試的注意點

一、性能測試注意點 1. 用jmeter測試時使用BeanShell腳本獲取隨機參數值&#xff0c;會導致請求時間過長&#xff0c;TPS過低。應改為使用csv讀取參數值&#xff0c;記錄的TPS會更加準確。 注&#xff1a;進行性能測試時&#xff0c;應注意會影響請求時間的操作&#xff0c;盡量…

[JVM 基礎 - Java 類加載機制]

這篇文章將帶你深入理解Java 類加載機制。 JVM 基礎 - Java 類加載機制 類的生命周期 類的加載: 查找并加載類的二進制數據連接 驗證: 確保被加載的類的正確性準備: 為類的靜態變量分配內存&#xff0c;并將其初始化為默認值解析: 把類中的符號引用轉換為直接引用初始化使用卸…

1-4、JDK目錄結構

語雀原文鏈接 文章目錄 1、目錄結構2、JDK中rt.jar、tools.jar和dt.jar作用3、bin目錄部分說明&#xff08;基本工具&#xff09; 1、目錄結構 bin目錄&#xff1a;包含一些用于開發Java程序的工具&#xff0c;例如&#xff1a;編譯工具(javac.exe)、運行工具 (java.exe) 、打…

菜鳥學習日記(python)——循環語句

python中的循環語句包括for循環語句和while循環語句&#xff0c;但是python中是沒有do...while循環語句的。 while循環語句 while循環語句的一般格式為; while condition:loop body condition是循環判斷條件&#xff0c;loop body是循環體。 當循環條件成立時&#xff0c;…

基于ssm的彩妝小樣售賣商城的設計與實現論文

摘 要 隨著科學技術的飛速發展&#xff0c;各行各業都在努力與現代先進技術接軌&#xff0c;通過科技手段提高自身的優勢&#xff1b;對于彩妝小樣售賣商城當然也不能排除在外&#xff0c;隨著網絡技術的不斷成熟&#xff0c;帶動了彩妝小樣售賣商城&#xff0c;它徹底改變了過…

RUST博客帖子編輯示例

狀態模式&#xff08;state pattern&#xff09;是一種面向對象的設計&#xff0c;它的關鍵點在于&#xff1a;一個值擁有的內部狀態由數個狀態對象&#xff08;state object&#xff09;表的而成&#xff0c;而值的行為則隨著內部狀態的改變而改變。 下面的示例用來實現發布博…