成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊二叉搜索樹中的插入操作

開發 前端
給定二叉搜索樹(BST)的根節點和要插入樹中的值,將值插入二叉搜索樹。返回插入后二叉搜索樹的根節點。輸入數據保證,新值和原始二叉搜索樹中的任意節點值都不同。

[[421164]]

二叉搜索樹中的插入操作

題目鏈接:https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/

給定二叉搜索樹(BST)的根節點和要插入樹中的值,將值插入二叉搜索樹。返回插入后二叉搜索樹的根節點。輸入數據保證,新值和原始二叉搜索樹中的任意節點值都不同。

注意,可能存在多種有效的插入方式,只要樹在插入后仍保持為二叉搜索樹即可。你可以返回任意有效的結果。

提示:

  • 給定的樹上的節點數介于 0 和 10^4 之間
  • 每個節點都有一個唯一整數值,取值范圍從 0 到 10^8
  • -10^8 <= val <= 10^8
  • 新值和原始二叉搜索樹中的任意節點值都不同

思路

其實這道題目其實是一道簡單題目,但是題目中的提示:有多種有效的插入方式,還可以重構二叉搜索樹,一下子嚇退了不少人,瞬間感覺題目復雜了很多。

其實可以不考慮題目中提示所說的改變樹的結構的插入方式。

如下演示視頻中可以看出:只要按照二叉搜索樹的規則去遍歷,遇到空節點就插入節點就可以了。

二叉搜索樹中的插入操作

例如插入元素10 ,需要找到末尾節點插入便可,一樣的道理來插入元素15,插入元素0,插入元素6,需要調整二叉樹的結構么?并不需要。。

只要遍歷二叉搜索樹,找到空節點 插入元素就可以了,那么這道題其實就簡單了。

接下來就是遍歷二叉搜索樹的過程了。

遞歸

遞歸三部曲:

  • 確定遞歸函數參數以及返回值

參數就是根節點指針,以及要插入元素,這里遞歸函數要不要有返回值呢?

可以有,也可以沒有,但遞歸函數如果沒有返回值的話,實現是比較麻煩的,下面也會給出其具體實現代碼。

有返回值的話,可以利用返回值完成新加入的節點與其父節點的賦值操作。(下面會進一步解釋)

遞歸函數的返回類型為節點類型TreeNode * 。

代碼如下:

  1. TreeNode* insertIntoBST(TreeNode* root, int val) 
  • 確定終止條件

終止條件就是找到遍歷的節點為null的時候,就是要插入節點的位置了,并把插入的節點返回。

代碼如下:

  1. if (root == NULL) { 
  2.     TreeNode* node = new TreeNode(val); 
  3.     return node; 

這里把添加的節點返回給上一層,就完成了父子節點的賦值操作了,詳細再往下看。

  • 確定單層遞歸的邏輯

此時要明確,需要遍歷整棵樹么?

別忘了這是搜索樹,遍歷整顆搜索樹簡直是對搜索樹的侮辱,哈哈。

搜索樹是有方向了,可以根據插入元素的數值,決定遞歸方向。

代碼如下:

  1. if (root->val > val) root->left = insertIntoBST(root->left, val); 
  2. if (root->val < val) root->right = insertIntoBST(root->right, val); 
  3. return root; 

到這里,大家應該能感受到,如何通過遞歸函數返回值完成了新加入節點的父子關系賦值操作了,下一層將加入節點返回,本層用root->left或者root->right將其接住。

整體代碼如下:

  1. class Solution { 
  2. public
  3.     TreeNode* insertIntoBST(TreeNode* root, int val) { 
  4.         if (root == NULL) { 
  5.             TreeNode* node = new TreeNode(val); 
  6.             return node; 
  7.         } 
  8.         if (root->val > val) root->left = insertIntoBST(root->left, val); 
  9.         if (root->val < val) root->right = insertIntoBST(root->right, val); 
  10.         return root; 
  11.     } 
  12. }; 

可以看出代碼并不復雜。

剛剛說了遞歸函數不用返回值也可以,找到插入的節點位置,直接讓其父節點指向插入節點,結束遞歸,也是可以的。

那么遞歸函數定義如下:

  1. TreeNode* parent; // 記錄遍歷節點的父節點 
  2. void traversal(TreeNode* cur, int val) 

沒有返回值,需要記錄上一個節點(parent),遇到空節點了,就讓parent左孩子或者右孩子指向新插入的節點。然后結束遞歸。

代碼如下:

  1. class Solution { 
  2. private: 
  3.     TreeNode* parent; 
  4.     void traversal(TreeNode* cur, int val) { 
  5.         if (cur == NULL) { 
  6.             TreeNode* node = new TreeNode(val); 
  7.             if (val > parent->val) parent->right = node; 
  8.             else parent->left = node; 
  9.             return
  10.         } 
  11.         parent = cur; 
  12.         if (cur->val > val) traversal(cur->left, val); 
  13.         if (cur->val < val) traversal(cur->right, val); 
  14.         return
  15.     } 
  16.  
  17. public
  18.     TreeNode* insertIntoBST(TreeNode* root, int val) { 
  19.         parent = new TreeNode(0); 
  20.         if (root == NULL) { 
  21.             root = new TreeNode(val); 
  22.         } 
  23.         traversal(root, val); 
  24.         return root; 
  25.     } 
  26. }; 

可以看出還是麻煩一些的。

我之所以舉這個例子,是想說明通過遞歸函數的返回值完成父子節點的賦值是可以帶來便利的。

網上千變一律的代碼,可能會誤導大家認為通過遞歸函數返回節點 這樣的寫法是天經地義,其實這里是有優化的!

迭代

再來看看迭代法,對二叉搜索樹迭代寫法不熟悉,可以看這篇:二叉樹:二叉搜索樹登場!

在迭代法遍歷的過程中,需要記錄一下當前遍歷的節點的父節點,這樣才能做插入節點的操作。

530.二叉搜索樹的最小絕對差501.二叉搜索樹中的眾數中,都是用了記錄pre和cur兩個指針的技巧,本題也是一樣的。

代碼如下:

  1. class Solution { 
  2. public
  3.     TreeNode* insertIntoBST(TreeNode* root, int val) { 
  4.         if (root == NULL) { 
  5.             TreeNode* node = new TreeNode(val); 
  6.             return node; 
  7.         } 
  8.         TreeNode* cur = root; 
  9.         TreeNode* parent = root; // 這個很重要,需要記錄上一個節點,否則無法賦值新節點 
  10.         while (cur != NULL) { 
  11.             parent = cur; 
  12.             if (cur->val > val) cur = cur->left
  13.             else cur = cur->right
  14.         } 
  15.         TreeNode* node = new TreeNode(val); 
  16.         if (val < parent->val) parent->left = node;// 此時是用parent節點的進行賦值 
  17.         else parent->right = node; 
  18.         return root; 
  19.     } 
  20. }; 

總結

首先在二叉搜索樹中的插入操作,大家不用恐懼其重構搜索樹,其實根本不用重構。

然后在遞歸中,我們重點講了如果通過遞歸函數的返回值完成新加入節點和其父節點的賦值操作,并強調了搜索樹的有序性。

最后依然給出了迭代的方法,迭代的方法就需要記錄當前遍歷節點的父節點了,這個和沒有返回值的遞歸函數實現的代碼邏輯是一樣的。

其他語言版本

Java

  1. class Solution { 
  2.     public TreeNode insertIntoBST(TreeNode root, int val) { 
  3.         if (root == nullreturn new TreeNode(val); 
  4.         TreeNode newRoot = root; 
  5.         TreeNode pre = root; 
  6.         while (root != null) { 
  7.             pre = root; 
  8.             if (root.val > val) { 
  9.                 root = root.left
  10.             } else if (root.val < val) { 
  11.                 root = root.right
  12.             } 
  13.         } 
  14.         if (pre.val > val) { 
  15.             pre.left = new TreeNode(val); 
  16.         } else { 
  17.             pre.right = new TreeNode(val); 
  18.         } 
  19.  
  20.         return newRoot; 
  21.     } 

遞歸法

  1. class Solution { 
  2.     public TreeNode insertIntoBST(TreeNode root, int val) { 
  3.         return buildTree(root, val); 
  4.     } 
  5.  
  6.     public TreeNode buildTree(TreeNode root, int val){ 
  7.         if (root == null) // 如果當前節點為空,也就意味著val找到了合適的位置,此時創建節點直接返回。 
  8.             return new TreeNode(val); 
  9.         if (root.val < val){ 
  10.             root.right = buildTree(root.right, val); // 遞歸創建右子樹 
  11.         }else if (root.val > val){ 
  12.             root.left = buildTree(root.left, val); // 遞歸創建左子樹 
  13.         } 
  14.         return root; 
  15.     } 

Python

遞歸法 - 有返回值

  1. class Solution: 
  2.     def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode: 
  3.         if root is None: 
  4.             return TreeNode(val) # 如果當前節點為空,也就意味著val找到了合適的位置,此時創建節點直接返回。 
  5.         if root.val < val: 
  6.             root.right = self.insertIntoBST(root.right, val) # 遞歸創建右子樹 
  7.         if root.val > val: 
  8.             root.left = self.insertIntoBST(root.left, val) # 遞歸創建左子樹 
  9.         return root 

遞歸法 - 無返回值

  1. class Solution: 
  2.     def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode: 
  3.         if not root: 
  4.             return TreeNode(val) 
  5.         parent = None 
  6.         def __traverse(cur: TreeNode, val: int) -> None: 
  7.             # 在函數運行的同時把新節點插入到該被插入的地方. 
  8.             nonlocal parent 
  9.             if not cur: 
  10.                 new_node = TreeNode(val) 
  11.                 if parent.val < val: 
  12.                     parent.right = new_node 
  13.                 else
  14.                     parent.left = new_node 
  15.                 return 
  16.  
  17.             parent = cur # 重點: parent的作用只有運行到上面if not cur:才會發揮出來. 
  18.             if cur.val < val: 
  19.                 __traverse(cur.right, val) 
  20.             else
  21.                 __traverse(cur.left, val) 
  22.             return 
  23.         __traverse(root, val) 
  24.         return root 

迭代法與無返回值的遞歸函數的思路大體一致

  1. class Solution: 
  2.     def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode: 
  3.         if not root: 
  4.             return TreeNode(val) 
  5.         parent = None 
  6.         cur = root 
  7.  
  8.         # 用while循環不斷地找新節點的parent 
  9.         while cur: 
  10.             if cur.val < val: 
  11.                 parent = cur 
  12.                 cur = cur.right 
  13.             elif cur.val > val: 
  14.                 parent = cur 
  15.                 cur = cur.left 
  16.  
  17.         # 運行到這意味著已經跳出上面的while循環, 
  18.         # 同時意味著新節點的parent已經被找到. 
  19.         # parent已被找到, 新節點已經ready. 把兩個節點黏在一起就好了. 
  20.         if parent.val > val: 
  21.             parent.left = TreeNode(val) 
  22.         else
  23.             parent.right = TreeNode(val) 
  24.  
  25.         return root 

 

責任編輯:姜華 來源: 代碼隨想錄
相關推薦

2021-08-26 11:31:11

二叉樹數據結構算法

2021-09-03 08:58:00

二叉搜索樹節點

2021-10-12 09:25:11

二叉樹樹形結構

2021-08-31 11:35:24

二叉搜索樹迭代法公共祖先

2022-12-26 00:51:33

雙向鏈表二叉搜索樹

2023-05-04 07:30:28

二叉搜索樹BST

2021-11-28 23:54:28

子樹B結構

2022-01-11 10:01:25

二叉搜索樹數量

2021-12-07 06:55:17

二叉搜索樹鏈表

2020-04-27 07:05:58

二叉樹左子樹右子樹

2021-12-03 09:16:03

二叉樹打印平衡

2024-01-17 07:36:50

二叉搜索聯系簿

2023-07-31 08:01:13

二叉搜索測試

2021-09-07 11:01:41

二叉搜索樹序數組

2023-02-13 08:02:08

哈希函數哈希表搜索樹

2023-02-01 07:27:46

序列化二叉樹根節點

2020-12-11 09:49:29

二叉樹搜索樹數據

2020-10-11 16:56:48

二叉搜索樹代碼開發

2021-09-06 10:38:50

二叉搜索樹遞歸

2021-10-11 06:38:52

遞歸二叉搜索樹
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩在线观看中文字幕 | 亚洲五码久久 | 免费精品 | 精品一区二区三区四区五区 | 日本亚洲欧美 | 日韩国产一区二区三区 | 一级毛片在线播放 | 精品av天堂毛片久久久借种 | 久久亚洲一区二区三区四区 | 久久麻豆精品 | 精品美女在线观看 | 色婷婷综合久久久中字幕精品久久 | 亚洲欧美视频 | 国产久| 中文一区| 超碰欧美 | 亚洲国产精品福利 | 国产亚洲欧美在线 | 一级免费看片 | 亚洲一区二区三区国产 | 日韩高清中文字幕 | 精品国产免费人成在线观看 | 一级做a爰片久久毛片免费看 | 日韩免费毛片 | av网址在线播放 | 在线2区| 黄色毛片在线看 | 一区二区三区视频在线免费观看 | avmans最新导航地址 | 日韩在线精品 | 午夜影院官网 | 国产成人免费视频网站视频社区 | 在线成人免费观看 | 午夜影院在线观看 | av中文字幕在线 | 国产精品美女久久久久久久网站 | 亚洲一区导航 | 国产婷婷精品av在线 | 日韩在线视频一区 | 色婷婷av777 av免费网站在线 | 久久久久久久国产 |