可能有一部分人沒有讀過我上一篇寫的二叉堆,因此這裏把二叉樹的基本概念複製過來了,若是讀過的人能夠忽略前面針對二叉樹基本概念的介紹,另外若是對鏈表數據結構不清楚的最好先看一下本人以前寫的js數據結構-鏈表node
二叉樹(Binary Tree)是一種樹形結構,它的特色是每一個節點最多隻有兩個分支節點,一棵二叉樹一般由根節點,分支節點,葉子節點組成。而每一個分支節點也經常被稱做爲一棵子樹。react
經常使用術語
在二叉樹中,咱們經常還會用父節點和子節點來描述,好比圖中2爲6和3的父節點,反之6和3是2子節點算法
在二叉樹的第i層上,至多有2^i-1個節點小程序
深度爲k的二叉樹至多有2^k-1個節點segmentfault
二叉樹分爲徹底二叉樹(complete binary tree)和滿二叉樹(full binary tree)數組
二叉搜索樹知足如下的幾個性質:數據結構
咱們來舉個例子來深刻理解如下post
一組數據:12,4,18,1,8,16,20
由下圖能夠看出,左邊的圖知足了二叉樹的性質,它的每一個左子節點都小於父節點,右子節點大於其父節點,同時左子樹的節點都小於根節點,右子樹的節點都大於根節點this
二叉搜索樹主要的幾個操做:spa
經過下圖,能夠知道二叉搜索樹的節點一般包含4個域,數據元素,分別指向其左,右節點的指針和一個指向父節點的指針所構成,通常把這種存儲結構稱爲三叉鏈表。
用代碼初始化一個二叉搜索樹的結點:
class BinaryTreeNode { constructor(key, value){ this.parent = null; this.left = null; this.right = null; this.key = key; this.value = value; } }
接着咱們再用代碼去初始化一個二叉搜索樹
class BinarySearchTree { constructor() { this.root = null; } }
static createNode(key, value) { return new BinarySearchTree(key, value); }
看下面這張圖,13是咱們要插入的節點,它插入的具體步驟:
經過上面的描述,咱們來看看代碼是怎麼寫的
insert(node){ let p = this.root; let tail = this.root; // 循環遍歷,去找到對應的位置 while(tail) { p = tail; // 要插入的節點key比當前節點小 if (node.key < tail.key){ tail = tail.left; } // 要插入的節點key比當前節點大 else { tail = tail.right; } } // 沒有根節點,則直接做爲根節點插入 if(!p) { this.root = node; return; } // p是最後一個節點,也就是咱們要插入的位置的父節點 // 比父節點大則往右邊插入 if(p.key < node.key){ p.right = node; } // 比父節點小則往左邊插入 else { p.left = node; } // 指向父節點 node.parent = p; }
查找就很簡單了,其實和插入差多,都是去別叫左右節點的大小,而後往下找
search(key) { let p = this.root; if(!p) { return; } while(p && p.key !== key){ if(p.key<key){ p = p.right; }else{ p = p.left; } } return p; }
最經常使用的通常是中序遍歷,由於中序遍歷能夠獲得一個已經排好序的列表,這也是爲何會用二叉搜索樹排序的緣由
根據上面對中序遍歷的解釋,那麼代碼就變的很簡單,就是一個遞歸的過程,遞歸中止的條件就是節點爲null
transverse() { return this._transverse(this.root); } *_transverse(node){ if(!node){ return; } yield* this._transverse(node.left); yield node; yield* this._transverse(node.right) }
看上面這張圖,咱們簡化的來看一下,先訪問左節點4,再本身12,而後右節點18,這樣輸出的就恰好是一個4,12,18
補充:這個地方用了generater,因此返回的一個迭代器。能夠經過下面這種方式獲得一個有序的數組,這裏的前提就當是已經有插入的節點了
const tree = new BinaryTree(); //...中間省略插入過程 // 這樣就返回了一個有序的數組 var arr = [...tree.transverse()].map(item=>item.key);
class BinaryTreeNode { constructor(key, value) { // 指向父節點 this.p = null; // 左節點 this.left = null; // 右節點 this.right = null; // 鍵 this.key = key; // 值 this.value = value; } } class BinaryTree { constructor() { this.root = null; } static createNode(key, value) { return new BinaryTreeNode(key, value); } search(key) { let p = this.root; if (!p) { return; } while (p && p.key !== key) { if (p.key < key) { p = p.right; } else { p = p.left; } } return p; } insert(node) { // 尾指針的父節點指針 let p = this.root; // 尾指針 let tail = this.root; while (tail) { p = tail; if (node.key < tail.key) { tail = tail.left; } else { tail = tail.right; } } if (!p) { this.root = node; return; } // 插入 if (p.key < node.key) { p.right = node; } else { p.left = node; } node.p = p; } transverse() { return this.__transverse(this.root); } *__transverse(node) { if (!node) { return; } yield* this.__transverse(node.left); yield node; yield* this.__transverse(node.right); } }
二叉查找樹就講完了哈,其實這個和鏈表很像的,仍是操做那麼幾個指針,既然叫查找樹了,它主要仍是用來左一些搜索,還有就是排序了,另外補充一下,二叉查找樹裏找最大值和最小值也很方即是不是,若是你大體讀懂了的話。
這篇文章我寫的感受有點亂誒,由於總感受哪裏介紹的不到位,讓一些基礎差的人會看不懂,若是有不懂或者文章哪裏寫錯了,歡迎評論留言哈
後續寫什麼呢,這個問題我也在想,排序算法,react第三方的一些模擬實現?,作個小程序組件庫?仍是別的,容我再想幾個小時,由於能夠,有建議的朋友們也能夠留言說一下哈。最後最後,最重要的請給個贊,請粉一個呢,謝謝啦