JavaScript数据结构之 —— 09二叉查找树(二叉搜索树)

本文详细介绍了二叉查找树(二叉搜索树)的优势、结构和主要操作,包括插入、搜索、删除节点以及三种遍历方式。通过实例展示了如何在JavaScript中实现二叉查找树,特别强调了中序遍历在排序中的应用。
摘要由CSDN通过智能技术生成

树结构对比于数组/链表/哈希表有哪些优势

数组:
优点:可以通过下标值访问,效率高;
缺点:在插入和删除元素时,需要大量的位移操作;

链表:
优点:数据的插入和删除操作效率都很高;
缺点:查找效率低,需要从头开始依次查找,直到找到目标数据为止;当需要在链表中间位置插入或删除数据时,插入或删除的效率都不高。

哈希表:
优点:哈希表的插入/查询/删除效率都非常高;
缺点:空间利用率不高,底层使用的数组中很多单元没有被利用;并且哈希表中的元素是无序的,不能按照固定顺序遍历哈希表中的元素;而且不能快速找出哈希表中最大值或最小值这些特殊值。

树结构:
优点:树结构综合了上述三种结构的优点,同时也弥补了它们存在的缺点(虽然效率不一定都比它们高),比如树结构中数据都是有序的,查找效率高;空间利用率高;并且可以快速获取最大值和最小值等。

总的来说:每种数据结构都有自己特定的应用场景

在这里插入图片描述

二叉树

二叉树中的节点最多只能有两个子节点:一个是左侧子节点,另一个是右侧子节点。二叉树每个节点的子节点不允许超过两个。通过将子节点的个数限定为2,可以写出高效的程序在树中插入、查找和删除数据。

二叉查找树

二叉搜索树(BST,Binary Search Tree),也称为二叉排序树和二叉查找树。
二叉查找树是一种特殊的二叉树,相对较小的值保存在左节点中,较大的值保存在右节点中。这一特性使得查找的效率很高,这也就是二叉搜索树中"搜索"的来源。

二叉搜索树的结构

下图展现了二叉搜索树数据结构的组织方式
在这里插入图片描述
和链表一样,将通过指针来表示节点之间的关系(术语称其为边)。
在双向链表中,每个节点包含两个指针,一个指向下一个节点,另一个指向上一个节点。
对于树,使用同样的方式(也使用两个指针)。但是,一个指向左侧子节点,另一个指向右侧子节点。
因此,将声明一个Node类来表示树中的每个节点。值得注意的一个小细节是,不同于在之前的章节中将节点本身称作节点或项,我们将会称其为键。
键是树相关的术语中对节点的称呼。

二叉搜索树的方法

  • insert(key):向树中插入一个新的键;
  • search(key):在树中查找一个键,如果节点存在,则返回true;如果不存在,则返回false;
  • inOrderTraverse:通过中序遍历方式遍历所有节点;
  • preOrderTraverse:通过先序遍历方式遍历所有节点;
  • postOrderTraverse:通过后序遍历方式遍历所有节点;
  • min:返回树中最小的值/键;
  • max:返回树中最大的值/键;
  • remove(key):从树中移除某个键;

封装二叉搜索树

//封装二叉搜索树
function BinarySearchTree(){
   

  //节点内部类
  function Node(key){
   
    this.key = key
    this.left = null
    this.right = null
  }

  //属性
  this.root = null
}

向树中插入一个键

var insertNode = function(node, newNode){
   
	// 新节点的key小于比较节点
	if (newNode.key < node.key){
    
		// 如果左子节点为空,左子节点指向新节点
		if (node.left === null){
    
			node.left = newNode; 
		// 如果左子节点不为空,就将新节点与左子节点进行比较
		} else {
   
			// 递归调用比较函数
			insertNode(node.left, newNode); 
		}
	// 新节点的key大于比较节点
	} else {
   
		// 如果右子节点为空,右子节点指向新节点
		if (node.right === null){
    
			node.right = newNode; 
		// 如果右子节点不为空,就将新节点与右子节点进行比较
		} else {
   
			// 递归调用比较函数
			insertNode(node.right, newNode); 
		}
	}
};

BinarySearchTree.prototype.insert = function(key){
   
	// 创建一个表示新节点的类
	var newNode = new Node(key); 

	// 判断插入的是否为根节点
	if (this.root === null){
   
		this.root = newNode;
	} else {
   
		// 正常节点插入
		insertNode(this.root,newNode); //{3}
	}
};

在这里插入图片描述

在这里插入图片描述
此时如果想插入一个值为6的键,执行流程及结果如下:

在这里插入图片描述

在这里插入图片描述

树的遍历

这里说的树的遍历不仅仅针对二叉搜索树,而是适用于所有的二叉树。由于树结构不是线性结构,所以便利方式有多种选择,常见的三种二叉树遍历方式为:先序遍历、中序遍历和后序遍历。其中中序遍历是以升序访问所有节点。

先序遍历

先序遍历的过程为:
首先,遍历根节点;
然后,遍历其左子树;
最后,遍历其右子树;

在这里插入图片描述
代码实现

BinarySearchTree.prototype.preOrderTraverse = function(callback){
   
	preOrderTraverseNode(this.root, callback);
};

var preOrderTraverseNode = function (node, callback) {
   
	if (node !== null) {
   
		// 先访问并处理节点本身
		// 然后访问左子节点,最后访问右子节点,每一层节点都是这样
		callback(node.key);
		preOrderTraverseNode(node.left, callback); 
		preOrderTraverseNode(node.right, callback); 
	}
};

在这里插入图片描述

中序遍历

中序遍历的过程为:
首先,遍历其左子树;
然后,遍历根(父)节点;
最后,遍历其右子树;

中序遍历是一种以上行顺序访问BST所有节点的遍历方式,也就是以从最小到最大的顺序访问所有节点。中序遍历的一种应用就是对树进行排序操作。

在这里插入图片描述

代码实现

//中序遍历
BinarySearchTree.prototype.inOrderTraverse = function(callback){
   
  inOrderTraverseNode(this.root, callback)
}

var inOrderTraverseNode = function(node, callback){
   
  if (node !== null) {
   
    //1.遍历左子树中的节点,这里会层层遍历
    // 直到找到最小值,对最小值执行callback方法
    inOrderTraverseNode(node.left, callback)<
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值