樹結構
樹是一種重要的非線性數據結構,直觀地看,它是數據元素(在樹中稱爲結點)按分支關係組織起來的結構,很象自然界中的樹那樣。
- HTML結構就是典型的樹結構
二叉搜索樹
- 特點:
- 節點最多只能有兩個子節點,一個左子節點,一個右子節點,左右子節點的順序不能顛倒。
- 在左側存儲比父節點小的值
- 在右側存儲比父節點大的值
- 實現:
- 樹(Tree)有:根節點,內部的Node類,查找,刪除,插入,遍歷
- 樹(Tree)有:根節點,內部的Node類,查找,刪除,插入,遍歷
- 插入節點
function Tree(){
var Node = function(val){
this.value = val
this.left = null
this.right = null
}
var root = null
// 插入節點
/**
* 1、樹爲空樹:root = value
* 2、樹不是空的:對比節點
*/
var insertNode = function(node,newNode){
if(newNode.value>node.value){
if(node.right===null){
node.right = newNode
}else{
insertNode(node.right,newNode)
}
}else if(newNode.value<node.value){
if(node.left===null){
node.left = newNode
}else{
insertNode(node.left,newNode)
}
}
}
this.insert = function(value){
var node = new Node(value)
if(root===null){
root = node
}else{
insertNode(root,node)
}
}
}
- 遍歷樹
// 遍歷節點
// 藉助遞歸
function traverse(node, callback){
if(node===null) return;
traverse(node.left,callback)
traverse(node.right,callback)
callback(node.value)
}
this.traverse = function(callback){
traverse(root,callback)
}
- 獲取最小值
- 移除節點
移除節點有很多種情況:
- 移除有2個子節點的?——選哪個子節點來代替被刪除的節點
- 移除末位節點(葉節點)
- 移除只有1個子節點
/**
* 根節點 root
* 插入 insert
* 查找 search
* 遍歷 traverse
* 刪除 remove
* 內部的Node類
*
*/
function Tree(){
var Node = function (value){
this.value = value
this.left = null
this.right = null
}
var root = null
// 插入
function insert(node,newNode){
if(node.value<newNode.value){
if(node.right===null){
node.right = newNode
}else{
insert(node.right,newNode)
}
}else{
if(node.left===null){
node.left = newNode
}else{
insert(node.left,newNode)
}
}
}
this.insert = function(value){
var node = new Node(value)
if(!root){
root = node
}else{
insert(root,node)
}
}
// 搜索
var searchNode = function(node,value){
if(node===null) return null
if(value<node.value) return searchNode(node.left,value)
else if(value>node.value) return searchNode(node.right,value)
else return node
}
this.search = function(val){
searchNode(root,value)
}
// 遍歷
function traverse (node,callback){
if(!node) return;
// callback(node.value) //前序遍歷 —— 訪問根節點的操作發生在遍歷其左右子樹之前。
traverse(node.left,callback)
// callback(node.value) //中序遍歷 —— 訪問根節點的操作發生在遍歷其左右子樹之間。
traverse(node.right,callback)
callback(node.value) //後序遍歷 —— 訪問根節點的操作發生在遍歷其左右子樹之後
}
this.traverse = function(callback){
traverse(root,callback)
}
// 最小值
this.min = function(node){
if(node===null) return null;
while(node&&node.left!==null){
node = node.left
}
return node
}
// 最大值
this.max = function(node){
if(node===null) return null
while(node&&node.right!==null){
node = node.right
}
return node
}
// 刪除——重新構建樹
function findMinNode(node){
if(node === null) return null
while(node && node.left!== null){
node = node.left
}
return node
}
let removeNode = function (node, key) {
if (node === null) return null;
// 查找
if (key < node.value) {
node.left = removeNode(node.left, key);
return node;
}else if (key > node.value) {
node.right = removeNode(node.right, key);
return node;
}else {
// 找到節點後,刪除
// 第一種情況:一個葉子節點(沒有子節點)
if (node.left === null && node.right === null) {
node = null;
return null;
}
// 第二種情況:只包含一個子節點
if (node.left === null) {
node = node.right;
return node;
}
else if (node.right === null) {
node = node.left;
return node;
}
// 第三種情況:有兩個子節點
let aux = findMinNode(node);
node.value = aux.key;
node.right = removeNode(node.right, aux.value);
return node;
}
};
this.remove = function(key){
root = removeNode(root,key)
}
this.getTree = function(){
return root
}
}
var t = new Tree
t.insert(8)
t.insert(2)
t.insert(3)
t.insert(9)
// t.remove(2)
// console.log(t.getTree())