操操操

跳跃表Golang版本

2023-08-20
1分钟阅读时长

跳跃表

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

type Node struct {
	key                   int
	value                 interface{}
	up, down, left, right *Node
	level                 int
}

func newNode(k int, v interface{}) *Node {
	return &Node{
		key:   k,
		value: v,
	}
}

func (n *Node) equals(node *Node) bool {
	if node == nil {
		return false
	}
	if n.key != node.key {

		return false
	}
	if n.value != node.value {

		return false
	}
	if n.level != node.level {
		return false
	}
	return true
}

// 实现跳跃表
type jumpTable struct {
	header *Node
	r      *rand.Rand
}

func New() *jumpTable {
	return &jumpTable{
		r:      rand.New(rand.NewSource(time.Now().UnixNano())),
		header: newNode(-int(^uint(0)>>1), nil),
	}
}

func println(input string) {
	return fmt.Println(input)
}

func (jt *jumpTable) Search(k int) *Node {
	println("walkPreviousNode")
	node, count := walkPreviousNode(jt.header, k)
	println("共需要", count, "步")
	return node
}

func (jt *jumpTable) Insert(k int, v interface{}) {
	sn := jt.header
	newN := newNode(k, v)
	node, _ := walkPreviousNode(sn, k)
	if node.key == k {

		node.value = v
		return
	}
	currentLevel := 0
	newN.level = currentLevel
	jt.setNode(newN, node)
	lowNode := newN
	for jt.isPromotion() {
		println("isPromotion")
		currentLevel++
		upNewN := setUpNewDownNode(currentLevel, k, newN)
		if jt.header.level < currentLevel {
			updateHeader(jt, upNewN)
		}
		leftUpNode := findLeftUpNode(lowNode, upNewN)
		if leftUpNode != nil {
			jt.setNode(upNewN, leftUpNode)
		}
		newN = upNewN
	}
}

func updateHeader(jt *jumpTable, upNew *Node) {
	jt.header = upNew
}

func setUpNewDownNode(level int, k int, v interface{}, newN *Node) *Node {
	upNew := newNode(k, v)
	upNew.level = level
	newN.up = upNew
	upNew.down = newN
	return upNew
}

func findLeftUpNode(newN *Node, upNew *Node) *Node {
	var leftUpNode *Node
	leftNewNode := newN.left
leftBreak:
	for leftNewNode != nil {
		leftNewUpNode := leftNewNode.up
		for leftNewUpNode != nil {
			if leftNewUpNode.level == upNew.level {

				leftUpNode = leftNewUpNode
				break leftBreak
			}
			leftNewNode = leftNewNode.left
		}
	}
	return leftUpNode
}

func (jt *jumpTable) setNode(q *Node, p *Node) {
	q.left = p
	if p.right != nil {
		q.right = p.right
		p.right.left = q
	}
	p.right = q
}

func walkPreviousNode(curNode *Node, k int) (*Node, int) {
	println("k:", k, " level", curNode.level)
	count := 0
	for curNode.key < k {
		count++
		if curNode.right == nil {
			break
		}
		println("curNode.key < k ", curNode.key, "-->", curNode.right.key)
		curNode = curNode.right
	}
	for curNode.key > k {
		count++
		if curNode.left == nil {
			break
		}
		println("curNode.key > k ", curNode.key, "-->", curNode.left.key)
		curNode = curNode.left
	}
	if curNode.down != nil {
		var newCount int
		println("curNode.down ", curNode.key, "-->", curNode.down.key)
		curNode, newCount = walkPreviousNode(curNode.down, k)
		count += newCount
	}
	return curNode, count
}

func (jt *jumpTable) isPromotion() bool {
	n := jt.r.Intn(2)
	if n == 0 {
		return false
	}
	return true
}
Avatar

Aisen

Be water,my friend.