您的位置:首页 > 编程语言 > Go语言

golang 实现 二分查找 差值差值 红黑树查找算法

2019-08-06 14:34 411 查看
原文链接:https://blog.csdn.net/qq_25870633/article/details/82705217
这几个查找算法其实放在一根文件里面都可以但是为了可读性比较高一些我就分别放了

lookup.go 入口文件

package helper

//二分查找 有序查找
func binarySearch4(arr []int, k int) int {
low := 0
high := len(arr) - 1
for low <= high {
/**
利用位与(&)提取出两个数相同的部分,利用异或(^)拿出两个数不同的部分的和,相同的部分加上不同部分的和除2即得到两个数的平均值
异或: 相同得零,不同得1 == 男男等零,女女得零,男女得子
avg = (a&b)  + (a^b)>>1;
或者
avg = (a&b)  + (a^b)/2;
*/
mid := low&high + (low^high)>>1
if k < arr[mid] {
high = mid - 1
} else if k > arr[mid] {
low = mid + 1
} else {
return mid
}
}
return -1
}

//差值查找 有序查找
func insertSearch(arr []int, key int) int {
low := 0
high := len(arr) - 1
time := 0
for low < high {
time += 1
// 计算mid值是插值算法的核心代码 实际上就是
mid := low + int((high-low)*(key-arr[low])/(arr[high]-arr[low]))
if key < arr[mid] {
high = mid - 1
} else if key > arr[mid] {
low = mid + 1
} else {
return mid
}
}
return -1
}

/**
基本思路:先把数组构造出一颗二叉树的样纸,然后查找的时候在从root往下对比
*/
func BSTsearch(arr []int, key int) int {
// 先在内存中构造 二叉树
tree := new(Tree)
for i, v := range arr {
Insert(tree, v, i)
}
// 开始二叉树查找目标key
return searchKey(tree.Root, key)
}

/**
红黑树查找
*/
func RedBlackTreeSearch(arr []int, key int) int {
// 先构造树
//tree := new(RBTree)
tree := new(RBTree)
for i, v := range arr {
insertValue(tree, v, i)
}
// 开始二叉树查找目标key
return tree.serch(key)
}

BinaryTree.go 二分查找文件

package helper

// 节点结构
type Node struct {
Value, Index int // 元素的值和在数组中的位置
Left, Right  *Node
}

// 树结构
type Tree struct {
Root *Node
}

// 把数组的的元素插入树中
func Insert(tree *Tree, value, index int) {
if nil == tree.Root {
tree.Root = newNode(value, index)
} else {
InsertNode(tree.Root, newNode(value, index))
}
}

// 把新增的节点插入树的对应位置
func InsertNode(root, childNode *Node) {
// 否则,先和根的值对比
if childNode.Value <= root.Value {
// 如果小于等于跟的值,则插入到左子树
if nil == root.Left {
root.Left = childNode
} else {
InsertNode(root.Left, childNode)
}
} else {
// 否则,插入到右子树
if nil == root.Right {
root.Right = childNode
} else {
InsertNode(root.Right, childNode)
}
}
}

func newNode(value, index int) *Node {
return &Node{
Value: value,
Index: index,
}
}

// 在构建好的二叉树中,从root开始往下查找对应的key 返回其在数组中的位置
func searchKey(root *Node, key int) int {
if nil == root {
return -1
}
if key == root.Value {
return root.Index
} else if key < root.Value {
// 往左子树查找
return searchKey(root.Left, key)
} else {
// 往右子树查找
return searchKey(root.Right, key)
}
}

RedBlackTree.go 红黑树文件

package helper

const (
RED   = true
BLACK = false
)

// 节点
type RBNode struct {
Color               bool // true == 红  false == 黑
Parent, Left, Right *RBNode
Value, Index        int
}

type RBTree struct {
Root *RBNode
}

/*
* 对红黑树的节点(x)进行左旋转
*
* 左旋示意图(对节点 x 进行左旋):
*      px                              px
*     /                               /
*    x                               y
*   /  \      --(左旋)-.           / \                #
*  lx   y                          x  ry
*     /   \                       /  \
*    ly   ry                     lx  ly
*
*
*/
func (t *RBTree) leftSpin(node *RBNode) {
// 先提出自己的 右子
y := node.Right

// 自己的新右子 是前右子的左子
node.Right = y.Left

if nil != y.Left {
y.Left.Parent = node
}

// 你以前的爹,就是我现在的爹
y.Parent = node.Parent

// 如果被旋转的节点是 之前树的根
// 那么,新的跟就是 y 节点
if nil == node.Parent {
t.Root = y
} else { // 被旋转的是普通节点时, 需要结合自身的父亲来确认自己之前是属于 左子还是右子
if node.Parent.Left == node { // 被旋转节点之前是 左子时
// 用 y 来作为之前 该节点父亲的 新左子
node.Parent.Left = y
} else { // 否则,是 右子
node.Parent.Right = y
}
}

// 将 node 设为 y 的左子
y.Left = node
// 将 y 设为 node 的新父亲
node.Parent = y
}

/*
* 对红黑树的节点(y)进行右旋转
*
* 右旋示意图(对节点 y 进行左旋):
*            py                               py
*           /                                /
*          y                                x
*         /  \      --(右旋)-.            /  \                     #
*        x   ry                           lx   y
*       / \                                   / \                   #
*      lx  rx                                rx  ry
*
*/
func (t *RBTree) rightSpin(node *RBNode) {
// 先提出自己的 左子
x := node.Left
node.Left = x.Right

if nil != x.Left {
x.Right.Parent = node
}

x.Parent = node.Parent

// 如果被旋转的节点是 之前树的根
// 那么,新的跟就是 x 节点
if nil == node.Parent {
t.Root = x
} else {

if node.Parent.Right == node {
node.Parent.Right = x
} else {
node.Parent.Left = x
}
}

x.Right = node

node.Parent = x
}

func insertValue(tree *RBTree, val, index int) {
node := &RBNode{Value: val, Index: index, Color: BLACK}
if nil == tree.Root {
tree.Root = node
} else {
tree.insert(node)
}
}

func (t *RBTree) insert(node *RBNode) {
//int cmp;
var tmpNode *RBNode
root := t.Root

// 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。
for nil != root {
if node.Value < root.Value {
root = root.Left
} else {
root = root.Right
}
tmpNode = root
}

node.Parent = tmpNode
if nil != tmpNode {

if node.Value < tmpNode.Value {
tmpNode.Left = node
} else {
tmpNode.Right = node
}
} else {
t.Root = node
}

// 2. 设置节点的颜色为红色
node.Color = RED

// 3. 将它重新修正为一颗二叉查找树
t.adjustRBTree(node)
}

// 修正树
func (t *RBTree) adjustRBTree(node *RBNode) {
var parent, gparent *RBNode // 父亲 和 祖父

// 若“父节点存在,并且父节点的颜色是红色”
for nil != node.Parent && RED == node.Parent.Color {
parent = node.Parent
gparent = parent.Parent

//若“父节点”是“祖父节点的左孩子”
if parent == gparent.Left {
// Case 1条件:叔叔节点是红色
uncle := gparent.Right
if nil != uncle && RED == uncle.Color {
uncle.Color = BLACK
parent.Color = BLACK
gparent.Color = RED
node = gparent
continue
}

// Case 2条件:叔叔是黑色,且当前节点是右孩子
if node == parent.Right {
var tmp *RBNode
t.leftSpin(parent)
tmp = parent
parent = node
node = tmp
}

// Case 3条件:叔叔是黑色,且当前节点是左孩子。
parent.Color = BLACK
gparent.Color = RED
t.rightSpin(gparent)
} else { //若“z的父节点”是“z的祖父节点的右孩子”
// Case 1条件:叔叔节点是红色
uncle := gparent.Left
if nil != uncle && RED == uncle.Color {
uncle.Color = BLACK
parent.Color = BLACK
gparent.Color = RED
node = gparent
continue
}

// Case 2条件:叔叔是黑色,且当前节点是左孩子
if node == parent.Left {
var tmp *RBNode
t.rightSpin(parent)
tmp = parent
parent = node
node = tmp
}

// Case 3条件:叔叔是黑色,且当前节点是右孩子。
parent.Color = BLACK
gparent.Color = RED
t.leftSpin(gparent)
}
}
// 将根节点设为黑色
t.Root.Color = BLACK
}

func (t *RBTree) serch(key int) int {
return serch(t.Root, key)
}
func serch(node *RBNode, key int) int {
if nil == node {
return -1
}
if key < node.Value {
return serch(node.Left, key)
} else if key > node.Value {
return serch(node.Right, key)
} else {
return node.Index
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: