本文将对平衡二叉树的旋转原理进行分析。

至于平衡二叉树是什么,大家可移步度娘,之后回到这里继续浏览。

本文还将使用golang实现二叉树的前中后序的打印,插入(平衡旋转)。

一、基础原理图解

话不多说,上图:

1. 基本介绍,字符约定(T、L、R、h、BF)

2. 树高、平衡因子介绍

3. 节点插入的四种类型,以及相应的旋转大法

 

二、golang 代码实现

废话少说,上golang实现的代码:

1. 定义了一个二叉树的接口 文件目录 tree/tree.go

(请忽略默认int存储数据,大家根据喜好自行优化即可,对于删除和搜索本文并未提供实现,想学习的朋友可根据本文提供的思路自己实现一下,我想这样才能真的理解并记住它)

package tree

type Tree interface {
	Insert(int)
	PrefaceTraversal() //根左右
	InorderTraversal() //左根右
	PostTraversal()    //左右根
	//Delete(int)
	//Search(int)
}

2. tree接口实现 文件目录 tree/avl.go

package tree

import (
	"log"
	"sync"
)

const (
	LH = 1  //左高
	EH = 0  //等高
	RH = -1 //右高
)

//二叉树结构体
type AvlBinary struct {
	state bool  // 树 长(三声)高的标志
	mutex *sync.RWMutex
	node  *node // node结构体
}

func NewAvlBinary() Tree {
	return &AvlBinary{
		state: false,
		mutex: &sync.RWMutex{},
	}
}

func (avl *AvlBinary) Insert(i int) {
	avl.mutex.Lock()
	defer avl.mutex.Unlock()
	avl.node = avl.node.insert(i, &avl.state)
}

func (avl *AvlBinary) PrefaceTraversal() {
	if avl != nil {
		avl.node.prefaceTraversal()
	}
}

func (avl *AvlBinary) InorderTraversal() {
	if avl != nil {
		avl.node.inorderTraversal()
	}
}

func (avl *AvlBinary) PostTraversal() {
	if avl != nil {
		avl.node.postTraversal()
	}
}

//节点结构体
type node struct {
	data, bf    int   // bf 平衡因子
	left, right *node
}

//创建节点
func createNode(i int) *node {
	return &node{
		data:  i,
		bf:    EH,
		left:  nil,
		right: nil,
	}
}

//左旋
func (n *node) rotateToLeft() *node {
	headNode := n.right
	n.right = headNode.left
	headNode.left = n
	return headNode
}

//右旋
func (n *node) rotateToRight() *node {
	headNode := n.left
	n.left = headNode.right
	headNode.right = n
	return headNode
}

//右平衡旋转
func (n *node) rightBalance() *node {
	r := n.right
	switch r.bf {
	case RH: //RR型 ,新入节点在p节点的右孩子的右子树,只做左旋。 旋转后 t与r的平衡因子 都为0
		n.bf = EH
		r.bf = EH
		return n.rotateToLeft()
	case LH: //RL型,新入节点在p节点的右孩子的左子树,需要双旋。//
		rl := r.left
		// 旋转后的平衡因子会根据新入节点的位置有不同的变化,【思考问题】的目的就在于此
		//有三种情况:
		switch rl.bf {
		case LH: //情况一.插入节点后rl的平衡因子为1,即插入到rl的左子树
			n.bf = EH
			r.bf = RH
		case RH: //情况二.插入节点后rl的平衡因子为-1,即插入到rl的右子树
			n.bf = LH
			r.bf = EH
		case EH: //情况三.插入节点后rl的平衡因子为0,这种情况下 rl本就为空,即新入节点就是rl
			n.bf = EH
			r.bf = EH
		}

		rl.bf = EH
		n.right = r.rotateToRight() //先对最小不平衡子树做右旋转处理
		return n.rotateToLeft()     //整体做左旋转处理
	}
	return n
}

//左平衡旋转
func (n *node) leftBalance() *node {
	l := n.left
	switch l.bf {
	case LH: //新入节点在p节点的左孩子的左子树,只做右旋处理
		n.bf = EH
		l.bf = EH
		return n.rotateToRight()
	case RH: //新入节点在p节点的左孩子的右子树,要做双旋处理
		lr := l.right

		switch lr.bf {
		case LH:
			n.bf = RH
			l.bf = EH
		case EH:
			n.bf = EH
			l.bf = EH
		case RH:
			n.bf = EH
			l.bf = LH
		}

		lr.bf = EH
		n.left = l.rotateToLeft()
		return n.rotateToRight()
	}
	return n
}

func (n *node) insert(i int, state *bool) *node {
	if n == nil {
		*state = true
		return createNode(i)
	} else {
		if i == n.data {
			return n
		}

		if i < n.data { //左子树寻找插入点
			newNode := n.left.insert(i, state)
			n.left = newNode
			//判断平衡因子 是否需要不平衡处理
			if *state {
				switch n.bf {
				case EH:
					n.bf = LH
					*state = true
				case LH: //因本身左子树平衡因子=1,插入左子树则平衡因子+1,故此时需要平衡处理
					*state = false
					return n.leftBalance()
				case RH:
					n.bf = EH
					*state = false
				}
			}
		} else {
			newNode := n.right.insert(i, state)
			n.right = newNode
			//判断平衡因子 是否需要不平衡处理
			if *state {
				switch n.bf {
				case EH:
					n.bf = RH
					*state = true
				case LH:
					n.bf = EH
					*state = false
				case RH:
					*state = false
					return n.rightBalance()
				}
			}
		}
	}

	return n
}

//前序打印
func (n *node) prefaceTraversal() {
	if n != nil {
		n.print()
		n.left.prefaceTraversal()
		n.right.prefaceTraversal()
	}
}

func (n *node) inorderTraversal() {
	if n != nil {
		n.left.inorderTraversal()
		n.print()
		n.right.inorderTraversal()
	}
}

func (n *node) postTraversal() {
	if n != nil {
		n.left.postTraversal()
		n.right.postTraversal()
		n.print()
	}
}

func (n *node) print() {
	log.Print(n.data, " 平衡因子:", n.bf)
}

3. main文件 文件目录 main.go

package main

import "dataStructure/tree"

func main() {
    avl := tree.NewAvlBinary()
	avl.Insert(8)
	avl.Insert(5)
	avl.Insert(12)
	avl.Insert(3)
	avl.Insert(6)
	avl.Insert(16)
	avl.Insert(11)
	//avl.Insert(14)
	//avl.Insert(13)
	avl.Insert(20)
	avl.Insert(18)

	avl.PrefaceTraversal()
}

参考书:《大话数据结构》-- 程杰

学习整理:马丁之帜