发表于 2017-12-18 17:02:13 | 分类于 算法 |

树的相关概念

  • 一个树结构包含一系列存在父子关系的节点。
  • 每个节点都有一个父节点(除了顶部的第一个节点)以及零个或多个子节点
  • 位于树顶部的节点叫做根节点,它没有父节点
  • 树中的每个元素都叫做节点
    • 节点分为外部节点和内部节点
    • 至少有一个子节点的节点为内部节点
    • 没有子元素的节点称为外部节点或叶节点
  • 一个节点可以有祖先和后代
    • 一个节点(除了根节点)的祖先包括,父节点、祖父节点、曾祖父节点等
    • 一个节点的后代包括子节点、孙子节点、曾孙节点等
  • 子树
    • 由节点和它的后代构成
  • 节点的深度
    • 取决于他的祖先节点的数量
  • 树的高度
    • 取决于所有节点深度的最大值 。

二叉树、二叉搜索树的相关概念

  • 二叉树
    • 二叉树的节点,最多只能有两个子节点
    • 一个是左侧子节点
    • 另一个是右侧子节点。
  • 二叉搜索树
    • 是二叉树的一种
    • 只允许在左侧节点存储(比父节点)小的值
    • 在右侧节点存储(比父节点)大(或者等于)的值。

创建二叉搜索树

BinarySearchTree 类方法

insert ( key ):向树中插入一个新的键

search ( key ):向树中查找一个键,如果节点存在,返回true;如果不存在,返回 false

inOrderTraverse ( ):通过中序遍历方式遍历所有节点

preOrderTraverse ( ):通过先序遍历方式遍历所有节点

postOrderTraverse ( ):通过后序遍历方式遍历所有节点。

min ():返回树中最小的值/键

max ( ):返回树中最大的值/键

remove ( key ):从树中移除某个键

BinarySearchTree 类

function BinarySearchTree ( ) {
  	// 声明一个 Node 类来表示树中的每个节点
  	// 将节点本身称为键。
  	// 键是树相关的术语中对节点的称呼。
  	var	Node = function ( key ) {
      	this.key = key ;
      	this.left = null ;
       	this.right = null ;
  	} ;
  	
  	var root = null ;
  
  	// 向树插入一个节点
    // 向树中插入一个新的节点,要经历三个步骤
    // 1)创建用来表示新节点的 Node 类实例。
    // 	  只须向构造函数传递我们想要插入树的节点值,
    //	  它的作指针和右指针的值会由构造函数自动设置为 null
    // 2)要验证这个插入操作是否为一种特殊情况
    //    该特殊情况就是,插入的节点是树的第一个节点
    //    如果是,就将根节点指向新节点
    // 3)将节点加在非根节点的其他位置
    //    该情况下,需要一个私有的辅助函数
    this.insert = function ( key ) {
        var newNode = new Node ( key ) ;

        if ( root === null ) {
            root = newNode ;
        }
        else {
            insertNode ( root, newNode ) ;
        }
    } ;
  
  	// insertNode 辅助函数,会找到新节点应该插入的正确位置
    // 1)如果树非空,需要找到插入新节点的位置。
    //    因此,在调用 inertNode 函数时要通过参数传入树的根节点和要插入的节点
    // 2)如果新节点的键小于当前节点的键(现在,当前节点就是根节点),需要检验当前节点的左侧子节点。
    //    如果没有左侧子节点,就在那里插入新节点
    //    如果有左侧子节点,需要通过递归调用 insertNode 函数,继续找到树的下一层。
    //    在这里,下次将要比较的节点将会是当前节点的左侧子节点
    // 3)如果节点的键比当前节点的键大,同时当前结点没有右侧子节点,
    //    那么,就在那里插入新节点
    //    如果有右侧子节点,需要递归调用 insertNode 函数
    //    要用来和新节点比较的节点是右侧子节点
    var insertNode = function ( node, newNode ) {
        if ( newNode.key < node.key) {
            if ( node.left === null ) {
                node.left = newNode ;
            }
            else {
                    insertNode ( node.left, newNode ) ;
            }
        }
        else {
            if ( node.right === null ) {
                node.right =newNode ;
            }3
            else {
                insertNode (node.right, newNode )
            }
        }
    } ;

    // 中序遍历
    // inOrderTraverse 方法接受一个回调函数作为参数。
    // 回调函数用来定义对遍历到的每个节点进行的操作(这也叫做访问者模式)
    this.inOrderTraverse = function ( calback ) {
        inOrderTraverseNode ( root, callback ) ;
    } ;
    // inOrderTraverseNode 的实现
    var inOrderTraverseNode = function ( node, callback ) {
        if ( node !== null ) {
            inOrderTraverseNode ( node.left, callback )	;
            callback ( node.key ) ;
            inOrderTraverseNode ( node.right, callback ) ;
        }
    } ;

    // 先序遍历
    this.preOrderTraverse = function ( callback ) {
        preOrderTraverseNode ( root, callback ) ;
    }  ;
    // preOrderTraverseNode 函数的实现	
    var preOrderTraverseNode = function ( callback ) {
        if ( node !== null ) {
            callback ( node.key ) ;
            preOrderTraverseNode ( node.left, callback ) ;
            preOrderTraverseNode ( node.right, callback ) ;
        }
    } ;
  
  
    // 后序遍历
    this.postOrderTraverse = function ( callback ) {
        postOrderTraverseNode ( root, callback ) ;
    } ;
  	// postOrderTraverseNode 函数的实现
  	var postOrderTraverseNode = function ( node, callback ) {
      	if ( node !== null ) {
          	postOrderTraverseNode ( node.left, callback ) ;
          	postOrderTraverseNode ( node.right, callback ) ;
          	callback ( node.key ) ;
      	}
  	} ;
  
  
    // 搜索树的最小键
    this.min = function ( ) {
        return minNode ( root ) ;
    } ;
    // minNode 函数的实现
    var minNode = function ( node ) {
        if ( node ) {
            while ( node && node.left !==null ) {
                node = node.left ;
            }

            return node.key ;
        }

        return null ;
    } ;
  	
  
    // 搜索树的最大键
  	 this.max = function ( ) {
     	return maxNode ( root ) ;  	
  	 } ;
  	 // maxNode 函数的实现
  	 var maxNode = function ( ) {
       	 if ( node ) {
           	while ( node && node.left !== null ) {
              	node = node.right ;
           	}          

           	return node.key ;
       	 }

       	 return null ;
  	 } ;
  
    // 搜索一个特定的值
    this.search = function ( key ) {
        return searchNode ( root, key ) ;
    } ;
    // searchNode 函数的实现
    var searchNode = function ( node, key ) {
        if ( node === null ) {
            return false ;
        }

        if ( key < node.key ) {
            return searchNode ( node.left, key ) ;
        }
        else if ( key > node.key ) {
            return searchNode ( node.right, key ) ;
        } 
        else {
            return true ;
        }
    } ;
  
    // 移除一个节点   
    this.remove = function ( key ) {
        root = removeNode ( root, key ) ;
    } ;
    // removeNode 函数的实现
    var removeNode = function ( node, key ) {
        if ( node === null ) {
            return null ;
        }

        if ( key < node.key ) {
            node.left = removeNode ( node.left, key ) ;
            return node ;
        }
        else if ( key > node.key ) {
            node.right = removeNode ( node.right, key ) ;
            return node ;
        }
        else { // 键等于 node.key
            // 第一种情况:一个叶节点
            if ( node.left === null && node.right === null ) {
                node = null ;
                return node ;
            }
        
            // 第二种情况:一个只有一个子节点的节点
            if ( node.left === null ) {
                node = node.right ;
                return node ;
            }
            else if ( node.right === null ) {
                node = node.left ;
                return node ;
            }
        
            // 第三种情况:一个有两个子节点的节点
            var aux = findMinNode ( node.right ) ;
            node.key = aux.key ;
            node.right = removeNode ( node.right, aux.key ) ;
            return node ;
        }
    } ;
}

更多关于二叉树的知识

  • AVL 树
  • 红黑树
  • 堆积树