chriscoding
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# 二元搜尋樹概念 [toc] > 二元搜尋樹會有規則,所以在做搜尋上會較簡單, 但是二元樹,很雜亂,所以只能透過地回和一一比對去做 # 二元樹和二元搜尋樹概念 - Not every level must be completely filled 就是不需要必定為completed tree - (最主要跟一般二元樹的差別)**任一個節點的左子樹都比父節點小,右子樹都比父節點大,且每一個節點的值都不重複**。 - 所以當我們要查找資料的時候,就可以從根節點開始,比根節點小的就從左子樹開始找,比較大的就從右子樹開始找。相對於其他資料結構而言,尋找、插入的時間複雜度較低,為O(logN)。 - 所以整個Tree最小的那個node 因該會在最左最下的那個node ,最大的則是最右最下的那個node - In a Binary Search Tree (BST), all keys in left subtree of a key must be smaller and all keys in right subtree must be greater. So a Binary Search Tree by definition has distinct keys and duplicates in binary search tree are not allowed. 記得所有的value不可重複**** # 二元搜尋樹 big o ![](https://i.imgur.com/ejfApqd.png) 搜尋 : 平均時間複雜度 log(n),因為只要往其中一邊走。 新增 : 平均時間複雜度 log(n),因為它要找到適當的插入位置 刪除 : 平均時間複雜度 log(n),因為它要找到適當的移除位置 ## 平衡二元搜尋樹 ( Balanced BST ) BST 平均來看基本操作都有指數級的時間複雜度,但為什麼還是沒選他呢 ? 主要的原因在於,它最壞變成 O(n) 的時間複雜度操作,如下圖 5 所示,它的確也是一個 BST,這樣如果我們要搜尋某個值,仍然是一個一個慢慢找。 ![](https://i.imgur.com/ESiTdE7.png) 圖 5 : 有問題的 BST 因為後來就誕生一種『 平衡二元搜尋樹 』,如下圖 6 所示,事實和上面二元樹相同,只是差在每當插入節點時,會進行平衡。 它的特點如下 : 葉節點的高度差的絕對值不能超過 1。 左右子樹都為平衡二元搜尋樹。 它的最好、最壞、平均的新增、刪除、搜尋的時間複雜度都是 O (logn)。 AVL 樹、紅黑樹都是屬於平衡二元搜尋樹,它們都會自動的進行平衡操作。 ![](https://i.imgur.com/xlQJovV.png) 圖 6 : 平衡二元樹 平衡二元搜尋樹,正常來說,已經是在搜尋中最有效率的資料結構了,但是為什麼它是沒選它呢 ? 因為它是以『 記憶體 』來說,操作最有效率,但是以『 硬碟 』來說則否。 在資料庫的世界,通常資料量都有點兒大,不太可能全部都塞在記憶體中操作,通常會放在硬碟中。 那為什麼平衡二元搜尋樹在硬碟中操作沒有什麼效率呢 ? 因為 I/O 的問題 然後你想想如果一個很深的平衡二元搜尋樹,那如果要找的值是在最小面,以下圖 7 為例,那它就至少要進行 100 次 i/o 操作。 ![](https://i.imgur.com/3kV64gl.png) 圖 7 : 平衡二元樹在節點多時的問題 B 樹 根據上述 i/o 的原因,因此又誕生出叫『 B 樹 』的東東,它想解決的東西為 :+1 :+1: :8ball: 當樹太大就要多次io處理: 是的,當樹的大小超過了系統的內存容量時,可能需要進行多次IO操作才能處理整個樹。這是因為內存容量有限,無法一次性將整個樹加載到內存中進行操作。 外部存儲器算法需要考慮到IO操作的效率和數據讀取的順序,以最大限度地減少IO次數和數據讀取的開銷。常見的技術包括使用緩存(cache)來減少IO操作、按照順序讀取數據以提高讀取效率、以及使用索引或搜索樹結構來加速節點查找等。 -[b tree](/g9s0omRrSmmRQbcRKJQDVw) # 二元搜尋樹搜尋、新增、改值、刪除四種操作 ## **新增節點** 假設我們今天要把值為 15 和 40 的節點新增進去 先做 15 的節點: 1. 與 root 節點 ( 20 ) 比較,15 < 20,左子樹不為空,往左子樹走 2. 與節點 ( 10 ) 比較,10 < 15,右子樹為空,就把 15 填進去 ![](https://i.imgur.com/mzawVH0.png) 相信聰明的你已經知道怎麼新增節點了,試試看把 40 新增進去吧。 沒錯就是這樣,按照上面的邏輯 40 就應該放在 30 的右邊(右子樹)。 ![](https://i.imgur.com/UNsWByK.png) ## **搜尋結點** 假設我們要搜尋 15 這個節點,**其實跟新增的步驟差不多**,先逐一比大小,差在要確認經過的節點的值是不是 15 即可。 1. 與 root 節點 ( 20 ) 比較,15 < 20,往左子樹走 2. 與節點 ( 10 ) 比較,10 < 15,往右子樹走 3. 與節點 ( 15 ) 比較,15 == 15,找到了! ## **修改節點的值** 我上網查發現沒有什麼人講到如果要改值的話怎麼操作最有效率,但最簡單的方法應該是就把該舊值的節點刪除,然後插入更新值的節點。 ## 刪除節點的值(有幾種情況) 1. 第一種情況:在最leaf 的node 直接delete 就好,因為你不需要重新排序他。 ![](https://i.imgur.com/fo0qNpr.jpg) 2. 第二種情況:如果是在父節點上,然後這個父節點只有一個子樹(左子樹or 右子樹)就把樹刪掉,然後讓子樹串上去,指標指上去就好 ![](https://i.imgur.com/lvYyBKL.jpg) 刪掉父節點,補上子節點。 ![](https://i.imgur.com/v38J9tv.jpg) 3. 第三種情況: 如果你要刪除的節點有很多子樹 但如果你是在父節點上,且你有兩層以上的子樹,那你要找的接替者succesor 如下圖,我們要刪除70, 並且補上70的位置,然後再讓85補上 會找到80的位置,因為比你要保持binary search tree的規律,所以要剛好藉在50<x<90之間 如果我們找90的右子樹,那麼他必定比90大,就不合理,那如果我們找90的左子樹,可以知道這個數字必定比90小,但右一定比50大(所以才會第一關跑來90這個子樹,而不是跑去50 ) ![](https://i.imgur.com/FuaqLOH.jpg) 至於要怎麼找出80這個位置: 如下圖,總而言之就是,我們要找到目前要刪除的點的子數中最大的那個樹(整個binary search tree 依照priority 排出順序後,你要刪除的node的前一個順位的那一個node就是你的補貼者)因為比你這個要刪出node更大的,可能會到刪除node的父子樹的右子樹去, 如果你要刪除的是左子樹→找最大的 如果你要刪除的是右子樹→找最小的 ![](https://i.imgur.com/FvG5dAA.jpg) - [BTS_CRUD完整程式碼](/stXJ17WyTX2kKszE7mHDag) # 二元搜尋樹插入概念(補充) ## 插入概念 和搜尋很像,從根節點開始比大小,比較小的往左子樹走,比較大的往右子樹走,一樣的則返回,直到插入為止(要邊排邊插入。 如果單純只是二元樹的插入話,就是插入在complete tree 上最後一個leaf 而已)。因為二元樹的建立沒有大小之分。 ![](https://i.imgur.com/9mkyRqX.jpg) # 二元搜尋樹部分code(插入新的node ) 思路: - 把每個子樹當作一個part ,每個子樹有父子樹以及左右子樹。每次地迴,就是再去下一個子樹part 去看。 - 因為BST的規則,父子樹要大於左子樹,所以我們必須要傳入兩個參數,要加入的點,以及父子樹,因為要做比較 - 然後比較父子樹和要加入的點的大小,如果小就往左邊地回,然後把左子樹看成新的子樹part 如第一步驟,反之如果比較大就往右邊走,然後一樣。 ## 二元搜尋樹部分code(插入新的node )程式碼 ```python= ```python import QueueLinkedList as queue class BSTNode: def __init__(self, data): self.data = data self.leftChild = None self.rightChild = None def insertNode(rootNode, nodeValue): # 必須傳入父節點,和子節點 #---------------先判斷有沒有樹 if rootNode.data == None: # 判斷是否有值 rootNode.data = nodeValue #----------------- elif nodeValue < rootNode.data: # 比對目前的這個節點是否小於你要插入的節點(放到左子樹) if rootNode.leftChild is None: rootNode.leftChild = BSTNode(nodeValue) # 如果左子樹為空,就建立左子樹 else: insertNode(rootNode.leftChild, nodeValue) #遞迴:如果左子樹不為空,就繼續尋找下去 elif nodeValue >rootNode.data: if rootNode.rightChild is None: # 同上的原理 只是變成右邊 rootNode.rightChild = BSTNode(nodeValue) else: insertNode(rootNode.rightChild, nodeValue) else: return "can not allowed duplicated value " return "The node has been successfully inserted ``` ## BST 全部程式碼 ```python= # Created by Elshad Karimov # Copyright © 2020 AppMillers. All rights reserved. import QueueLinkedList as queue class BSTNode: def __init__(self, data): self.data = data self.leftChild = None self.rightChild = None def insertNode(rootNode, nodeValue): # 必須傳入父節點,和子節點 #---------------先判斷有沒有樹 if rootNode.data == None: # 判斷是否有值 rootNode.data = nodeValue #----------------- elif nodeValue <= rootNode.data: # 比對目前的這個節點是否小於你要插入的節點(放到左子樹) if rootNode.leftChild is None: rootNode.leftChild = BSTNode(nodeValue) # 如果左子樹為空,就建立左子樹 else: insertNode(rootNode.leftChild, nodeValue) #遞迴:如果左子樹不為空,就繼續尋找下去 else: if rootNode.rightChild is None: # 同上的原理 只是變成右邊 rootNode.rightChild = BSTNode(nodeValue) else: insertNode(rootNode.rightChild, nodeValue) return "The node has been successfully inserted" def preOrderTraversal(rootNode): # travel 方法,一樣和之前的一般binary tree 一樣 if not rootNode: return print(rootNode.data) preOrderTraversal(rootNode.leftChild) preOrderTraversal(rootNode.rightChild) def inOrderTraversal(rootNode): if not rootNode: return inOrderTraversal(rootNode.leftChild) print(rootNode.data) inOrderTraversal(rootNode.rightChild) def postOrderTraversal(rootNode): if not rootNode: return postOrderTraversal(rootNode.leftChild) postOrderTraversal(rootNode.rightChild) print(rootNode.data) ## level order 的方法 跟binary tree 一模一樣 def levelOrderTraversal(rootNode): if not rootNode: return else: customQueue = queue.Queue() customQueue.enqueue(rootNode) while not(customQueue.isEmpty()): root = customQueue.dequeue() print(root.value.data) if root.value.leftChild is not None: customQueue.enqueue(root.value.leftChild) if root.value.rightChild is not None: customQueue.enqueue(root.value.rightChild) def searchNode(rootNode, nodeValue): if rootNode.data == nodeValue: print("The value is found") elif nodeValue < rootNode.data: # 跟上面的插入很像, 因為你在插入的動作,就需要去做排序比較 ,這個binary search tree的原則 if rootNode.leftChild.data == nodeValue: print("The value is found") else: searchNode(rootNode.leftChild, nodeValue) # 做地迴 else: if rootNode.rightChild.data == nodeValue: print("The value is found") else: searchNode(rootNode.rightChild, nodeValue) def minValueNode(bstNode): # binary search tree 最小值會發生在最左邊且最下面的那個leaf current = bstNode while (current.leftChild is not None): current = current.leftChild return current def deleteNode(rootNode, nodeValue): if rootNode is None: return rootNode if nodeValue < rootNode.data: rootNode.leftChild = deleteNode(rootNode.leftChild, nodeValue) elif nodeValue > rootNode.data: rootNode.rightChild = deleteNode(rootNode.rightChild, nodeValue) else: if rootNode.leftChild is None: temp = rootNode.rightChild rootNode = None return temp if rootNode.rightChild is None: temp = rootNode.leftChild rootNode = None return temp temp = minValueNode(rootNode.rightChild) # 從右子樹去找最小的,固定的,假設我們把我要刪除的那個點,當作根節點來看的話 rootNode.data = temp.data #這個最小的直是我們要替換的對象,所以我們會return 他 rootNode.rightChild = deleteNode(rootNode.rightChild, temp.data)# 這個code是要刪掉我們找到的那個最小的直,所以再一次地迴 return rootNode def deleteBST(rootNode): rootNode.data = None rootNode.leftChild = None rootNode.rightChild = None return "The BST has been successfully deleted" newBST = BSTNode(None) insertNode(newBST, 70) insertNode(newBST,50) insertNode(newBST,90) insertNode(newBST, 30) insertNode(newBST,60) insertNode(newBST,80) insertNode(newBST,100) insertNode(newBST,20) insertNode(newBST,40) print(deleteBST(newBST)) levelOrderTraversal(newBST) ```

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully