【數據結構篇】鏈式結構二叉樹

目錄:

一 二叉鏈的概念與結構:

1.1 概念:

1.2 結構:

二 二叉鏈的實現:

2.1 二叉樹的構建:

2.2 二叉樹的遍歷:

2.2.1?前序遍歷:

2.2.2 中序遍歷:

2.2.3 后序遍歷:

2.3 二叉樹結點個數:

2.4 二叉樹葉子結點個數:

2.5?二叉樹第k層結點個數:

2.6?二叉樹深度/高度:

2.7?二叉樹查找值為x的結點:

2.8 二叉樹的銷毀:

2.9?二叉樹的層序遍歷:

三?判斷是否為完全二叉樹:

四 二叉樹性質選擇題:


一 二叉鏈的概念與結構:

1.1 概念:

????????用鏈表來表示一棵二叉樹,即用鏈來指示元素的邏輯關系。通常的方法是鏈表中每個結點由三個域組成,數據域和左右指針域,左右指針分別用來給出該結點左孩子和右孩子所在的鏈結點的存儲地址。

1.2 結構:

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;

回顧二叉樹:

二叉樹分為空樹和非空二叉樹,非空二叉樹由根結點、根結點的左子樹、根結點的右子樹組成的。根結點的左子樹和右子樹分別又是由子樹結點、子樹結點的左子樹、子樹結點的右子樹組成的,因此 二叉樹定義是遞歸式的,后序鏈式二叉樹的操作中基本都是按照該概念實現的。

二 二叉鏈的實現:

Tree.h

定義二叉鏈結構

將存儲數據類型重命名

所寫的函數的聲明

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int BTdatatype;typedef struct BinaryTreenode
{int data;struct BinaryTreenode* left;struct BinaryTreenode* right;
}BTnode;//前序遍歷
void Preorder(BTnode* root);//中序遍歷
void Inorder(BTnode* root);//后序遍歷
void Postorder(BTnode* root);// ?叉樹結點個數
int BinaryTreeSize(BTnode* root);// ?叉樹葉?結點個數
int BinaryTreeLeafSize(BTnode* root);// ?叉樹第k層結點個數
int BinaryTreeLevelKSize(BTnode* root, int k);//?叉樹的深度/?度
int BinaryTreeDepth(BTnode* root);// ?叉樹查找值為x的結點
BTnode* BinaryTreeFind(BTnode* root, BTdatatype x);// ?叉樹銷毀
void BinaryTreeDestory(BTnode** root);//層序遍歷
//借助數據結構---隊列
void LevelOrder(BTnode* root);

Tree.c

函數的實現方法

2.1 二叉樹的構建:

二叉樹的構建是遞歸實現的

二叉樹的創建方式比較復雜,為了更好的步入到二叉樹內容中,我們先手動創建一棵鏈式二叉樹

方法:

BTNode* BuyBTNode(int val)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->val = val;newnode->left = NULL;newnode->right = NULL;return newnode;
}BTNode* CreateTree()
{BTNode* n1 = BuyBTNode(1);BTNode* n2 = BuyBTNode(2);BTNode* n3 = BuyBTNode(3);BTNode* n4 = BuyBTNode(4);BTNode* n5 = BuyBTNode(5);BTNode* n6 = BuyBTNode(6);BTNode* n7 = BuyBTNode(7);n1->left = n2;n1->right = n4;n2->left = n3; n4->left = n5; n4->right = n6; n5->left = n7; return n1;
}

2.2 二叉樹的遍歷:

按照規則,二叉樹的遍歷有:前序/中序/后序的遞歸結構遍歷
1)前序遍歷(先序遍歷):訪問根結點的操作發?在遍歷其左右?樹之前
訪問順序為:根結點、左?樹、右?樹
2)中序遍歷:訪問根結點的操作發?在遍歷其左右?樹之中(間)
訪問順序為:左?樹、根結點、右?樹
3)后序遍歷:訪問根結點的操作發?在遍歷其左右?樹之后
訪問順序為:左?樹、右?樹、根結點

2.2.1?前序遍歷:

核心思想就是遞歸:先遞推,再回歸

?? 傳入根節點,依據前序遍歷根左右的規則,先打印根節點,然后再將左結點當做一課新樹的根節點進行相同操作,右子樹同理為遞推,當root==NULL時,直接返回為回歸。

圖解:

代碼:

void Preorder(BTnode* root)
{if (root == NULL){return;}printf("%d ", root->data);Preorder(root->left);Preorder(root->right);
}

2.2.2 中序遍歷:

原理同前序遍歷:(訪問順序為:左?樹、根結點、右?樹

//中序遍歷
void Inorder(BTnode* root)
{if (root == NULL){return;}Inorder(root->left);printf("%d ", root->data);Inorder(root->right);}

2.2.3 后序遍歷:

原理同前序遍歷:(訪問順序為:左?樹、右?樹、根結點

//后序遍歷
void Postorder(BTnode* root)
{if (root == NULL){return;}Postorder(root->left);Postorder(root->right);printf("%d ", root->data);}

2.3 二叉樹結點個數:

求二叉樹結點個數,即當下結點+左子樹+右子樹

當結點某一子樹為空時,返回0即可,遞推結束

// ?叉樹結點個數
int BinaryTreeSize(BTnode* root)
{if (root == NULL){return 0;}return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

2.4 二叉樹葉子結點個數:

葉子結點度為0

要求葉子結點,就是求左右子樹葉子結點之和,依次遞推下去

滿足葉子結點條件或是某一子樹為空結束遞推

// ?叉樹葉?結點個數
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);
}

2.5?二叉樹第k層結點個數:

求第k層節點個數,即將根結點設為k,每遞推一層,便將k-1, 當k==1時說明已經遞推到第k層了,此時若不是空結點,返回1,若遇到空節點,返回0,然后在回歸時將它們加起來即可。

// ?叉樹第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);
}

2.6?二叉樹深度/高度:

要求高度,即子樹高度的最大值+1,子樹高度的最大值又是其子樹高度最大值+1,以此類推當遞推到空節點時結束——>返回0(空節點不算高度)

回歸時每次返回左右子樹高度取最大值+1

//?叉樹的深度/?度
int BinaryTreeDepth(BTnode* root)
{if (root == NULL){return 0;}int leftdep = BinaryTreeDepth(root->left);int rightdep = BinaryTreeDepth(root->right);return leftdep > rightdep ? leftdep + 1 : rightdep + 1;}

2.7?二叉樹查找值為x的結點:

分為左右子樹查找,依次遞推即可

結束條件為空:說明在這一路徑上沒有找到

結束條件找到了返回結點指針即可

// ?叉樹查找值為x的結點
BTnode* BinaryTreeFind(BTnode* root, BTdatatype x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}BTnode* leftfind = BinaryTreeFind(root->left,x);if (leftfind){return leftfind;}BTnode* rightfind = BinaryTreeFind(root->right,x);if (rightfind){return rightfind;}return NULL;
}

2.8 二叉樹的銷毀:

先銷毀左右子樹,最后銷毀根節點

當為空時,不用銷毀直接返回

// ?叉樹銷毀
//將本來指向根節點的root指針改為空,所以傳二級指針(一級指針也可以,只不過在調用完記得把root置為空)
void BinaryTreeDestory(BTnode** root)
{if (*root == NULL){return;}BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;}

2.9?二叉樹的層序遍歷:

除了先序遍歷、中序遍歷、后序遍歷外,還可以對二叉樹進行層序遍歷。設二叉樹的根結點所在層數為1,層序遍歷就是從所在二叉樹的根結點出發,首先訪問第一層的樹根結點,然后從左到右訪問第2 層上的結點,接著是第3層的結點,以此類推,自上而下,自左而右逐層訪問樹的結點的過程就是層序遍歷

由于遞歸會沿著一邊路徑一直遞歸下去,所以顯然不能使用遞歸!

實現層序遍歷需要額外借助數據結構:隊列

圖解:

1.創建并初始化隊列,注意將隊列結點存儲的數據類型更改
2.插入的是指向結點的指針,而不是結點的值,否則找不到結點的左右孩子,所以隊列結點存儲的數據類型為struct BTNode*
3.首先將指向根節點的指針入隊列,保存后并打印結點的值
4.根節點出隊列,保證每一次取到的隊列的頭都是新的
5.如果根節點左右孩子不為空就將其入隊列,為空則無必要,不需要打印NULL
6.重復上述操作直到隊列為空

//層序遍歷
//借助數據結構---隊列
void LevelOrder(BTnode* root)
{Queue q;Queueinit(&q);Queuepush(&q, root);while (!QueueEmpty(&q)){//取隊頭,打印BTnode* front = QueueFront(&q);printf("%d ", front->data);QueuePop(&q);//隊頭節點的左右孩子入隊列if (front->left)QueuePush(&q, front->left);if (front->right)Queuepush(&q, front->right);}//隊列為空QueueDestroy(&q);
}

三?判斷是否為完全二叉樹:

使用層序遍歷
1.左右結點不管是否為空,都入隊列
2.第一個循環用來取二叉樹第一個NULL結點前的所有數據:

???????? 如果是完全二叉樹,跳出此循環后剩下的都是NULL結點
???????? 如果是非完全二叉樹,跳出此循環后還有非空結點

3.第二個循環用來判斷此時隊列里是否有非空的指針

??? 如果直到隊列為空跳出循環說明全是空指針,返回true
??? 反之返回false


//判斷二叉樹是否為完全二叉樹
//---隊列
bool BinaryTreeComplete(BTnode* root)
{Queue q;QueueInit(&q);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 false;}}QueueDestroy(&q);return true;
}

四 二叉樹性質選擇題:

選 B。

性質:度為0結點個數==度為2結點個數+1

選 A。

2n為偶數,由二叉樹的定義可知,樹中必定存在度為0的結點和度為2的結點,設度為0結點有a個,根據度為0的結點(即葉子結點)總比度為2的結點多一個,得度為2的結點有a-1個。

再根據完全二叉樹的定義,度為1的結點有0個或1個

設度為1的結點有0個,a+0+a-1=2n,得2a=2n-1,由于結點個數必須為整數,假設不成立;

設度為1的結點有1個,a+1+a-1=2n,得a=n,即葉子結點個數為n。

選B。

由2^9-1<531<2^10-1

說明第九層填滿,第十層沒有填滿

選B。

由二叉樹的定義可知,樹中必定存在度為0的結點和度為2的結點,設度為0結點有a個,根據度為0的結點(即葉子結點)總比度為2的結點多一個,得度為2的結點有a-1個。
再根據完全二叉樹的定義,度為1的結點有0個或1個
假設度1結點為0個,a+0+a-1=767,得2a=768,即葉子結點個數為384
當度為1的結點為1個時,a+1+a-1=767,不為整數,舍去。

選D。

后序遍歷最后一個一定是根節點

中序遍歷中得到根節點左右子樹

確定一個劃去一個

在左右子樹又可以根據后序遍歷確定根節點

再看中序遍歷得到左右子樹

重復上述操作即可畫出二叉樹

以上就是【數據結構篇】鏈式結構二叉樹的全部內容,歡迎指正~?🌹🌹🌹

碼文不易,還請多多關注支持,這是我持續創作的最大動力!

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

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

相關文章

【MySQL】02.數據庫基礎

1. 數據庫的引入 之前存儲數據用文件就可以了&#xff0c;為什么還要弄個數據庫? 文件存儲存在安全性問題&#xff0c;文件不利于數據查詢和管理&#xff0c;文件不利于存儲海量數據&#xff0c;文件在程序中控制不方便。而為了解決上述問題&#xff0c;專家們設計出更加利于…

什么是 Langchain 以及其核心組件

LangChain 官方文檔&#xff1a;LangChain 一、什么是Langchain LangChain 是一個用于構建基于LLM的應用框架&#xff0c;它提供了對 LLM API 的封裝和擴展&#xff0c;使開發者能夠更方便地構建復雜的應用。 個人理解&#xff1a;用類比的方法來說&#xff0c;LangChain類似…

博客系統功能測試

博客系統網址&#xff1a;http://8.137.19.140:9090/blog_list.html 主要測試內容 功能測試、界面測試、性能測試、易用性測試、安全測試、兼容性測試、弱網測試、安裝卸載測試、壓力測試… 測試方法及目的 利用selenium和python編寫測試腳本&#xff0c;對博客系統進行的相關…

項目制作流程

一、使用 CRA 創建項目 npx create-react-app name 二、按照業務規范整理項目目錄 &#xff08;重點src目錄&#xff09; 三、安裝插件 npm install sass -Dnpm install antd --savenpm install react-router-dom 四、配置基礎路由 Router 1. 安裝路由包 react-router-dom …

ngx_http_random_index_module 模塊概述

一、使用場景 隨機內容分發 當同一目錄下存放多份等價內容&#xff08;如多張輪播圖、不同版本靜態頁面等&#xff09;時&#xff0c;可通過隨機索引實現負載均衡或流量分散。A/B 測試 通過目錄請求自動隨機分配用戶到不同測試組&#xff0c;無需后端邏輯參與。動態“首頁”選…

智能權限守護者:基于Python描述符的動態角色控制實現

智能權限守護者:基于Python描述符的動態角色控制實現 引言:當描述符遇見權限管理 在Python的魔法方法體系中,描述符(Descriptor)以其優雅的屬性訪問控制機制著稱。當我們將描述符與RBAC(基于角色的訪問控制)模型結合,就能創造出既靈活又安全的動態權限管理系統。本文…

Linux 的 UDP 網絡編程 -- 回顯服務器,翻譯服務器

目錄 1. 回顯服務器 -- echo server 1.1 相關函數介紹 1.1.1 socket() 1.1.2 bind() 1.1.3 recvfrom() 1.1.4 sendto() 1.1.5 inet_ntoa() 1.1.6 inet_addr() 1.2 Udp 服務端的封裝 -- UdpServer.hpp 1.3 服務端代碼 -- UdpServer.cc 1.4 客戶端代碼 -- UdpClient.…

Linux 內核等待機制詳解:prepare_to_wait_exclusive 與 TASK_INTERRUPTIBLE

1. prepare_to_wait_exclusive 函數解析 1.1 核心作用 prepare_to_wait_exclusive 是 Linux 內核中用于將進程以獨占方式加入等待隊列的關鍵函數,其主要功能包括: 標記獨占等待:通過設置 WQ_FLAG_EXCLUSIVE 標志,表明此等待條目是獨占的。 安全入隊:在自旋鎖保護下,將條…

【Android構建系統】了解Soong構建系統

背景介紹 在Android7.0之前&#xff0c;Android使用GNU Make描述和執行build規則。Android7.0引入了Soong構建系統&#xff0c;彌補Make構建系統在Android層面變慢、容易出錯、無法擴展且難以測試等缺點。 Soong利用Kati GNU Make克隆工具和Ninja構建系統組件來加速Android的…

信息學奧賽一本通 1539:簡單題 | 洛谷 P5057 [CQOI2006] 簡單題

【題目鏈接】 ybt 1539&#xff1a;簡單題 洛谷 P5057 [CQOI2006] 簡單題 【題目考點】 1. 樹狀數組 模板題及講解&#xff1a;洛谷 P3374 【模板】樹狀數組 【解題思路】 解法1&#xff1a;樹狀數組 該有01構成數組初值都為0。 某位置的元素被修改奇數次后值為1&#x…

倉頡開發語言入門教程:搭建開發環境

倉頡開發語言作為華為為鴻蒙系統自研的開發語言&#xff0c;雖然才發布不久&#xff0c;但是它承擔著極其重要的歷史使命。作為鴻蒙開發者&#xff0c;掌握倉頡開發語言將成為不可或缺的技能&#xff0c;今天我們從零開始&#xff0c;為大家分享倉頡語言的開發教程&#xff0c;…

玉米籽粒發育

成熟玉米籽粒的結構 玉米籽粒的組成 成熟的玉米籽粒主要由以下三部分組成&#xff1a; 母體組織&#xff1a;包括種皮、胎座和花梗。種皮由珠被發育而來&#xff0c;起到保護種子的作用&#xff0c;并在種子的休眠和萌發中發揮重要作用。胚&#xff1a;包含根分生組織、莖分…

sherpa-ncnn:音頻處理跟不上采集速度 -- 語音轉文本大模型

目錄 1. 問題報錯2. 解決方法 1. 問題報錯 報錯&#xff1a; An overrun occurred, which means the RTF of the current model on your board is larger than 1. You can use ./bin/sherpa-ncnn to verify that. Please select a smaller model whose RTF is less than 1 fo…

Postman一直打不開的解決辦法

Postman 是一款非常流行的開源 API 開發工具&#xff0c;主要用于構建、測試、調試和文檔化應用程序接口&#xff08;API&#xff09;。但有時它的性能不會特別穩定&#xff0c;功能限制和擴展性不足&#xff1b;應用于開發、測試、運維等環節&#xff0c;尤其在開發 RESTful A…

問題|對只允許輸入的變量是否進行了更改

“對只允許輸入的變量是否進行了更改”這一問題的核心是&#xff1a;在編程中&#xff0c;某些變量被設計為僅用于輸入&#xff08;只讀&#xff09;&#xff0c;但在代碼中可能被意外修改&#xff0c;導致潛在錯誤。以下是詳細解釋&#xff1a; 1. 什么是“只允許輸入的變量”…

RPC與SOAP的區別

一.RPC&#xff08;遠程過程調用&#xff09;和SOAP&#xff08;簡單對象訪問協議&#xff09;均用于實現分布式系統中的遠程通信&#xff0c;但兩者在設計理念、協議實現及應用場景上存在顯著差異。 二.對比 1.設計理念 2.協議規范 3.技術特性 4.典型應用場景 5.總結 三.總結…

c#的內存指針操作(僅用于記錄)

c#也可以直接操作內存指針&#xff0c;如下為示例&#xff1a; unsafe {byte[] a {1,2,3};fixed (byte* p1 a, p2 &a[^1]){Debugger.Log(1, "test", $"max index:{p2-p1}");Debugger.Log(1, "test", $"address:{(long)p1:X}")…

Jsp技術入門指南【十三】基于 JSTL SQL 標簽庫實現 MySQL 數據庫連接與數據分頁展示

Jsp技術入門指南【十三】基于 JSTL SQL 標簽庫實現 MySQL 數據庫連接與數據分頁展示 前言一、回顧SQL標簽的內容1. 什么是JSTL SQL標簽&#xff1f;2.為什么要用SQL標簽&#xff1f;3.第一步&#xff1a;引入SQL標簽庫4. SQL標簽的核心功能&#xff1a;連接數據庫標簽常用屬性&…

羽毛球訂場小程序源碼介紹

基于ThinkPHP、FastAdmin以及UniApp開發的羽毛球訂場小程序源碼&#xff0c;這款小程序旨在為羽毛球愛好者提供便捷的場地預訂服務。 該小程序前端采用UniApp框架開發&#xff0c;具有良好的跨平臺兼容性&#xff0c;可以一鍵發布至iOS和Android平臺&#xff0c;極大地提高了開…

Unreal Engine: Windows 下打包 AirSim項目 為 Linux 平臺項目

環境&#xff1a; Windows: win10, UE4.27, Visual Studio 2022 Community.Linux: 22.04 windows環境安裝教程&#xff1a; 鏈接遇到的問題&#xff08;問題&#xff1a;解決方案&#xff09; 點擊Linux打包按鈕&#xff0c;跳轉至網頁而不是執行打包流程&#xff1a;用VS打開項…