JavaScript樹結構——二叉搜索樹

JavaScript樹結構——二叉搜索樹

//二叉搜索樹類
function BinarySearchTree(){
	//節點類
	function Node(key, value=key){
		this.key = key
		this.value = value
		this.left = null
		this.right = null
	}
	//根節點
	this.root = null
	/*
	* 1.1 插入或修改數據
	*/ 
	BinarySearchTree.prototype.insert = function(key, value=key){
		let newNode = new Node(key, value=key)
		if (this.root == null){
			this.root = newNode
		}
		else{
			this.insertNode(this.root , newNode)
		}
	}
	/*
	* 1.2 插入數據內置方法
	* 從根節點開始尋找新節點要插入的位置(遞歸查找合適的空子節點)
	* 參數1:當前節點(初始爲根節點) , 參數2:要插入的新節點
	*/ 
	BinarySearchTree.prototype.insertNode = function(node, newNode){
		// 1. 向當前節點左邊插入的情況
		if (newNode.key < node.key){
			// 1.1 當前節點的左子節點爲空(結束遞歸)
			if (node.left == null){
				node.left = newNode 
			}
			// 1.2 當前節點的左子節點不爲空(繼續遞歸查找)
			else{
				this.insertNode(node.left, newNode)
			}
		}
		// 2. 向當前節點右邊插入的情況
		else if (newNode.key > node.key){
			// 2.1 當前節點的右子節點爲空(結束遞歸)
			if (node.right == null){
				node.right = newNode
			}
			// 2.2 當前節點的左子節點不爲空(繼續遞歸查找)
			else {
				this.insertNode(node.right, newNode)
			}
		}
		// 3. 修改數據的情況(newNode.key == node.key)
		else{
			node.value = newNode.value
		}
	}
	/*
	* 2.1 先序遍歷
	*/ 
	BinarySearchTree.prototype.preOrderTraversal = function(){
		let result = ''
		this.preOrderTraversalNode(this.root, function(key, value){
			result += `${key} => ${value}\n`
		}) 
		return result
	}
	/*
	* 2.2 先序遍歷內置方法
	*/ 
	BinarySearchTree.prototype.preOrderTraversalNode = function(node, callback){
		if (node != null){
			//處理數據
			callback(node.key,node.value)
			this.preOrderTraversalNode(node.left, callback)
			this.preOrderTraversalNode(node.right, callback)
		}
	}
	/*
	* 3.1 中序遍歷
	*/ 
	BinarySearchTree.prototype.midOrderTraversal = function(){
		let result = ''
		this.midOrderTraversalNode(this.root, function(key, value){
			result += `${key} => ${value}\n`
		})
		return result
	}
	/*
	* 3.2 中序遍歷內置方法
	*/ 
	BinarySearchTree.prototype.midOrderTraversalNode = function(node, callback){
		if (node != null){
			this.midOrderTraversalNode(node.left, callback)
			//處理數據
			callback(node.key, node.value)
			this.midOrderTraversalNode(node.right, callback)
		}
	}
	/*
	* 4.1 後序遍歷
	*/ 
	BinarySearchTree.prototype.postOrderTraversal = function(){
		let result = ''
		this.postOrderTraversalNode(this.root, function(key, value){
			result += `${key} => ${value}\n`
		})
		return result
	}
	/*
	* 4.2 後序遍歷內置方法
	*/ 
	BinarySearchTree.prototype.postOrderTraversalNode = function(node, callback){
		if (node != null){
			this.postOrderTraversalNode(node.left)
			this.postOrderTraversalNode(node.right)
			//處理數據
			callback(node.key, node.value)
		}
	}
	/*
	* 5. 獲取key的最值
	*/ 
	BinarySearchTree.prototype.max = function(){
		let node = this.root
		let key = null
		while (node != null){
			key = node.key
			node = node.right
		}
		return key
	}
	BinarySearchTree.prototype.min = function(){
		let node = this.root
		let key = null
		while (node != null){
			key = node.key
			node = node.left
		}
		return key
	}
	/*
	*	6. 查找節點數據
	*/ 
	BinarySearchTree.prototype.search = function(key){
		let node = this.root
		while (node != null){
			if (key < node.key){
				node = node.left
			}
			else if (key > node.key){
				node = node.right
			}
			else {
				return node.value
			}
		}
		return null
	}
	/*
	* 7. 刪除節點
	*/ 
	BinarySearchTree.prototype.remove = function(key){
		//定義變量保存信息
		let current = this.root
		let parent = null
		let isLeftChild = true
		//循環查找傳入的key
		while (current.key != key){
			parent = current
			
			if (key < current.key){
				isLeftChild = true
				current = current.left
			}
			else{
				isLeftChild = false
				current = current.right
			}
			//找不到返回false
			if (current == null){
				return false
			}
		}
		//循環結束,說明已經找到key所在的節點current和其父節點parent
		// 1. 刪除的是葉子節點(沒有子節點)
		if (current.left == null && current.right == null){
			// 1.1 刪除的是根節點
			if (current == this.root){
				this.root = null
			}
			// 1.2 刪除的不是根節點
			else {
				// 刪除的是左葉子節點
				if (isLeftChild){
					parent.left = null
				}
				else {
					parent.right = null
				}
			}
		}
		// 2. 刪除的節點僅有一個右子節點
		else if (current.left == null){
			if (current == this.root){
				this.root = current.right
			}
			else if (isLeftChild){
				parent.left = current.right
			}
			else {
				parent.right = current.right
			}
		}
		// 3. 刪除的節點僅有一個左子節點
		else if (current.right == null){
			if (current == this.root){
				this.root = current.left
			}
			else if (isLeftChild){
				parent.left = current.left
			}
			else {
				parent.right = current.left
			}
		}
		// 4. 刪除的節點有兩個子節點
		else {
			//獲取後繼節點
			let successor = this.getSuccessor(current)
			if (current == this.root){
				this.root = successor
				successor.left = current.left
			}
			else if (isLeftChild){
				parent.left = successor
				successor.left = current.left
			}
			else {
				parent.right = successor
				successor.left = current.left
			}
		}
	}
	/*
	* 8. 內部方法,查找要刪除節點的後繼
	*/ 
	BinarySearchTree.prototype.getSuccessor = function(delNode){
		let successor = delNode
		let successorParent = delNode
		let current = delNode.right
		
		while (current != null){
			successorParent = successor
			successor = current
			current = current.left
		}	
		//後繼節點不爲找到的首個右子節點
		if (successor != delNode.right){
			successorParent.left = successor.right
			successor.right = delNode.right
		}
		return successor
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章