のバイナリ検索ツリー
48958 ワード
大学でBSTを作ることを学んだので、ずっと.私はBSTのものを再訪したいと思うので、私はこのポストを作ります.BSTは怖いです.各ノードに値を重複させずにツリーを作成する必要があるだけで、より貴重なノードが左側に移動し、ノードの残りが右または逆に移動します.この記事では、整数の価値の少ないノードが左側に移動し、go言語でBSTを作ります.go languageとtreeデータ構造の基本的な知識を持っていると思います.
ディレクトリ構造
$ tree
.
├── bst
│ ├── node.go
│ └── tree.go
├── go.mod
└── main.go
使用するtree
コマンドをディレクトリ構造をダウンリストを表示します.コード
を作りましょう
node struct
ファーストインサイドnode.go
ファイル.type node struct {
value int
left, right *node
}
func newNode(value int) *node {
return &node{
value: val,
left: nil,
right: nil,
}
}
func (n *node) Value() int {
return n.value
}
func (n *node) Left() *node {
return n.left
}
func (n *node) Right() *node {
return n.right
}
私はそれをエクスポートしないようにuser
使えないnode struct
データの変異性を避けるために直接getter functions
.それから
binarySearchTree struct
インサイドtree.go
の使用をラップするファイルnode
. ITストアpointer of node struct
としてroot
それで、我々は木の根を追跡することができます.type binarySearchTree struct {
root *node
}
func New() *binarySearchTree {
return &binarySearchTree{}
}
現在のコードでは、このようにBSTを作成できますmain function
.func main() {
tree := bst.New()
}
今、私たちは木にいくつかの機能性を与えますinsert
, find
, traverse
, and remove
. レッツゴー・ウィズinsert
ファースト.擬似コードはこのようになります.If there's no node, then create a new node.
If a node with same value is already exists inside the tree, returns error.
If the value is greater than current node's value, then insert to the right.
If the value is less than current node's value, then insert to the left.
関数を再帰的にし、ツリーの値を直接変更しません.それで、エラーが起こったならば、木は同じままです.func insertNode(node *node, val int) (*node, error) {
// if there's no node, create one
if node == nil {
return newNode(val), nil
}
if node.value == val {
// if there's duplicated node returns error
return nil, ErrDuplicatedNode
}
if val > node.value {
// if value is greater than current node's value, insert to the right
right, err := insertNode(node.right, val)
if err != nil {
return nil, err
}
node.right = right
} else if val < node.value {
// if value is less than current node's value, insert to the left
left, err := insertNode(node.left, val)
if err != nil {
return nil, err
}
node.left = left
}
return node, nil
}
その機能をユーザーに公開しましょうbinarySearchTree struct
.func (tree *binarySearchTree) Insert(val int) error {
// always start insert from the root
root, err := insertNode(tree.root, val)
if err != nil {
return err
}
tree.root = root
return nil
}
入力した値が正しい位置にあるかどうかを確認するには、まずトラバース関数を作成します.ツリーを横断する3つの方法があります.pre-order
, in-order
, and post-order
. 以下は違いです.# pre-order
1. print current value
2. go recursively to the left
3. go recursively to the right
# in-order
1. go recursively to the left
2. print current value
3. go recursively to the right
# post-order
1. go recursively to the left
2. go recursively to the right
3. print current value
簡単に覚えて、現在の値を印刷する必要があるときに覚えておいてください.if pre
次に最初に印刷するpost
そして最後に印刷し、そうでなければ中央に印刷する.私達はgonna作るin order traverse
, それは最初に左へ再帰的に行きます、そして、次に、それが印刷する我々のケースで意味する値を印刷しますfrom least valuable nodes to the greatest
.func traverse(node *node) {
// exit condition
if node == nil {
return
}
traverse(node.left)
fmt.Println(node.value)
traverse(node.right)
}
func (tree *binarySearchTree) Traverse() {
// traverse from the root
traverse(tree.root)
}
まずコードをチェックしましょう.func main() {
tree := bst.New()
tree.Insert(23)
tree.Insert(10)
tree.Insert(15)
tree.Insert(20)
tree.Insert(2)
tree.Insert(25)
tree.Insert(50)
tree.Traverse() // 2 10 15 20 23 25 50
}
今、あなたはあなたを見つけるtraverse
結果はソートされますfind
関数.ツリー全体を移動する必要がない特定のノードを見つけるには、BSTがノード値をチェックすることによって特定のノードにルーティングできることを知る必要があります.と同じようにinsert
関数は、ノードの値が大きければ、ノードの値が現在のノードよりも右側であれば左側に移動する必要があります.func findNode(node *node, val int) *node {
if node == nil {
return nil
}
// if the node is found, return the node
if node.value == val {
return node
}
// if value is greater than current node's value, search recursively to the right
if val > node.value {
return findNode(node.right, val)
}
// if value is less than current node's value, search recursively to the left
if val < node.value {
return findNode(node.left, val)
}
return nil
}
func (tree *binarySearchTree) Find(val int) *node {
// as always, search from the root
return findNode(tree.root, val)
}
指定された値を持つノードがあれば、指定したノードを返します.我々はノード属性をカプセル化して、ゲッター機能だけでユーザを残すので、データの変異性を心配する必要はありません.さあ、へ移動しましょう
remove
関数.まさにinsert
and find
関数は、ノードの位置を最初に見つけ、削除する必要があります.ツリーからノードを削除する3つの規則があります.If the node has no child, then Simply make it nil
If the node has 1 child, then move the child to the node position.
If the node has 2 children, then find the successor and move the successor to the node position.
ノードの後継者を見つけるには2つの方法がありますFind the least valueable node from the right child of the node
OR
Find the greatest valueable node from the left child of the node
最初のアプローチを使います.find the least valuable node of the right child node
. 現在のノードから最低限のノードを見つけるには、一番左のノードに移動する必要があります.そして、現在のノードの最も価値あるノードを見つけるために、ちょうど一番右のノードに行ってください.func least(node *node) *node {
if node == nil {
return nil
}
if node.left == nil {
return node
}
return least(node.left)
}
func removeNode(node *node, val int) (*node, error) {
if node == nil {
return nil, ErrNodeNotFound
}
if val > node.value {
right, err := removeNode(node.right, val)
if err != nil {
return nil, err
}
node.right = right
} else if val < node.value {
left, err := removeNode(node.left, val)
if err != nil {
return nil, err
}
node.left = left
} else {
if node.left != nil && node.right != nil {
// has 2 children
// find the successor
successor := least(node.right)
value := successor.value
// remove the successor
right, err := removeNode(node.right, value)
if err != nil {
return nil, err
}
node.right = right
// copy the successor value to the current node
node.value = value
} else if node.left != nil || node.right != nil {
// has 1 child
// move the child position to the current node
if node.left != nil {
node = node.left
} else {
node = node.right
}
} else if node.left == nil && node.right == nil {
// has no child
// simply remove the node
node = nil
}
}
return node, nil
}
それはすべて、人々です.私がコードを抑制するならば、それはこれのようです.ノード。試み
package bst
import (
"errors"
"fmt"
)
var (
ErrDuplicatedNode error = errors.New("bst: found duplicated value on tree")
ErrNodeNotFound error = errors.New("bst: node not found")
)
type node struct {
value int
left, right *node
}
func (n *node) Value() int {
return n.value
}
func (n *node) Left() *node {
return n.left
}
func (n *node) Right() *node {
return n.right
}
func newNode(val int) *node {
return &node{
value: val,
left: nil,
right: nil,
}
}
func insertNode(node *node, val int) (*node, error) {
// if there's no node, create one
if node == nil {
return newNode(val), nil
}
if node.value == val {
// if there's duplicated node returns error
return nil, ErrDuplicatedNode
}
if val > node.value {
// if value is greater than current node's value, insert to the right
right, err := insertNode(node.right, val)
if err != nil {
return nil, err
}
node.right = right
} else if val < node.value {
// if value is less than current node's value, insert to the left
left, err := insertNode(node.left, val)
if err != nil {
return nil, err
}
node.left = left
}
return node, nil
}
func removeNode(node *node, val int) (*node, error) {
if node == nil {
return nil, ErrNodeNotFound
}
if val > node.value {
right, err := removeNode(node.right, val)
if err != nil {
return nil, err
}
node.right = right
} else if val < node.value {
left, err := removeNode(node.left, val)
if err != nil {
return nil, err
}
node.left = left
} else {
if node.left != nil && node.right != nil {
// has 2 children
// find the successor
successor := least(node.right)
value := successor.value
// remove the successor
right, err := removeNode(node.right, value)
if err != nil {
return nil, err
}
node.right = right
// copy the successor value to the current node
node.value = value
} else if node.left != nil || node.right != nil {
// has 1 child
// move the child position to the current node
if node.left != nil {
node = node.left
} else {
node = node.right
}
} else if node.left == nil && node.right == nil {
// has no child
// simply remove the node
node = nil
}
}
return node, nil
}
func findNode(node *node, val int) *node {
if node == nil {
return nil
}
// if the node is found, return the node
if node.value == val {
return node
}
// if value is greater than current node's value, search recursively to the right
if val > node.value {
return findNode(node.right, val)
}
// if value is less than current node's value, search recursively to the left
if val < node.value {
return findNode(node.left, val)
}
return nil
}
func least(node *node) *node {
if node == nil {
return nil
}
if node.left == nil {
return node
}
return least(node.left)
}
func traverse(node *node) {
// exit condition
if node == nil {
return
}
traverse(node.left)
fmt.Println(node.value)
traverse(node.right)
}
ツリー試み
package bst
type binarySearchTree struct {
root *node
}
func New() *binarySearchTree {
return &binarySearchTree{}
}
func (tree *binarySearchTree) Insert(val int) error {
// always start insert from the root
root, err := insertNode(tree.root, val)
if err != nil {
return err
}
tree.root = root
return nil
}
func (tree *binarySearchTree) Remove(val int) error {
root, err := removeNode(tree.root, val)
if err != nil {
return err
}
tree.root = root
return nil
}
func (tree *binarySearchTree) Find(val int) *node {
// as always, search from the root
return findNode(tree.root, val)
}
func (tree *binarySearchTree) Traverse() {
// traverse from the root
traverse(tree.root)
}
メイン.試み
package main
import (
"learn/bst"
)
func main() {
tree := bst.New()
tree.Insert(23)
tree.Insert(10)
tree.Insert(15)
tree.Remove(10)
tree.Insert(20)
tree.Insert(2)
tree.Insert(25)
tree.Remove(25)
tree.Remove(23)
tree.Insert(50)
tree.Traverse() // 2 15 20 50
}
お読みありがとうございます.Reference
この問題について(のバイナリ検索ツリー), 我々は、より多くの情報をここで見つけました https://dev.to/clavinjune/binary-search-tree-in-go-4hffテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol