golang非算法手撕实现总结
主要是给自己看,里面内容可能错的挺多的,写错的地方大佬们可以说一下
1.交叉打印123
1.1 使用同步channel
package main
import (
"fmt"
"sync"
)
func main() {
n := 5
ch1 := make(chan struct{})
ch2 := make(chan struct{})
ch3 := make(chan struct{})
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
for range ch1 {
fmt.Print("1")
ch2 <- struct{}{}
}
close(ch2)
}()
go func() {
defer wg.Done()
for range ch2 {
fmt.Print("2")
ch3 <- struct{}{}
}
close(ch3)
}()
go func() {
defer wg.Done()
for i := 0; i < n; i++ {
<-ch3
fmt.Print("3")
if i == n-1 {
close(ch1) // 安全地只关闭 ch1,触发所有退出
} else {
ch1 <- struct{}{}
}
}
}()
ch1 <- struct{}{} // 启动第一个
wg.Wait()
fmt.Println()
}
1.2 使用sync.cond
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var mu sync.Mutex
cond := sync.NewCond(&mu)
turn := 0
printFunc := func(id int, label string) {
defer wg.Done()
for i := 0; i < 100; i++ {
cond.L.Lock()
for turn != id {
cond.Wait()
}
fmt.Println(label)
turn = (turn + 1) % 3
cond.Broadcast()
cond.L.Unlock()
}
}
wg.Add(3)
go printFunc(0, "1")
go printFunc(1, "2")
go printFunc(2, "3")
wg.Wait()
}
2.单例模式,懒汉饿汉
2.1 懒汉式,sync.Once
package main
import (
"fmt"
"sync"
)
var (
lazySingletonInstance *Singleton
lazySingletonOnce sync.Once
)
type Singleton struct {
name string
}
func getSingleton() *Singleton {
lazySingletonOnce.Do(func() {
lazySingletonInstance = &Singleton{
name: "Singleton",
}
})
return lazySingletonInstance
}
func main() {
s1 := getSingleton()
s2 := getSingleton()
fmt.Printf("%p,%p", s1, s2)
}
2.2 饿汉式
package main
import "fmt"
var EagerSingelton = &Singleton{name: "singleton"}
type Singleton struct {
name string
}
func getSingleton() *Singleton {
return EagerSingelton
}
func main() {
s1 := getSingleton()
s2 := getSingleton()
fmt.Printf("%p,%p", s1, s2)
}
3.限流算法
3.1 滑动窗口
package main
import (
"fmt"
"sync"
"time"
)
type SlidingWindowLimiter struct {
limit int // 最大请求数
window time.Duration // 窗口大小
count int // 当前窗口计数
lastWindow time.Time // 当前窗口起始时间
lock sync.Mutex
}
func NewSlidingWindowLimiter(limit int, window time.Duration) *SlidingWindowLimiter {
return &SlidingWindowLimiter{
limit: limit,
window: window,
lastWindow: time.Now(),
}
}
func (s *SlidingWindowLimiter) Allow() bool {
s.lock.Lock()
defer s.lock.Unlock()
now := time.Now()
if now.Sub(s.lastWindow) >= s.window {
// 新窗口,重置计数
s.count = 0
s.lastWindow = now
}
if s.count >= s.limit {
return false
}
s.count++
return true
}
func main() {
limiter := NewSlidingWindowLimiter(5, 2*time.Second) // 2秒最多5次
for i := 1; i <= 15; i++ {
if limiter.Allow() {
fmt.Println(i, "允许")
} else {
fmt.Println(i, "限流")
}
time.Sleep(300 * time.Millisecond)
}
}
3.2 令牌桶
package main
import (
"fmt"
"time"
)
var (
ratePerSec = 2
buckets = make(chan struct{}, ratePerSec)
)
func main() {
// 生成令牌
go func() {
ticker := time.NewTicker(time.Second / time.Duration(ratePerSec))
for range ticker.C {
select {
case buckets <- struct{}{}:
default:
// 桶满就丢弃
}
}
}()
// 模拟请求
for i := 0; i < 20; i++ {
select {
case <-buckets:
fmt.Println(time.Now().Format("15:04:05.000"), "请求", i, "允许")
default:
fmt.Println(time.Now().Format("15:04:05.000"), "请求", i, "被限流")
}
time.Sleep(time.Millisecond * 300)
}
}
3.3 漏桶
package main
import (
"fmt"
"sync"
"time"
)
type leakyBucktes struct {
cap float64
rate float64
current float64
lastTime time.Time
lock sync.Mutex
}
func NewLeakyBuckets(cap, rate float64) *leakyBucktes {
return &leakyBucktes{
cap: cap,
rate: rate,
lastTime: time.Now(),
}
}
func (this *leakyBucktes) Allow() bool {
fmt.Println(this.current)
this.lock.Lock()
defer this.lock.Unlock()
elapsed := time.Now().Sub(this.lastTime).Seconds()
leaked := elapsed * this.rate
if this.current-float64(leaked) < 0 {
this.current = 0
} else {
this.current -= float64(leaked)
}
this.lastTime = time.Now()
if this.current < this.cap {
this.current++
return true
} else {
return false
}
}
func main() {
cap := 5.0
rate := 2.0 // 每秒漏掉2个
tick := 300 * time.Millisecond
bucket := NewLeakyBuckets(cap, rate)
for i := 0; i < 50; i++ {
if bucket.Allow() {
fmt.Printf("Allow %2d | current=%.2f\n", i, bucket.current)
} else {
fmt.Printf("Reject %2d | current=%.2f\n", i, bucket.current)
}
time.Sleep(tick)
}
}
4.带TTL的LRU算法
package main
import (
"fmt"
"time"
)
type DlinkNode struct {
Key, Val int
Pre, Next *DlinkNode
ExpireAt time.Time // 过期时间
}
type LRUCache struct {
cache map[int]*DlinkNode
size int
cap int
head, tail *DlinkNode
ttl time.Duration // 全局 TTL
}
// 初始化双向链表节点
func initDLinkNode(key, val int) *DlinkNode {
return &DlinkNode{
Key: key,
Val: val,
}
}
// 初始化缓存
func Constructor(capacity int, ttl time.Duration) LRUCache {
cache := map[int]*DlinkNode{}
head, tail := initDLinkNode(0, 0), initDLinkNode(0, 0)
head.Next = tail
tail.Pre = head
return LRUCache{
cache: cache,
head: head,
tail: tail,
cap: capacity,
ttl: ttl,
}
}
// Get 获取键值(带懒删除)
func (this *LRUCache) Get(key int) int {
if node, ok := this.cache[key]; ok {
// 检查是否过期
if time.Now().After(node.ExpireAt) {
this.removeNode(node)
delete(this.cache, key)
this.size--
return -1
}
this.moveToHead(node)
return node.Val
}
return -1
}
// Put 插入或更新键值
func (this *LRUCache) Put(key int, value int) {
if node, ok := this.cache[key]; ok {
node.Val = value
node.ExpireAt = time.Now().Add(this.ttl)
this.moveToHead(node)
} else {
node := initDLinkNode(key, value)
node.ExpireAt = time.Now().Add(this.ttl)
this.addToHead(node)
this.cache[key] = node
this.size++
}
// 懒删除 + 容量控制
for this.size > this.cap {
k := this.removeTail()
delete(this.cache, k)
this.size--
}
}
// moveToHead 移动到头部
func (this *LRUCache) moveToHead(node *DlinkNode) {
this.removeNode(node)
this.addToHead(node)
}
// addToHead 插入头部
func (this *LRUCache) addToHead(node *DlinkNode) {
node.Pre = this.head
node.Next = this.head.Next
this.head.Next.Pre = node
this.head.Next = node
}
// removeNode 移除节点
func (this *LRUCache) removeNode(node *DlinkNode) {
node.Pre.Next = node.Next
node.Next.Pre = node.Pre
}
// removeTail 移除尾节点
func (this *LRUCache) removeTail() int {
node := this.tail.Pre
this.removeNode(node)
return node.Key
}
func main() {
cache := Constructor(2, 3*time.Second)
cache.Put(1, 1)
cache.Put(2, 2)
fmt.Println(cache.Get(1))
time.Sleep(4 * time.Second)
fmt.Println(cache.Get(1))
cache.Put(3, 3)
fmt.Println(cache.Get(2))
fmt.Println(cache.Get(3))
}
#手撕题#