摘要:簡(jiǎn)介二叉樹是一種非常重要的數(shù)據(jù)結(jié)構(gòu),很多其它數(shù)據(jù)結(jié)構(gòu)都是基于二叉樹的基礎(chǔ)演變而來的。二叉搜索樹是二叉樹的一種,但是它只允許你在左側(cè)節(jié)點(diǎn)存儲(chǔ)比父節(jié)點(diǎn)小的值,在右側(cè)節(jié)點(diǎn)存儲(chǔ)比父節(jié)點(diǎn)大或者等于的值。樹的高度,樹的高度體現(xiàn)為節(jié)點(diǎn)深度的最大值。
簡(jiǎn)介
二叉樹是一種非常重要的數(shù)據(jù)結(jié)構(gòu),很多其它數(shù)據(jù)結(jié)構(gòu)都是基于二叉樹的基礎(chǔ)演變而來的。
對(duì)于二叉樹,有深度遍歷和廣度遍歷,深度遍歷有前序、中序以及后序三種遍歷方法,廣度遍歷即我們平常所說的層次遍歷。因?yàn)闃涞亩x本身就是遞歸定義,因此采用遞歸的方法去實(shí)現(xiàn)樹的三種遍歷不僅容易理解而且代碼很簡(jiǎn)潔,而對(duì)于廣度遍歷來說,需要其他數(shù)據(jù)結(jié)構(gòu)的支撐,比如堆了。
二叉樹中的節(jié)點(diǎn)最多只能有兩個(gè)節(jié)點(diǎn):一個(gè)是左側(cè)子節(jié)點(diǎn),另一個(gè)是右側(cè)子節(jié)點(diǎn)。
二叉搜索樹(BST)是二叉樹的一種,但是它只允許你在左側(cè)節(jié)點(diǎn)存儲(chǔ)(比父節(jié)點(diǎn))小的值,在右側(cè)節(jié)點(diǎn)存儲(chǔ)(比父節(jié)點(diǎn))大(或者等于)的值。
樹中的每個(gè)元素,都叫做節(jié)點(diǎn)。從節(jié)點(diǎn)延伸而下的,叫子節(jié)點(diǎn)。
樹頂部的節(jié)點(diǎn)叫根節(jié)點(diǎn)。每棵樹只有一個(gè)根節(jié)點(diǎn)。
在節(jié)點(diǎn)中,有子節(jié)點(diǎn)的節(jié)點(diǎn)也稱為內(nèi)部節(jié)點(diǎn),沒有的話則被稱為外部節(jié)點(diǎn)或者葉節(jié)點(diǎn)。
同時(shí)在節(jié)點(diǎn)中是有祖先和后代關(guān)系的,比如節(jié)點(diǎn)9的祖先就有13,7,6,15四個(gè)。
深度: 節(jié)點(diǎn)的深度取決于其祖先的數(shù)量,節(jié)點(diǎn)9的深度就是4。
樹的高度,樹的高度體現(xiàn)為節(jié)點(diǎn)深度的最大值。
比如上圖,節(jié)點(diǎn)深度最大值為4,則樹的高度為4。
下面我們先來簡(jiǎn)單實(shí)現(xiàn)一個(gè)二叉搜索樹類,并包含以下的方法:
insert(key): 向樹中插入一個(gè)新的鍵
min(): 返回樹中最小的值
max(): 返回樹中最大的值
search(key): 搜索某個(gè)值,在樹中則返回true
remove(key): 從樹中移除某個(gè)鍵
代碼如下:
function BinarySearchTree() { var Node = function(key){ //數(shù)據(jù)結(jié)構(gòu)類 this.key = key; this.left = null; this.right = null; }; var root = null; //根節(jié)點(diǎn) this.insert = function(key){ //插入新的鍵 var newNode = new Node(key); //special case - first element if (root === null){ //根節(jié)點(diǎn)為空,作為根節(jié)點(diǎn) root = newNode; } else { insertNode(root,newNode); //插入節(jié)點(diǎn)操作 } }; var insertNode = function(node, newNode){ if (newNode.key < node.key){ if (node.left === null){ //如果沒有左側(cè)節(jié)點(diǎn)就插入新的節(jié)點(diǎn) node.left = newNode; } else { //有的話遞歸 insertNode(node.left, newNode); } } else { if (node.right === null){ //如果沒有右側(cè)節(jié)點(diǎn)就插入新的節(jié)點(diǎn) node.right = newNode; } else { //有的話遞歸 insertNode(node.right, newNode); } } }; this.getRoot = function(){ return root; }; this.search = function(key){ //搜索鍵 return searchNode(root, key); //搜索操作 }; var searchNode = function(node, key){ if (node === null){ return false; } if (key < node.key){ //如果小于繼續(xù)從左邊搜索 return searchNode(node.left, key); } else if (key > node.key){ //如果大于繼續(xù)從右邊搜索 return searchNode(node.right, key); } else { //命中 return true; } }; this.min = function() { //找最小鍵 return minNode(root); }; 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); }; var maxNode = function (node) { if (node){ while (node && node.right !== null) { node = node.right; } return node.key; } return null; }; this.remove = function(element){ root = removeNode(root, element); }; var findMinNode = function(node){ //返回節(jié)點(diǎn) while (node && node.left !== null) { node = node.left; } return node; }; var removeNode = function(node, element){ //移除一個(gè)節(jié)點(diǎn) if (node === null){ return null; } if (element < node.key){ node.left = removeNode(node.left, element); return node; } else if (element > node.key){ node.right = removeNode(node.right, element); return node; } else { //命中后分三種情況 //移除葉子節(jié)點(diǎn),即該節(jié)點(diǎn)沒有左側(cè)或者右側(cè)子節(jié)點(diǎn)的葉結(jié)點(diǎn) if (node.left === null && node.right === null){ node = null; return node; } //移除有一個(gè)左側(cè)或者右側(cè)子節(jié)點(diǎn)的節(jié)點(diǎn) if (node.left === null){ node = node.right; //把引用改為子節(jié)點(diǎn)的引用,下同 return node; } else if (node.right === null){ node = node.left; return node; } //移除有兩個(gè)子節(jié)點(diǎn)的節(jié)點(diǎn) var aux = findMinNode(node.right); //找到右邊子樹的最小節(jié)點(diǎn) node.key = aux.key; //改變節(jié)點(diǎn)的鍵,更新節(jié)點(diǎn)的值 node.right = removeNode(node.right, aux.key); //移除有相同鍵的節(jié)點(diǎn) return node; //返回更新后節(jié)點(diǎn)的引用 } }; }二叉樹的遍歷
前序遍歷:根結(jié)點(diǎn) ---> 左子樹 ---> 右子樹
中序遍歷:左子樹---> 根結(jié)點(diǎn) ---> 右子樹
后序遍歷:左子樹 ---> 右子樹 ---> 根結(jié)點(diǎn)
層次遍歷:只需按層次遍歷即可
例如,求下面二叉樹的各種遍歷
前序遍歷:1 2 4 5 7 8 3 6
中序遍歷:4 2 7 5 8 1 3 6
后序遍歷:4 7 8 5 2 6 3 1
層次遍歷:1 2 3 4 5 6 7 8
代碼實(shí)現(xiàn)如下:
/** * 先序遍歷 * @param {any} callback 回調(diào)函數(shù) */ this.preOrderTranverse = function (callback) { preOrderTranverseNode(root, callback) } var preOrderTranverseNode = function (node, callback) { if (node !== null) { callback && callback(node.key); preOrderTranverseNode(node.left, callback); preOrderTranverseNode(node.right, callback); } }中序遍歷
代碼實(shí)現(xiàn)如下:
/**
中序遍歷
@param {any} callback 回調(diào)函數(shù)
*/
this.inOrderTraverse = function (callback) {
inOrderTraverseNode(root, callback)
}
var inOrderTraverseNode = function (node, callback) {
if (node !== null) { inOrderTraverseNode(node.left, callback); callback && callback(node.key) inOrderTraverseNode(node.right, callback); }
}
后序遍歷代碼實(shí)現(xiàn)如下:
/** * 后序遍歷 * @param {any} callback 回調(diào)函數(shù) */ this.postOrderTranverse = function (callback) { postOrderTranverseNode(root, callback); } var postOrderTranverseNode = function (node, callback) { if (node !== null) { postOrderTranverseNode(node.left, callback); postOrderTranverseNode(node.right, callback); callback(node.key); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/89292.html
摘要:二叉搜索樹是二叉樹的一種,其特征是左側(cè)子節(jié)點(diǎn)存儲(chǔ)比父節(jié)點(diǎn)小的值,右側(cè)子節(jié)點(diǎn)存儲(chǔ)比父節(jié)點(diǎn)大或等于父節(jié)點(diǎn)的值。實(shí)現(xiàn)和這個(gè)兩個(gè)方法其實(shí)挺簡(jiǎn)單的,最小的節(jié)點(diǎn)就在二叉搜索樹的最左反之,最大的就在最右。 本系列所有文章:第一篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之棧與隊(duì)列第二篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之鏈表第三篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之集合第四篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之字典和散列表第五篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)...
摘要:像剛才的這幅圖,就是二叉搜索樹。而我們本文要學(xué)習(xí)的內(nèi)容,就是如何寫一個(gè)二叉搜索樹。但在二叉搜索樹中,我們把節(jié)點(diǎn)成為鍵,這是術(shù)語(yǔ)。前端路漫漫,且行且歌的前端樂園原文鏈接寒假前端學(xué)習(xí)學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法四二叉搜索樹 本系列的第一篇文章: 學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(一),棧與隊(duì)列第二篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(二):鏈表第三篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)...
摘要:原文博客地址學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)四樹知乎專欄簡(jiǎn)書專題前端進(jìn)擊者知乎前端進(jìn)擊者簡(jiǎn)書博主博客地址的個(gè)人博客人之所能,不能兼?zhèn)洌瑮壠渌蹋∑渌L(zhǎng)。通常子樹被稱作左子樹和右子樹。敬請(qǐng)期待數(shù)據(jù)結(jié)構(gòu)篇最后一篇文章學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)五圖參考文章樹數(shù)據(jù)結(jié)構(gòu)二叉樹 前言 總括: 本文講解了數(shù)據(jù)結(jié)構(gòu)中的[樹]的概念,盡可能通俗易懂的解釋樹這種數(shù)據(jù)結(jié)構(gòu)的概念,使用javascript實(shí)現(xiàn)了樹,如有紕漏,歡迎批評(píng)指正。 ...
摘要:筆者作為一位,將工作以來用到的各種優(yōu)秀資料神器及框架整理在此,畢竟好記性不如爛鍵盤,此前端知識(shí)點(diǎn)大百科全書前端掘金,,不定期更新技巧前端掘金技巧,偶爾更新。計(jì)算數(shù)組的極值技巧使你的更加專業(yè)前端掘金一個(gè)幫你提升技巧的收藏集。 CSS 樣式畫各種圖形 - 前端 - 掘金下面是一些我在 CSS 中經(jīng)常用到的圖案,還有一些是在css-tricks看到的。記錄一下,以后會(huì)用到。會(huì)持續(xù)更新… 一、...
閱讀 2684·2021-11-16 11:53
閱讀 2749·2021-07-26 23:38
閱讀 2080·2019-08-30 15:55
閱讀 1760·2019-08-30 13:21
閱讀 3680·2019-08-29 17:26
閱讀 3314·2019-08-29 13:20
閱讀 884·2019-08-29 12:20
閱讀 3200·2019-08-26 10:21