JS实现平衡二叉树(AVL)

1,576 阅读2分钟

定义

AVL树是一种二叉排序树,得名于其发明者的名字( Adelson-Velskii 以及 Landis),因为它其中的每个节点的左子树和右子树的高度差至多等于1,所以又称平衡二叉树

如图所示:

image.png

构建原理

其本质其实也是在构建一个二叉搜索树,区别就是在二叉树的构建的过程中,一但发现树中存在不平衡现象,即某节点的平衡因子大于1或小于-1,就找出那个最小的不平衡子树,进行“旋转”转换操作,调整最小不平衡子树中各节点的链接关系,使之成为新的平衡子树。

如图所示:

image.png

从上图中就可以清晰的看到,旋转后的二叉搜索树就符合平衡二叉树的定义要求,即:每个节点的左子树和右子树的高度差至多等于1

编码实现

1、声明一个函数用来创建节点

function TreeNode(key){ 
    this.data = key; // 存储数据
    this.bf = 0; // 平衡因子 balance factor
    this.leftChild = null; // 左子节点
    this.rightChild = null; // 右子节点
}

2、声明左旋函数与右旋函数

左旋函数与右旋函数就是对不平衡子树中某一节点的一次左旋和右旋操作函数代码,返回旋转后的新节点

// 左旋操作
function LeftRotate(node) {
    let newNode = node.rightChild;
    node.rightChild = newNode.leftChild;
    newNode.leftChild = node;
    return newNode;
}

// 右旋操作
function RightRotate(node) {
    let newNode = node.leftChild;
    node.leftChild = newNode.rightChild;
    newNode.rightChild = node;
    return newNode;
}

function leftBalance(node){
	let lc = node.leftChild;
	switch (lc.bf){
		case 1:
			lc.bf = 0;
			node.bf = 0;
			return RightRotate(node);
		case -1:
			let rd = lc.rightChild;
			switch (rd.bf){
				case 1:       
					lc.bf = 0;
					node.bf = -1;
					break;
				case -1:      
					lc.bf = 1;
					node.bf = 0;
					break;
				case 0:
					lc.bf = 0;
					node.bf = 0;
					break;
			}
			rd.bf = 0;
			node.leftChild = LeftRotate(node.leftChild);
			return RightRotate(node);
	}
}


function rightBalance(node){
	let rc = node.rightChild;
	switch (rc.bf){
		case -1:
			rc.bf = 0;
			node.bf = 0;
			return LeftRotate(node);
		case 1:
			let ld = rc.leftChild;
			switch (ld.bf){
				case 1:      
					rc.bf = -1;
					node.bf = 0;
					break;
				case -1:      
					rc.bf = 0;
					node.bf = 1;
					break;
				case 0:
					rc.bf = 0;
					node.bf = 0;
					break;
			}
			ld.bf = 0;
			node.rightChild = RightRotate(node.rightChild);
			return LeftRotate(node);
	}
}

3、声明节点插入函数

节点插入时如果存在已有相同key的值,则不进行插入操作

var taller = true;
var temp = null;

function insertAVL(node,key){
	if (!node){              // 新建节点
		node = new TreeNode(key);
		taller = true;
	}else{
		if (key === node.data){ // 不插入
			taller = false;
			return 0;
		}else if (key < node.data){
			temp = insertAVL(node.leftChild,key); //  进行节点的左子树搜索
			if ( temp === 0) return 0;
			node.leftChild = temp;
			if (taller){
				switch (node.bf){
					case 1:
						node = leftBalance(node);  
						taller = false;
						break;
					case 0:
						node.bf = 1;
						taller = true;
						break;
					case -1:
						node.bf = 0;
						taller = false;
						break;
				}
			}
		} else {
			temp = insertAVL(node.rightChild,key); // 进行节点的右子树搜索
			if ( temp === 0) return 0;
			node.rightChild = temp;
			if (taller){
				switch (node.bf){
					case 1:
						node.bf = 0;
						taller = false;
						break;
					case 0:
						node.bf = -1;
						taller = true;
						break; 
					case -1:
						node = rightBalance(node);
						taller = false;
						break;
				}
			}
		}
	}
	return node;
}