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)) 
}

#手撕题#
全部评论
写的好垃圾
点赞 回复 分享
发布于 10-11 17:20 安徽

相关推荐

评论
2
11
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务