国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

使用 Go 語言實現二叉搜索樹

開發(fā) 前端
最重要的就是它的有序性,在二叉搜索樹中,每個節(jié)點的值都大于其左子樹中的所有節(jié)點的值,并且小于其右子樹中的所有節(jié)點的值。

二叉樹是一種常見并且非常重要的數據結構,在很多項目中都能看到二叉樹的身影。

它有很多變種,比如紅黑樹,常被用作 std::map 和 std::set 的底層實現;B 樹和 B+ 樹,廣泛應用于數據庫系統(tǒng)中。

本文要介紹的二叉搜索樹用的也很多,比如在開源項目 go-zero 中,就被用來做路由管理。

這篇文章也算是一篇前導文章,介紹一些必備知識,下一篇再來介紹具體在 go-zero 中的應用。

二叉搜索樹的特點

最重要的就是它的有序性,在二叉搜索樹中,每個節(jié)點的值都大于其左子樹中的所有節(jié)點的值,并且小于其右子樹中的所有節(jié)點的值。

圖片圖片

這意味著通過二叉搜索樹可以快速實現對數據的查找和插入。

Go 語言實現

本文主要實現了以下幾種方法:

  • Insert(t):插入一個節(jié)點
  • Search(t):判斷節(jié)點是否在樹中
  • InOrderTraverse():中序遍歷
  • PreOrderTraverse():前序遍歷
  • PostOrderTraverse():后序遍歷
  • Min():返回最小值
  • Max():返回最大值
  • Remove(t):刪除一個節(jié)點
  • String():打印一個樹形結構

下面分別來介紹,首先定義一個節(jié)點:

type Node struct {
    key   int
    value Item
    left  *Node //left
    right *Node //right
}

定義樹的結構體,其中包含了鎖,是線程安全的:

type ItemBinarySearchTree struct {
    root *Node
    lock sync.RWMutex
}

插入操作:

func (bst *ItemBinarySearchTree) Insert(key int, value Item) {
    bst.lock.Lock()
    defer bst.lock.Unlock()
    n := &Node{key, value, nil, nil}
    if bst.root == nil {
        bst.root = n
    } else {
        insertNode(bst.root, n)
    }
}

// internal function to find the correct place for a node in a tree
func insertNode(node, newNode *Node) {
    if newNode.key < node.key {
        if node.left == nil {
            node.left = newNode
        } else {
            insertNode(node.left, newNode)
        }
    } else {
        if node.right == nil {
            node.right = newNode
        } else {
            insertNode(node.right, newNode)
        }
    }
}

在插入時,需要判斷插入節(jié)點和當前節(jié)點的大小關系,保證搜索樹的有序性。

中序遍歷:

func (bst *ItemBinarySearchTree) InOrderTraverse(f func(Item)) {
    bst.lock.RLock()
    defer bst.lock.RUnlock()
    inOrderTraverse(bst.root, f)
}

// internal recursive function to traverse in order
func inOrderTraverse(n *Node, f func(Item)) {
    if n != nil {
        inOrderTraverse(n.left, f)
        f(n.value)
        inOrderTraverse(n.right, f)
    }
}

前序遍歷:

func (bst *ItemBinarySearchTree) PreOrderTraverse(f func(Item)) {
    bst.lock.Lock()
    defer bst.lock.Unlock()
    preOrderTraverse(bst.root, f)
}

// internal recursive function to traverse pre order
func preOrderTraverse(n *Node, f func(Item)) {
    if n != nil {
        f(n.value)
        preOrderTraverse(n.left, f)
        preOrderTraverse(n.right, f)
    }
}

后序遍歷:

func (bst *ItemBinarySearchTree) PostOrderTraverse(f func(Item)) {
    bst.lock.Lock()
    defer bst.lock.Unlock()
    postOrderTraverse(bst.root, f)
}

// internal recursive function to traverse post order
func postOrderTraverse(n *Node, f func(Item)) {
    if n != nil {
        postOrderTraverse(n.left, f)
        postOrderTraverse(n.right, f)
        f(n.value)
    }
}

返回最小值:

func (bst *ItemBinarySearchTree) Min() *Item {
    bst.lock.RLock()
    defer bst.lock.RUnlock()
    n := bst.root
    if n == nil {
        return nil
    }
    for {
        if n.left == nil {
            return &n.value
        }
        n = n.left
    }
}

由于樹的有序性,想要得到最小值,一直向左查找就可以了。

返回最大值:

func (bst *ItemBinarySearchTree) Max() *Item {
    bst.lock.RLock()
    defer bst.lock.RUnlock()
    n := bst.root
    if n == nil {
        return nil
    }
    for {
        if n.right == nil {
            return &n.value
        }
        n = n.right
    }
}

查找節(jié)點是否存在:

func (bst *ItemBinarySearchTree) Search(key int) bool {
    bst.lock.RLock()
    defer bst.lock.RUnlock()
    return search(bst.root, key)
}

// internal recursive function to search an item in the tree
func search(n *Node, key int) bool {
    if n == nil {
        return false
    }
    if key < n.key {
        return search(n.left, key)
    }
    if key > n.key {
        return search(n.right, key)
    }
    return true
}

刪除節(jié)點:

func (bst *ItemBinarySearchTree) Remove(key int) {
    bst.lock.Lock()
    defer bst.lock.Unlock()
    remove(bst.root, key)
}

// internal recursive function to remove an item
func remove(node *Node, key int) *Node {
    if node == nil {
        return nil
    }
    if key < node.key {
        node.left = remove(node.left, key)
        return node
    }
    if key > node.key {
        node.right = remove(node.right, key)
        return node
    }
    // key == node.key
    if node.left == nil && node.right == nil {
        node = nil
        return nil
    }
    if node.left == nil {
        node = node.right
        return node
    }
    if node.right == nil {
        node = node.left
        return node
    }
    leftmostrightside := node.right
    for {
        //find smallest value on the right side
        if leftmostrightside != nil && leftmostrightside.left != nil {
            leftmostrightside = leftmostrightside.left
        } else {
            break
        }
    }
    node.key, node.value = leftmostrightside.key, leftmostrightside.value
    node.right = remove(node.right, node.key)
    return node
}

刪除操作會復雜一些,分三種情況來考慮:

  1. 如果要刪除的節(jié)點沒有子節(jié)點,只需要直接將父節(jié)點中,指向要刪除的節(jié)點指針置為 nil 即可
  2. 如果刪除的節(jié)點只有一個子節(jié)點,只需要更新父節(jié)點中,指向要刪除節(jié)點的指針,讓它指向刪除節(jié)點的子節(jié)點即可
  3. 如果刪除的節(jié)點有兩個子節(jié)點,我們需要找到這個節(jié)點右子樹中的最小節(jié)點,把它替換到要刪除的節(jié)點上。然后再刪除這個最小節(jié)點,因為最小節(jié)點肯定沒有左子節(jié)點,所以可以應用第二種情況刪除這個最小節(jié)點即可

最后是一個打印樹形結構的方法,在實際項目中其實并沒有實際作用:

func (bst *ItemBinarySearchTree) String() {
    bst.lock.Lock()
    defer bst.lock.Unlock()
    fmt.Println("------------------------------------------------")
    stringify(bst.root, 0)
    fmt.Println("------------------------------------------------")
}

// internal recursive function to print a tree
func stringify(n *Node, level int) {
    if n != nil {
        format := ""
        for i := 0; i < level; i++ {
            format += "       "
        }
        format += "---[ "
        level++
        stringify(n.left, level)
        fmt.Printf(format+"%d\n", n.key)
        stringify(n.right, level)
    }
}

單元測試

下面是一段測試代碼:

func fillTree(bst *ItemBinarySearchTree) {
    bst.Insert(8, "8")
    bst.Insert(4, "4")
    bst.Insert(10, "10")
    bst.Insert(2, "2")
    bst.Insert(6, "6")
    bst.Insert(1, "1")
    bst.Insert(3, "3")
    bst.Insert(5, "5")
    bst.Insert(7, "7")
    bst.Insert(9, "9")
}

func TestInsert(t *testing.T) {
    fillTree(&bst)
    bst.String()

    bst.Insert(11, "11")
    bst.String()
}

// isSameSlice returns true if the 2 slices are identical
func isSameSlice(a, b []string) bool {
    if a == nil && b == nil {
        return true
    }
    if a == nil || b == nil {
        return false
    }
    if len(a) != len(b) {
        return false
    }
    for i := range a {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}

func TestInOrderTraverse(t *testing.T) {
    var result []string
    bst.InOrderTraverse(func(i Item) {
        result = append(result, fmt.Sprintf("%s", i))
    })
    if !isSameSlice(result, []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}) {
        t.Errorf("Traversal order incorrect, got %v", result)
    }
}

func TestPreOrderTraverse(t *testing.T) {
    var result []string
    bst.PreOrderTraverse(func(i Item) {
        result = append(result, fmt.Sprintf("%s", i))
    })
    if !isSameSlice(result, []string{"8", "4", "2", "1", "3", "6", "5", "7", "10", "9", "11"}) {
        t.Errorf("Traversal order incorrect, got %v instead of %v", result, []string{"8", "4", "2", "1", "3", "6", "5", "7", "10", "9", "11"})
    }
}

func TestPostOrderTraverse(t *testing.T) {
    var result []string
    bst.PostOrderTraverse(func(i Item) {
        result = append(result, fmt.Sprintf("%s", i))
    })
    if !isSameSlice(result, []string{"1", "3", "2", "5", "7", "6", "4", "9", "11", "10", "8"}) {
        t.Errorf("Traversal order incorrect, got %v instead of %v", result, []string{"1", "3", "2", "5", "7", "6", "4", "9", "11", "10", "8"})
    }
}

func TestMin(t *testing.T) {
    if fmt.Sprintf("%s", *bst.Min()) != "1" {
        t.Errorf("min should be 1")
    }
}

func TestMax(t *testing.T) {
    if fmt.Sprintf("%s", *bst.Max()) != "11" {
        t.Errorf("max should be 11")
    }
}

func TestSearch(t *testing.T) {
    if !bst.Search(1) || !bst.Search(8) || !bst.Search(11) {
        t.Errorf("search not working")
    }
}

func TestRemove(t *testing.T) {
    bst.Remove(1)
    if fmt.Sprintf("%s", *bst.Min()) != "2" {
        t.Errorf("min should be 2")
    }
}

上文中的全部源碼都是經過測試的,可以直接運行,并且已經上傳到了 GitHub,需要的同學可以自取。

源碼地址:

  • https://github.com/yongxinz/go-example
責任編輯:武曉燕 來源: AlwaysBeta
相關推薦

2024-01-17 07:36:50

二叉搜索聯系簿

2022-12-26 00:51:33

雙向鏈表二叉搜索樹

2021-12-07 06:55:17

二叉搜索樹鏈表

2021-08-31 11:35:24

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

2020-10-11 16:56:48

二叉搜索樹代碼開發(fā)

2021-09-02 11:31:28

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

2022-01-11 10:01:25

二叉搜索樹數量

2021-09-03 08:58:00

二叉搜索樹節(jié)點

2020-04-27 07:05:58

二叉樹左子樹右子樹

2020-08-12 08:56:30

代碼凱撒密碼函數

2021-09-07 11:01:41

二叉搜索樹序數組

2021-08-26 11:31:11

二叉樹數據結構算法

2021-04-20 08:37:14

數據結構二叉樹

2023-02-13 08:02:08

哈希函數哈希表搜索樹

2021-10-11 06:38:52

遞歸二叉搜索樹

2021-09-06 10:38:50

二叉搜索樹遞歸

2021-04-06 08:20:24

二叉搜索樹數據結構算法

2020-09-23 18:25:40

算法二叉樹多叉樹

2020-12-22 08:56:51

JavaScript數據結構前端

2009-08-11 13:29:57

C#二叉樹遍歷
點贊
收藏

51CTO技術棧公眾號

黄网站在线免费看| 卡通动漫国产精品| 久久久国产一区二区三区四区小说 | 色综合天天综合给合国产| 国产经典久久久| 日韩中文字幕高清在线观看| 国产亚洲xxx| 日本福利在线| 亚洲午夜日本在线观看| 国产精品自拍片| 久久伊人亚洲| 亚洲a级在线观看| 视频欧美精品| 亚洲精品videossex少妇| 邻居大乳一区二区三区| 亚洲欧美在线视频观看| 欧美乱大交xxxxx潮喷l头像| 蜜桃视频第一区免费观看| 成人18视频| 成人a'v在线播放| 欧美高清视频在线播放| 日韩一区二区三区在线免费观看 | 欧美午夜片在线观看| 国产小黄视频| 久久精品人人做| 男女私大尺度视频| 九色综合狠狠综合久久| 日韩精品久久久毛片一区二区| 欧美成人首页| 亚洲va男人天堂| 97精品在线| 成人免费直播live| 亚洲人成网www| 欧美中文字幕精品| 老司机aⅴ在线精品导航| 欧美裸体xxxx极品少妇| 日本精品久久| www国产精品视频| 黄色精品视频网站| 在线看福利67194| 国内自拍亚洲| 欧美国产日韩一区二区| av日韩一区| 蜜臀久久99精品久久久久久宅男| 欧美高清免费| 久久99久久99精品免观看粉嫩| 欧美视频二区欧美影视| 欧美国产日韩中文字幕在线| 久久久精品区| 欧美在线精品免播放器视频| 九九综合久久| 91精品天堂| 香蕉久久久久久久av网站| 日韩福利视频| 国产99久久久国产精品潘金网站| 少妇人妻无码专区视频| 国产欧美精品国产国产专区| 97中文字幕| 亚洲成人免费影院| 成人不用播放器| 亚洲国产美女久久久久| 国产亚洲欧美日韩精品一区二区三区 | 国产精品网站导航| 人人做人人爽| 色一区在线观看| 超免费在线视频| 夜夜嗨av一区二区三区免费区 | 91.成人天堂一区| 99热99re6国产在线播放| 亚洲图片在线综合| 亚洲精品观看| 91成人免费看| 国产真实乱子伦精品视频| 日韩久久一级片| 天天爽夜夜爽夜夜爽精品视频| 欧美尤物美女在线| 中文字幕在线视频日韩| 国产午夜一区| 日本高清视频一区二区三区 | 国产伦精一区二区三区| 2022亚洲天堂| 欧美性猛交xxxx乱大交蜜桃| 免费看电影在线| 欧美国产日韩视频| 国内精品久久久久久久影视蜜臀| 在线不卡日本| 亚洲人成影院在线观看| 成年人网站在线| 久久影院免费观看| 色一区二区三区四区| 色姑娘综合网| 亚洲天堂精品视频| 少女频道在线观看高清| 欧美高清视频一区二区| 激情久久综合| 久久久久久久久久福利| 精品视频一区三区九区| 国产免费区一区二区三视频免费| 99国产在线| 久久亚洲一级片| 国产大学生校花援交在线播放| 一区二区三区在线播放欧美| 91综合视频| 国产视频一视频二| 在线视频欧美精品| 亚洲国产欧美国产第一区| 成人激情直播| 欧美激情一区二区三区不卡| 成人短视频在线观看| 69久久夜色精品国产69| 日本v片在线高清不卡在线观看| 福利在线免费| 亚洲视频国产视频| 亚洲午夜一级| av日韩在线免费| 国产小视频国产精品| 亚洲国产日韩欧美一区二区三区| 精品久久久久久中文字幕2017| 欧美刺激脚交jootjob| 国产95亚洲| 在线观看精品视频| 欧美亚洲愉拍一区二区| 日韩在线麻豆| 国产亚洲综合视频| 精品国产伦理网| 欧美先锋影音| 国产超碰精品在线观看| 欧美精品在线第一页| 国产最新精品免费| 黄色av电影在线观看| 成人av资源在线播放| 国产精品狼人久久影院观看方式| 一区一区三区| 四虎永久国产精品| 欧美午夜精品一区二区三区| 精品视频黄色| 成人毛片免费在线观看| 日韩网站在线观看| 国产一区二区不卡老阿姨| 99热国产在线| 国产无套精品一区二区| 欧美视频在线观看免费| 亚洲精品推荐| 99在线免费观看| 97av视频在线| 国产精品乱子久久久久| 亚洲1区在线观看| 免费观看日韩毛片| 久久亚洲精品一区二区| www.日韩在线| 亚洲美女色播| 黄色片一级视频| 欧美成人在线影院| 国产亚洲欧美中文| 日韩视频一区二区三区四区| www精品久久| 色七七影院综合| 91亚洲大成网污www| 色香欲www7777综合网| 桥本有菜av在线| 亚洲人在线视频| 国产v综合v亚洲欧| 成人国产一区二区三区精品麻豆| 国产成人亚洲综合无码| 一区二区三区四区视频| 99精品视频在线播放观看| 久久99久久久精品欧美| 青青草原av在线播放| 欧美日韩ab片| 综合久久给合久久狠狠狠97色| 欧美三级自拍| 88av在线| 成人看片视频| 欧美videossexotv100| 国内一区二区视频| 福利一区二区三区视频在线观看| 久久婷婷五月综合色国产香蕉| 欧美日本高清视频| 亚洲一卡二卡三卡四卡五卡| 国产在线成人| 黄在线观看免费网站ktv| 拔插拔插海外华人免费| 97精品国产97久久久久久春色| 樱花草国产18久久久久| 亚洲欧美综合国产精品一区| 黄网页免费在线观看| 国产精品视频一二三四区| 欧美日本啪啪无遮挡网站| 一区二区三区日韩精品视频| 欧美视频四区| 国产精品一区二区av影院萌芽| 国产成人无码av在线播放dvd| 热99精品里视频精品| 欧美日韩国产一级| 国产成人在线电影| 久久99国产精品视频| caopon在线免费视频| 男人天堂网视频| www 成人av com| 日韩中文在线视频|