溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript 中怎么實(shí)現(xiàn)一個(gè)二叉樹算法

發(fā)布時(shí)間:2021-08-07 17:38:46 來源:億速云 閱讀:158 作者:Leah 欄目:web開發(fā)

這篇文章將為大家詳細(xì)講解有關(guān)JavaScript 中怎么實(shí)現(xiàn)一個(gè)二叉樹算法,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

二叉樹和二叉搜索樹介紹

二叉樹中的節(jié)點(diǎn)最多只能有2個(gè)子節(jié)點(diǎn),一個(gè)是左側(cè)子節(jié)點(diǎn),一個(gè)是右側(cè)子節(jié)點(diǎn),這樣定義的好處是有利于我們寫出更高效的插入,查找,刪除節(jié)點(diǎn)的算法。二叉搜索樹是二叉樹的一種,但是它只允許你在左側(cè)子節(jié)點(diǎn)存儲(chǔ)比父節(jié)點(diǎn)小的值,但在右側(cè)節(jié)點(diǎn)存儲(chǔ)比父節(jié)點(diǎn)大的值。接下來我們將按照這個(gè)思路去實(shí)現(xiàn)一個(gè)二叉搜索樹。

JavaScript 中怎么實(shí)現(xiàn)一個(gè)二叉樹算法

1. 創(chuàng)建BinarySearchTree類

這里我們將使用構(gòu)造函數(shù)去創(chuàng)建一個(gè)類:

function BinarySearchTree(){     // 用于創(chuàng)建節(jié)點(diǎn)的類     let Node = function(key) {         this.key = key;         this.left = null;         this.right = null;     }     // 根節(jié)點(diǎn)     let root = null; }

我們將使用和鏈表類似的指針方式去表示節(jié)點(diǎn)之間的關(guān)系,如果不了解鏈表,請(qǐng)看我后序的文章《如何實(shí)現(xiàn)單向鏈表和雙向鏈表》。

2.插入一個(gè)鍵

// 插入一個(gè)鍵 this.insert = function(key) {     let newNode = new Node(key);     root === null ? (root = newNode) : (insertNode(root, newNode)) }

向樹中插入一個(gè)新的節(jié)點(diǎn)主要有以下三部分:1.創(chuàng)建新節(jié)點(diǎn)的Node類實(shí)例 --> 2.判斷插入操作是否為根節(jié)點(diǎn),是根節(jié)點(diǎn)就將其指向根節(jié)點(diǎn) -->  3.將節(jié)點(diǎn)加入非根節(jié)點(diǎn)的其他位置。

insertNode的具體實(shí)現(xiàn)如下:

function insertNode(node, newNode){     if(newNode.key < node.key) {         node.left === null ? (node.left = newNode) : (insertNode(node.left, newNode))     }else {         node.right === null ? (node.right = newNode) : (insertNode(node.right, newNode))     } }

這里我們用到遞歸,接下來要實(shí)現(xiàn)的search,del等都會(huì)大量使用遞歸,所以說不了解的可以先自行學(xué)習(xí)了解。我們創(chuàng)建一個(gè)二叉樹實(shí)例,來插入一個(gè)鍵:

let tree = new BinarySearchTree(); tree.insert(20); tree.insert(21); tree.insert(520); tree.insert(521);

插入的結(jié)構(gòu)會(huì)按照二叉搜索樹的規(guī)則去插入,結(jié)構(gòu)類似于上文的第一個(gè)樹圖。

樹的遍歷

訪問樹的所有節(jié)點(diǎn)有三種遍歷方式:中序,先序和后序。

  • 中序遍歷:以從最小到最大的順序訪問所有節(jié)點(diǎn)

  • 先序遍歷:以優(yōu)先于后代節(jié)點(diǎn)的順序訪問每個(gè)節(jié)點(diǎn)

  • 后序遍歷:先訪問節(jié)點(diǎn)的后代節(jié)點(diǎn)再訪問節(jié)點(diǎn)本身

根據(jù)以上的介紹,我們可以有以下的實(shí)現(xiàn)代碼。

1 中序排序

this.inOrderTraverse = function(cb){     inOrderTraverseNode(root, cb); }  // 輔助函數(shù) function inOrderTraverseNode(node, cb){     if(node !== null){         inOrderTraverseNode(node.left, cb);         cb(node.key);         inOrderTraverseNode(node.right, cb);     } }

使用中序遍歷可以實(shí)現(xiàn)對(duì)樹進(jìn)行從小到大排序的功能。

2 先序排序

// 先序排序 --- 優(yōu)先于后代節(jié)點(diǎn)的順序訪問每個(gè)節(jié)點(diǎn)    this.preOrderTraverse = function(cb) {      preOrderTraverseNode(root, cb);    }     // 先序排序輔助方法    function preOrderTraverseNode(node, cb) {      if(node !== null) {        cb(node.key);        preOrderTraverseNode(node.left, cb);        preOrderTraverseNode(node.right, cb);      }    }

使用先序排序可以實(shí)現(xiàn)結(jié)構(gòu)化輸出的功能。

3 后序排序

// 后續(xù)遍歷 --- 先訪問后代節(jié)點(diǎn),再訪問節(jié)點(diǎn)本身    this.postOrderTraverse = function(cb) {      postOrderTraverseNode(root, cb);    }     // 后續(xù)遍歷輔助方法    function postOrderTraverseNode(node, cb) {      if(node !== null){        postOrderTraverseNode(node.left, cb);        postOrderTraverseNode(node.right, cb);        cb(node.key);      }    }

后序遍歷可以用于計(jì)算有層級(jí)關(guān)系的所有元素的大小。

搜索樹中的值

在樹中有三種經(jīng)常執(zhí)行的搜索類型:最大值,最小值,特定的值。

1 最小值

最小值通過定義可以知道即是左側(cè)樹的最底端的節(jié)點(diǎn),具體實(shí)現(xiàn)代碼如下:

// 最小值    this.min = function(){      return minNode(root)    }      function minNode(node) {      if(node) {        while(node && node.left !== null){          node = node.left;        }        return node.key      }      return null    }

相似的,實(shí)現(xiàn)最大值的方法如下:

// 最大值    this.max = function() {      return maxNode(root)    }     function maxNode(node) {      if(node){        while(node && node.right !== null){          node = node.right;        }        return node.key      }      return null    }

2.搜索一個(gè)特定的值

// 搜索樹中某個(gè)值 this.search = function(key) {     return searchNode(root, key) }  // 搜索輔助方法 function searchNode(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     } }

3 移除一個(gè)節(jié)點(diǎn)

this.remove = function(key){     root = removeNode(root, key); }  // 發(fā)現(xiàn)最小節(jié)點(diǎn) function findMinNode(node) {     if(node) {     while(node && node.left !== null){         node = node.left;     }     return node     }     return null }  // 移除節(jié)點(diǎn)輔助方法 function removeNode(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 {     // 一個(gè)頁節(jié)點(diǎn)     if(node.left === null && node.right === null) {         node = null;         return node     }      // 只有一個(gè)子節(jié)點(diǎn)的節(jié)點(diǎn)     if(node.left === null) {         node = node.right;         return node     }else if(node.right === null) {         node = node.left;         return node     }      // 有兩個(gè)子節(jié)點(diǎn)的節(jié)點(diǎn)     let aux = findMinNode(node.right);     node.key = aux.key;     node.right = removeNode(node.right, aux.key);     return node     } }

刪除節(jié)點(diǎn)需要考慮的情況比較多,這里我們會(huì)使用和min類似的實(shí)現(xiàn)去寫一個(gè)發(fā)現(xiàn)最小節(jié)點(diǎn)的函數(shù),當(dāng)要?jiǎng)h除的節(jié)點(diǎn)有兩個(gè)子節(jié)點(diǎn)時(shí),我們要將當(dāng)前要?jiǎng)h除的節(jié)點(diǎn)替換為子節(jié)點(diǎn)中最大的一個(gè)節(jié)點(diǎn)的值,然后將這個(gè)子節(jié)點(diǎn)刪除。

關(guān)于JavaScript 中怎么實(shí)現(xiàn)一個(gè)二叉樹算法就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI