golang数据结构 红黑树 | 青训营笔记

70 阅读2分钟

在搜索和排序数据时,最基本的数据结构之一是二叉搜索树。然而,二叉搜索树的性能高度依赖于它的形状,在最坏的情况下,它可以退化为时间复杂度为 O(n) 的线性结构。这就是红黑树的用武之地,它们是一种平衡的二叉搜索树,它使用一组特定的规则来确保树始终是平衡的。这种平衡保证了插入、删除和搜索等操作的时间复杂度始终为 O(log n),而不管树的初始形状如何。

红黑树是自平衡的,这意味着树会在每次插入或删除操作后自动调整自身。它使用一种简单但强大的机制来保持平衡,方法是将树中的每个节点着色为红色或黑色。

红黑树是一种二叉搜索树,其中每个节点都用红色或黑色着色。它是一种自平衡二叉搜索树。它具有良好高效的最坏情况运行时间复杂度。

大多数 BST 操作(例如,搜索、最大、最小、插入、删除等)需要 O(h) 时间,其中 h 是 BST 的高度。对于倾斜的二叉树,这些操作的成本可能变为 O(n)。如果我们确保在每次插入和删除之后树的高度保持为 O(log n),那么我们可以保证所有这些操作的上界为 O(log n)。红黑树的高度总是 O(log n),其中 n 是树中的节点数。


import (
    rbt "github.com/emirpasic/gods/trees/redblacktree"
)

type TweetCounts struct {
    counts map[string]*rbt.Tree
}

func Constructor() TweetCounts {
    return TweetCounts{
        counts: map[string]*rbt.Tree{},
    }
}

func (this *TweetCounts) RecordTweet(tweetName string, time int)  {
    if _, ok := this.counts[tweetName]; !ok {
        this.counts[tweetName] = rbt.NewWithIntComparator()
    }
    
    counts, _ := this.counts[tweetName]

    if oldCountVal, ok := counts.Get(time); ok {
        counts.Put(time, oldCountVal.(int) + 1)
    } else {
        counts.Put(time, 1)
    }
}

func (this *TweetCounts) GetTweetCountsPerFrequency(freq string, tweetName string, startTime int, endTime int) []int {
    k := 1
    
    switch freq {
    case "minute":
        k = 60
    case "hour":
        k = 3600
    case "day":
        k = 86400
    }
    
    buckets := make([]int, (endTime - startTime) / k + 1)

    counts, ok := this.counts[tweetName]
    if !ok {
        return buckets
    }
    ceilingNode, ok := counts.Ceiling(startTime)
    if !ok {
        return buckets
    }
    
    for it := counts.IteratorAt(ceilingNode); ; {
        t := it.Key().(int)
        count := it.Value().(int)
        
        if t > endTime {
            break
        }
        
        buckets[(t - startTime) / k] += count
        
        if !it.Next() {
            break
        }
    }

    return buckets
}