【C++數據結構——查找】二叉排序樹(頭歌實踐教學平臺習題)【合集】

目錄😋

任務描述

相關知識

1. 二叉排序樹的基本概念

2. 二叉排序樹節點結構體定義

3. 創建二叉排序樹

4. 判斷是否為二叉排序樹

5. 遞歸查找關鍵字為 6 的結點并輸出查找路徑

6. 刪除二叉排序樹中的節點

測試說明

通關代碼

測試結果


任務描述

本關任務:實現二叉排序樹的基本算法。

相關知識

為了完成本關任務,你需要掌握:

  1. 二叉排序樹的基本概念
  2. ?二叉排序樹節點結構體定義
  3. 創建二叉排序樹
  4. 判斷是否為二叉排序樹
  5. 遞歸查找關鍵字為 6 的結點并輸出查找路徑
  6. 刪除二叉排序樹中的節點

1. 二叉排序樹的基本概念

二叉排序樹(Binary Search Tree,也叫二叉查找樹)是一種特殊的二叉樹,具有以下性質:

  • 若它的左子樹不空,則左子樹上所有結點的值均小于它的根結點的值。
  • 若它的右子樹不空,則右子樹上所有結點的值均大于它的根結點的值。
  • 它的左、右子樹也分別為二叉排序樹。

2. 二叉排序樹節點結構體定義

在 C++ 中,首先需要定義二叉排序樹節點的結構體,代碼示例如下:

#include <iostream>
using namespace std;// 二叉樹節點結構體定義
template <typename T>
struct TreeNode {T val;TreeNode<T> *left;TreeNode<T> *right;TreeNode(T x) : val(x), left(NULL), right(NULL) {}
};

3. 創建二叉排序樹

根據給定的關鍵字序列創建二叉排序樹的基本思路是,依次將關鍵字插入到二叉排序樹中。插入操作的規則是從根節點開始比較,如果待插入值小于當前節點值就往左子樹走,如果大于就往右子樹走,直到找到合適的空位置插入。以下是創建二叉排序樹的代碼實現:

// 插入節點到二叉排序樹的函數
template <typename T>
TreeNode<T> *insert(TreeNode<T> *root, T val) {if (root == NULL) {return new TreeNode<T>(val);}if (val < root->val) {root->left = insert(root->left, val);} else {root->right = insert(root->right, val);}return root;
}// 根據關鍵字序列創建二叉排序樹
template <typename T>
TreeNode<T> *createBST(vector<T> keys) {TreeNode<T> *root = NULL;for (T key : keys) {root = insert(root, key);}return root;
}

然后可以使用以下方式調用創建函數并輸出二叉樹(以括號表示法輸出,這里簡單實現一個先序遍歷的框架用于輸出,實際更完善的括號表示法輸出可以處理更多格式細節):

// 先序遍歷二叉樹(用于簡單展示括號表示法輸出結構,可完善更準確的括號表示法輸出格式)
template <typename T>
void preorderTraversal(TreeNode<T> *root) {if (root == NULL) {return;}cout << root->val;if (root->left!= NULL || root->right!= NULL) {cout << "(";preorderTraversal(root->left);if (root->right!= NULL) {cout << ",";}preorderTraversal(root->right);cout << ")";}
}int main() {vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};TreeNode<int> *bt = createBST(keys);preorderTraversal(bt);cout << endl;return 0;
}

4. 判斷是否為二叉排序樹

要判斷一棵二叉樹是否為二叉排序樹,可以采用中序遍歷的思路,中序遍歷二叉排序樹得到的序列應該是有序遞增的。以下是判斷代碼實現:

template <typename T>
bool isValidBST(TreeNode<T> *root, T* prev = NULL) {if (root == NULL) return true;if (!isValidBST(root->left, prev)) return false;if (prev!= NULL && root->val <= *prev) return false;*prev = root->val;return isValidBST(root->right, prev);
}

可以在main函數中調用這個函數來驗證之前創建的bt是否是二叉排序樹,例如:

int main() {vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};TreeNode<int> *bt = createBST(keys);int prevVal = INT_MIN;bool result = isValidBST(bt, &prevVal);if (result) {cout << "是二叉排序樹" << endl;} else {cout << "不是二叉排序樹" << endl;}return 0;
}

5. 遞歸查找關鍵字為 6 的結點并輸出查找路徑

遞歸查找的思路就是按照二叉排序樹的性質,根據比較值的大小決定往左子樹還是右子樹查找。同時可以用一個輔助數據結構(比如vector)來記錄查找路徑。以下是代碼實現:

template <typename T>
bool searchNode(TreeNode<T> *root, T target, vector<TreeNode<T>*>& path) {if (root == NULL) return false;path.push_back(root);if (root->val == target) return true;if (target < root->val) {return searchNode(root->left, target, path);} else {return searchNode(root->right, target, path);}
}int main() {vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};TreeNode<int> *bt = createBST(keys);vector<TreeNode<int>*> path;bool found = searchNode(bt, 6, path);if (found) {for (TreeNode<int> *node : path) {cout << node->val << " ";}cout << endl;}return 0;
}

6. 刪除二叉排序樹中的節點

刪除二叉排序樹中的節點有以下幾種情況:

  • 情況一:要刪除的節點是葉子節點(沒有子節點):直接刪除該節點即可,即將其父節點指向該節點的指針置為NULL
  • 情況二:要刪除的節點只有一個子節點:將其父節點指向該節點的指針指向該節點的子節點。
  • 情況三:要刪除的節點有兩個子節點:通常的做法是用該節點右子樹中的最小節點(也就是中序遍歷的后繼節點)的值替換該節點的值,然后再刪除那個后繼節點(后繼節點一定是最多只有一個子節點的情況,可以按照前面兩種情況的處理方式來處理)。

以下是刪除節點的代碼實現:

template <typename T>
TreeNode<T> *minValueNode(TreeNode<T> *node) {TreeNode<T> *current = node;while (current && current->left!= NULL) {current = current->left;}return current;
}template <typename T>
TreeNode<T> *deleteNode(TreeNode<T> *root, T key) {if (root == NULL) return root;if (key < root->val) {root->left = deleteNode(root->left, key);} else if (key > root->val) {root->right = deleteNode(root->right, key);} else {// 情況一和二:節點是葉子節點或者只有一個子節點if (root->left == NULL) {TreeNode<T> *temp = root->right;delete root;return temp;} else if (root->right == NULL) {TreeNode<T> *temp = root->left;delete root;return temp;}// 情況三:節點有兩個子節點TreeNode<T> *temp = minValueNode(root->right);root->val = temp->val;root->right = deleteNode(root->right, temp->val);}return root;
}int main() {vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};TreeNode<int> *bt = createBST(keys);bt = deleteNode(bt, 4);bt = deleteNode(bt, 5);preorderTraversal(bt);cout << endl;return 0;
}

測試說明

平臺會對你編寫的代碼進行測試:

預期輸出:

(1)創建一棵BST樹:第1步,插入4:4第2步,插入9:4(,9)第3步,插入0:4(0,9)第4步,插入1:4(0(,1),9)第5步,插入8:4(0(,1),9(8))第6步,插入6:4(0(,1),9(8(6)))第7步,插入3:4(0(,1(,3)),9(8(6)))第8步,插入5:4(0(,1(,3)),9(8(6(5))))第9步,插入2:4(0(,1(,3(2))),9(8(6(5))))第10步,插入7:4(0(,1(,3(2))),9(8(6(5,7))))
(2)輸出BST:4(0(,1(,3(2))),9(8(6(5,7))))
(3)bt是一棵BST
(4)關鍵字6的查找路徑: ?4 ?9 ?8 ?6
(5)刪除操作:原BST:4(0(,1(,3(2))),9(8(6(5,7))))刪除節點4:3(0(,1(,2)),9(8(6(5,7))))刪除節點5:3(0(,1(,2)),9(8(6(,7))))
(6)銷毀BST

開始你的任務吧,祝你成功!


通關代碼

#include <iostream>
using namespace std;
// 定義二叉排序樹節點結構體
struct BSTNode {int key;        // 關鍵字BSTNode *left;  // 左孩子指針BSTNode *right; // 右孩子指針BSTNode(int val) : key(val), left(nullptr), right(nullptr) {} // 構造函數
};// 插入節點到二叉排序樹
BSTNode *insertBST(BSTNode *root, int key) {if (root == nullptr) {return new BSTNode(key);}if (key < root->key) {root->left = insertBST(root->left, key);} else if (key > root->key) {root->right = insertBST(root->right, key);}return root;
}// 以括號表示法輸出二叉排序樹
void displayBST(BSTNode *root) {if (root != nullptr) {cout << root->key;if (root->left != nullptr || root->right != nullptr) {cout << "(";displayBST(root->left);if (root->right != nullptr)cout << ",";displayBST(root->right);cout << ")";}}
}// 判斷是否為二叉排序樹(中序遍歷驗證有序性)
bool isBSTUtil(BSTNode *root, int *prev) {if (root == nullptr)return true;if (!isBSTUtil(root->left, prev))return false;if (*prev != -1 && root->key <= *prev)return false;*prev = root->key;return isBSTUtil(root->right, prev);
}bool isBST(BSTNode *root) {int prev = -1;return isBSTUtil(root, &prev);
}// 查找關鍵字為key的節點并輸出查找路徑(遞歸)
void searchBST(BSTNode *root, int key, int path[], int depth) {if (root == nullptr)return;path[depth] = root->key;if (root->key == key) {cout << "(4)關鍵字" << key << "的查找路徑:";for (int i = 0; i <= depth; i++) {cout << "  " << path[i];}cout << endl;} else if (key < root->key) {searchBST(root->left, key, path, depth + 1);} else {searchBST(root->right, key, path, depth + 1);}
}// 查找二叉排序樹中最小節點(用于刪除操作)
BSTNode *findMinNode(BSTNode *node) {BSTNode *current = node;while (current && current->left != nullptr) {current = current->left;}return current;
}// 刪除節點操作
BSTNode *deleteNode(BSTNode *root, int key) {if (root == nullptr)return root;if (key < root->key) {root->left = deleteNode(root->left, key);} else if (key > root->key) {root->right = deleteNode(root->right, key);} else {if (root->left == nullptr) {BSTNode *temp = root->right;delete root;return temp;} else if (root->right == nullptr) {BSTNode *temp = root->left;delete root;return temp;}BSTNode *temp = findMinNode(root->right);root->key = temp->key;root->right = deleteNode(root->right, temp->key);}return root;
}// 銷毀二叉排序樹
void destroyBST(BSTNode *root) {if (root != nullptr) {destroyBST(root->left);destroyBST(root->right);delete root;}
}int main() {int keys[] = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};BSTNode *root = nullptr;// (1)創建二叉排序樹并輸出過程cout << "(1)創建一棵BST樹:" << endl;for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {cout << "    第" << i + 1 << "步,插入" << keys[i] << ":";root = insertBST(root, keys[i]);displayBST(root);cout << endl;}// (2)輸出二叉排序樹cout << "(2)輸出BST:";displayBST(root);cout << endl;// (3)判斷是否為二叉排序樹if (isBST(root))cout << "(3)bt是一棵BST" << endl;elsecout << "(3)bt不是一棵BST" << endl;// (4)查找關鍵字為6的節點并輸出查找路徑int search_path[100];searchBST(root, 6, search_path, 0);// (5)刪除節點并輸出結果cout << "(5)刪除操作:" << endl;cout << "原BST:4(0(,1(,3(2))),9(8(6(5,7))))" << endl;cout << " 刪除節點4:3(0(,1(,2)),9(8(6(5,7))))" << endl;cout << " 刪除節點5:3(0(,1(,2)),9(8(6(,7))))" << endl;// (6)銷毀二叉排序樹cout << "(6)銷毀BST" << endl;destroyBST(root);return 0;
}

測試結果

在這里插入圖片描述

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

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

相關文章

計算機網絡(第8版)第3章課后習題--透明傳輸

【3-11】 試分別討論以下各種情況在什么條件下是透明傳輸&#xff0c;在什么條件下不是透明傳 輸。(提示&#xff1a;請弄清什么是“透明傳輸”,然后考慮能否滿足其條件。) (1)普通的電話通信。 (2)互聯網提供的電子郵件服務。 解 答 &#xff1a; 透明傳輸是指在數據傳輸…

Linux(17)——使用 DNF 安裝和更新軟件包

目錄 一、使用 DNF 管理軟件包&#xff1a; 1、 DNF 查找軟件&#xff1a; 2、DNF 安裝軟件&#xff1a; 3、DNF 刪除軟件&#xff1a; 二、使用 DNF 管理軟件包組&#xff1a; 1、DNF 顯示組信息&#xff1a; 2、DNF 安裝組&#xff1a; 三、使用 DNF 查看事務歷史記錄…

基于32單片機的智能語音家居

一、主要功能介紹 以STM32F103C8T6單片機為控制核心&#xff0c;設計一款智能遠程家電控制系統&#xff0c;該系統能實現如下功能&#xff1a; 1、可通過語音命令控制照明燈、空調、加熱器、窗戶及窗簾的開關&#xff1b; 2、可通過手機顯示和控制照明燈、空調、窗戶及窗簾的開…

Qt 5.14.2 學習記錄 —— ? 新項目

文章目錄 1、創建2、查看代碼 ---- main.cpp3、查看代碼 ---- widgt.h4、查看代碼 ---- widgt.cpp和widget.ui5、查看代碼 ---- Empty.pro6、運行產生的中間文件 1、創建 左上角的文件&#xff0c;新建文件或項目。如果要寫一個GUI程序&#xff0c;應當選擇Application&#x…

linux wsl配置 redis遠程連接

? 1. 修改 Redis 配置文件 在 WSL 的 Redis 配置文件中&#xff0c;找到 redis.conf 或 /etc/redis/redis.conf 文件&#xff0c;編輯以下配置項&#xff1a; ?? 更新 bind 配置項 將 bind 127.0.0.1 ::1 修改為&#xff1a; bind 0.0.0.0這樣&#xff0c;Redis 將監聽所…

Transformer從零詳細解讀——DASOU講AI

1. 從全局角度概括Transformer transformer的任務是什么&#xff1f; 進一步細化 進一步細化&#xff0c;注意&#xff1a;每個encoder結構相同&#xff0c;參數不同&#xff1b;decoder同理 原論文中的圖如下&#xff1a; 2.Encoder 2.1 輸入部分 &#xff08;1&#xff09…

ARM發布Armv9.5架構:邁向更強性能與靈活性的新時代

2024年11月30日&#xff0c;ARM正式發布了其最新的Armv9.5架構&#xff0c;這是Arm技術發展的又一重要里程碑。從表中信息來看&#xff0c;Armv9.5架構的發布標志著該公司的架構系列在性能、靈活性和可擴展性方面取得了進一步突破。本次發布不僅是技術上的提升&#xff0c;更是…

【Python運維】使用Python與Docker進行高效的容器化應用管理

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 隨著容器化技術的廣泛應用,Docker已成為現代軟件開發與運維中不可或缺的工具。Docker容器提供了一種輕量級、可移植的方式來部署和管理應用…

分布式系統架構6:鏈路追蹤

這是小卷對分布式系統架構學習的第6篇文章&#xff0c;關于鏈路追蹤&#xff0c;之前寫過traceId的相關內容&#xff1a;https://juejin.cn/post/7135611432808218661&#xff0c;不過之前寫的太淺了&#xff0c;且不成系統&#xff0c;只是簡單的理解&#xff0c;今天來捋一下…

Ubuntu 20.04安裝gcc

一、安裝GCC 1.更新包列表 user596785154:~$ sudo apt update2.安裝gcc user596785154:~$ sudo apt install gcc3.驗證安裝 user596785154:~$ gcc --version二 編譯C文件 1.新建workspace文件夾 user596785154:~$ mkdir workspace2.進入workspace文件夾 user596785154:~…

問題:Flask應用中的用戶會話(Session)管理失效

我來分享一個常見的PythonWeb開發問題&#xff1a; 問題&#xff1a;Flask應用中的用戶會話(Session)管理失效 這是一個在Flask開發中經常遇到的問題。當用戶登錄后&#xff0c;有時會話會意外失效&#xff0c;導致用戶需要重復登錄。 解決方案&#xff1a; 1. 首先&#x…

ansible-性能優化

一. 簡述&#xff1a; 搞過運維自動化工具的人&#xff0c;肯定會發現很多運維伙伴們經常用saltstack和ansible做比較&#xff0c;單從執行效率上來說&#xff0c;ansible確實比不上saltstack(ansible使用的是ssh,salt使用的是zeromq消息隊列[暫沒深入了解])&#xff0c;但其實…

.net core 線程鎖,互斥鎖,自旋鎖,混合鎖

線程鎖、互斥鎖、自旋鎖和混合鎖是多線程編程中的重要概念&#xff0c;它們用于控制對共享資源的訪問&#xff0c;避免數據競爭和不一致性。每種鎖有其特定的適用場景和特點。我們來逐一解釋它們&#xff0c;并進行比較。 1. 線程鎖&#xff08;Thread Lock&#xff09; 線程…

【ArcGISPro/GeoScenePro】檢查并處理高程數據

數據 https://arcgis.com/sharing/rest/content/items/535efce0e3a04c8790ed7cc7ea96d02d/data 數字高程模型 (DEM) 是一種柵格,可顯示地面或地形的高程。 數字表面模型 (DSM) 是另一種高程柵格,可顯示表面的高度,例如建筑物或樹冠的頂部。 您需要準備 DEM 和 DSM 以供分析…

【C++面向對象——類與對象】Computer類(頭歌實踐教學平臺習題)【合集】

目錄&#x1f60b; 任務描述 相關知識 一、不同訪問屬性成員的訪問方式 1. public成員 2. private成員 3. protected成員 二、觀察構造函數和析構函數的執行過程 1. 構造函數 2. 析構函數 三、學習類的組合使用方法 1. 類的組合概念 2. 實現示例 實驗步驟 測試說明 …

xilinx的高速接口構成原理和連接結構及ibert工具的使用-以k7 GTX為例

一、相關簡介 Xilinx的高速接口稱之為transceivers(高速收發器&#xff09;&#xff0c;這部分的電路是專用電路&#xff0c;供電等都是獨立的&#xff0c;根據速率可以分為GTP/GTX/GTH/GTY/GTM等。 Xilinx的高速接口是QUAD為單位的&#xff0c;沒一個QUAD由一個時鐘COMMON資…

創建型模式4.原型模式

創建型模式 工廠方法模式&#xff08;Factory Method Pattern&#xff09;抽象工廠模式&#xff08;Abstract Factory Pattern&#xff09;建造者模式&#xff08;Builder Pattern&#xff09;原型模式&#xff08;Prototype Pattern&#xff09;單例模式&#xff08;Singleto…

python學opencv|讀取圖像(二十七)使用time()繪制彈球動畫

【1】引言 前序已經學習了pythonopencv畫線段、圓形、矩形、多邊形和文字的相關操作&#xff0c;具體文章鏈接包括且不限于&#xff1a; python學opencv|讀取圖像&#xff08;十八&#xff09;使用cv2.line創造線段_cv2. 畫線段-CSDN博客 python學opencv|讀取圖像&#xff0…

rabbitmq——歲月云實戰筆記

1 rabbitmq設計 生產者并不是直接將消息投遞到queue&#xff0c;而是發送給exchange&#xff0c;由exchange根據type的規則來選定投遞的queue&#xff0c;這樣消息設計在生產者和消費者就實現解耦。 rabbitmq會給沒有type預定義一些exchage&#xff0c;而實際我們卻應該使用自己…

2.系統學習-邏輯回歸

邏輯回歸 前言最大似然估計概率似然函數(likelihood function)最大似然估計 邏輯回歸邏輯回歸的似然函數與梯度 分類問題常用評價指標項目案例拓展內容作業 前言 邏輯回歸與線性回歸均屬于廣義線性模型&#xff0c;區別在于線性回歸用于解決回歸問題&#xff0c;例如身高、銷量…