Golang | 集合求交

文章目录

bitmap求交集


2个有序链表

多个有序链表

  • 为什么非最大的所有都要往后移动呢?因为现在已经知道交集即使有,也最小都是这个目前最大的了,其他不是最大的不可能是交集,所有除了最大其他都往后移动就行

跳表

  • 跳表(Skip List)是一种用于高效查找、插入和删除有序元素的数据结构,结合了链表和二分查找的思想,空间换时间。它通过构建多层链表来实现快速搜索,平均时间复杂度为 O(logn),且实现比平衡树更简单。
  • 多层链表结构:
    • 底层是完整的有序链表,包含所有元素。
    • 每一层都是下一层的"快速通道",节点随机晋升到更高层,形成类似"索引"的结构。
    • 高层节点稀疏,低层节点密集。
  • 随机晋升:
    • 插入新节点时,通过随机算法(如抛硬币)决定晋升到多少层。
    • 晋升概率通常为1/2,即每个节点有 50% 的概率出现在上一层。


go 复制代码
package main

import (
	"fmt"
	"math/rand"
	"time"
)

const (
	MaxLevel    = 16   // 跳表的最大层数
	Probability = 0.5  // 每增加一层的概率
)

// 节点结构
type Node struct {
	value int
	next  []*Node
}

// 跳表结构
type SkipList struct {
	head  *Node
	level int
}

// 创建新节点
func newNode(value, level int) *Node {
	return &Node{
		value: value,
		next:  make([]*Node, level),
	}
}

// 创建跳表
func NewSkipList() *SkipList {
	rand.Seed(time.Now().UnixNano())
	return &SkipList{
		head:  newNode(0, MaxLevel),
		level: 1,
	}
}

// 随机层数
func (sl *SkipList) randomLevel() int {
	level := 1
	for rand.Float64() < Probability && level < MaxLevel {
		level++
	}
	return level
}

// 查找
func (sl *SkipList) Search(target int) bool {
	curr := sl.head
	for i := sl.level - 1; i >= 0; i-- {
		for curr.next[i] != nil && curr.next[i].value < target {
			curr = curr.next[i]
		}
	}
	curr = curr.next[0]
	return curr != nil && curr.value == target
}

// 插入
func (sl *SkipList) Insert(value int) {
	update := make([]*Node, MaxLevel)
	curr := sl.head

	for i := sl.level - 1; i >= 0; i-- {
		for curr.next[i] != nil && curr.next[i].value < value {
			curr = curr.next[i]
		}
		update[i] = curr
	}

	level := sl.randomLevel()
	if level > sl.level {
		for i := sl.level; i < level; i++ {
			update[i] = sl.head
		}
		sl.level = level
	}

	newNode := newNode(value, level)
	for i := 0; i < level; i++ {
		newNode.next[i] = update[i].next[i]
		update[i].next[i] = newNode
	}
}

// 打印跳表(调试用)
func (sl *SkipList) Print() {
	for i := sl.level - 1; i >= 0; i-- {
		curr := sl.head.next[i]
		fmt.Printf("Level %d: ", i+1)
		for curr != nil {
			fmt.Printf("%d ", curr.value)
			curr = curr.next[i]
		}
		fmt.Println()
	}
}

func main() {
	sl := NewSkipList()
	sl.Insert(1)
	sl.Insert(3)
	sl.Insert(5)
	sl.Insert(7)
	sl.Insert(9)

	sl.Print()

	fmt.Println("Search 5:", sl.Search(5))  // true
	fmt.Println("Search 6:", sl.Search(6))  // false
}
  • 两跳表求交集
go 复制代码
func IntersectionOfSkipList(lists ...*skiplist.SkipList) (res *skiplist.SkipList) {
	if len(lists) == 0 {
		return nil
	}
	if len(lists) == 1 {
		return lists[0]
	}

	res = skiplist.New(skiplist.Uint64)
	nodes := make([]*skiplist.Element, len(lists))
	for i, list := range lists {
		if list == nil || list.Len() == 0 {
			return nil
		}
		nodes[i] = list.Front()
	}

	for {
		var maxList map[int]struct{} // 用于存储当前值最大的节点(可能有多个,所以用map来模仿集合)
		var maxValue uint64 = 0
		for i, node := range nodes {
			if node.Key().(uint64) > maxValue {
				maxValue = node.Key().(uint64)
				maxList = map[int]struct{}{i: {}}
			} else if node.Key().(uint64) == maxValue {
				maxList[i] = struct{}{}
			}
		}
		if len(maxList) == len(lists) { // 所有node节点都指向了最大值,可以添加到交集
			res.Set(nodes[0].Key(), nodes[0].Value)
			for i, node := range nodes { // 所有node节点往后移
				nodes[i] = node.Next()
				if nodes[i] == nil {
					return
				}
			}
		} else {
			for i, node := range nodes {
				if _, exists := maxList[i]; !exists {
					nodes[i] = node.Next()
					if nodes[i] == nil {
						return
					}
				}
			}
		}
	}
}

go 复制代码
func (sl *SkipList) Intersection(other *SkipList) []int {
	result := []int{}

	// 从最底层第一个节点开始
	p1 := sl.head.next[0]
	p2 := other.head.next[0]

	for p1 != nil && p2 != nil {
		if p1.value == p2.value {
			result = append(result, p1.value)
			p1 = p1.next[0]
			p2 = p2.next[0]
		} else if p1.value < p2.value {
			p1 = p1.next[0]
		} else {
			p2 = p2.next[0]
		}
	}

	return result
}


// 加速查找


// Search查找一个元素,返回是否存在
func (sl *SkipList) Search(value int) bool {
	curr := sl.head
	for i := sl.level - 1; i >= 0; i-- {
		for curr.next[i] != nil && curr.next[i].value < value {
			curr = curr.next[i]
		}
	}
	curr = curr.next[0]
	return curr != nil && curr.value == value
}

// 交集(基于快速查找)
func (sl1 *SkipList) IntersectionWith(sl2 *SkipList) []int {
	result := []int{}

	curr := sl2.head.next[0] // 遍历第二个跳表的底层节点
	for curr != nil {
		if sl1.Search(curr.value) { // 用第一个跳表查找
			result = append(result, curr.value)
		}
		curr = curr.next[0]
	}

	return result
}
  • 多跳表求交集
go 复制代码
// Search查找一个元素,返回是否存在
func (sl *SkipList) Search(value int) bool {
	curr := sl.head
	for i := sl.level - 1; i >= 0; i-- {
		for curr.next[i] != nil && curr.next[i].value < value {
			curr = curr.next[i]
		}
	}
	curr = curr.next[0]
	return curr != nil && curr.value == value
}

// 多跳表交集(基于跳表加速查找)
func IntersectionSkipLists(lists []*SkipList) []int {
	if len(lists) == 0 {
		return []int{}
	}
	if len(lists) == 1 {
		// 只有一个跳表,直接返回所有元素
		result := []int{}
		curr := lists[0].head.next[0]
		for curr != nil {
			result = append(result, curr.value)
			curr = curr.next[0]
		}
		return result
	}

	// 1. 找到元素最少的跳表作为主跳表
	mainList := lists[0]
	for _, sl := range lists[1:] {
		if sl.Size() < mainList.Size() {
			mainList = sl
		}
	}

	// 2. 依次遍历主跳表的元素
	result := []int{}
	curr := mainList.head.next[0]
	for curr != nil {
		found := true
		for _, sl := range lists {
			if sl == mainList {
				continue
			}
			if !sl.Search(curr.value) {
				found = false
				break
			}
		}
		if found {
			result = append(result, curr.value)
		}
		curr = curr.next[0]
	}
	return result
}

// Size 计算跳表元素数量
func (sl *SkipList) Size() int {
	cnt := 0
	curr := sl.head.next[0]
	for curr != nil {
		cnt++
		curr = curr.next[0]
	}
	return cnt
}
相关推荐
阳光_你好1 小时前
简单介绍C++中线性代数运算库Eigen
开发语言·c++·线性代数
菠萝崽.2 小时前
RabbitMQ高级篇-MQ的可靠性
java·分布式·后端·消息队列·rabbitmq·异步编程
你采不起的野花5 小时前
Go 语言 vs C+Lua(Skynet)游戏服务器方案对比分析
游戏·golang·lua
风逸hhh5 小时前
python打卡day29@浙大疏锦行
开发语言·前端·python
ᖰ・◡・ᖳ5 小时前
JavaScript:PC端特效--缓动动画
开发语言·前端·javascript·css·学习·html5
hy____1236 小时前
C++多态的详细讲解
开发语言·c++
小葡萄20256 小时前
黑马程序员C++2024版笔记 第0章 C++入门
开发语言·c++·笔记
键盘客6 小时前
Spring Boot 配置明文密码加密,防泄漏
java·spring boot·后端·spring
万物此臻6 小时前
C#编写软件添加菜单栏
开发语言·c#
RongSen336 小时前
Python海龟绘图(Turtle Graphics)核心函数和关键要点
开发语言·python