成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript算法之二叉搜索樹(shù)

khlbat / 1097人閱讀

摘要:二叉搜索樹(shù)的特性二叉搜索樹(shù)由于其獨(dú)特的數(shù)據(jù)結(jié)構(gòu),使得其無(wú)論在增刪,還是查找,時(shí)間復(fù)雜度都是,為二叉樹(shù)的高度。二叉搜索樹(shù)的查找查找很簡(jiǎn)單,根據(jù)左子節(jié)點(diǎn)比該節(jié)點(diǎn)小,右子節(jié)點(diǎn)比該節(jié)點(diǎn)大的原則進(jìn)行循環(huán)判斷即可。

什么是二叉樹(shù)

二叉樹(shù)就是樹(shù)的每個(gè)節(jié)點(diǎn)最多只能有兩個(gè)子節(jié)點(diǎn)

什么是二叉搜索樹(shù)

二叉搜索樹(shù)在二叉樹(shù)的基礎(chǔ)上,多了一個(gè)條件,就是二叉樹(shù)在插入值時(shí),若插入值比當(dāng)前節(jié)點(diǎn)小,就插入到左節(jié)點(diǎn),否則插入到右節(jié)點(diǎn);若插入過(guò)程中,左節(jié)點(diǎn)或右節(jié)點(diǎn)已經(jīng)存在,那么繼續(xù)按如上規(guī)則比較,直到遇到一個(gè)新的節(jié)點(diǎn)。

二叉搜索樹(shù)的特性

二叉搜索樹(shù)由于其獨(dú)特的數(shù)據(jù)結(jié)構(gòu),使得其無(wú)論在增刪,還是查找,時(shí)間復(fù)雜度都是O(h),h為二叉樹(shù)的高度。因此二叉樹(shù)應(yīng)該盡量的矮,即左右節(jié)點(diǎn)盡量平衡。

二叉搜索樹(shù)的構(gòu)造

要構(gòu)造二叉搜索樹(shù),首先要構(gòu)造二叉樹(shù)的節(jié)點(diǎn)類(lèi)。由二叉樹(shù)的特點(diǎn)可知,每個(gè)節(jié)點(diǎn)類(lèi)都有一個(gè)左節(jié)點(diǎn),右節(jié)點(diǎn)以及值本身,因此節(jié)點(diǎn)類(lèi)如下:

class Node {
  constructor(key) {
    this.key = key;
    this.left = null;
    this.right = null;
  }
}

接著構(gòu)造二叉搜索樹(shù)

class Tree{
  constructor(param = null) {
    if (param) {
      this.root = new Node(param);
    } else {
      this.root = null;
    }
  }
}

這里this.root就是當(dāng)前對(duì)象的樹(shù)。

二叉搜索樹(shù)的新增

由二叉搜索樹(shù)左子樹(shù)比節(jié)點(diǎn)小,右子樹(shù)別節(jié)點(diǎn)大的特點(diǎn),可以很簡(jiǎn)單的寫(xiě)出二叉搜索樹(shù)新增的算法,如下:

insert(key) {
  if (this.root === null) {
    this.root = new Node(key);
  } else {
    this._insertNode(this.root, key);
  }
}
_insertNode(node, key) {
  if (key < node.key) {
    if (node.left === null) {
      node.left = new Node(key);{1}
    } else {
      this._insertNode(node.left, key);{2}
    }
  } else if (key > node.key) {
    if (node.right === null) {
      node.right = new Node(key);{3}
    } else {
      this._insertNode(node.right, key);{4}
    }
  }
}

如上代碼先判斷新增的key與當(dāng)前節(jié)點(diǎn)的key大小,如果小,就遞歸遍歷左子節(jié)點(diǎn),直到找到一個(gè)為null的左子節(jié)點(diǎn);如果比當(dāng)前節(jié)點(diǎn)大同理。如上代碼{1}{2}{3}{4}之所以能改變this.root的值,是由于JavaScript函數(shù)是按值傳遞,而當(dāng)參數(shù)是非基本類(lèi)型時(shí),例如這里的對(duì)象,其對(duì)象的值為內(nèi)存,因此每次都會(huì)直接改變this.root的內(nèi)容。

二叉搜索樹(shù)的遍歷

二叉搜索樹(shù)分為先序、中序、后序三種遍歷方式。

inOrderTraverse(callback) {
  this._inOrderTraverse(this.root, callback);
}
_inOrderTraverse(node, callback) {
  if (node) {
    this._inOrderTraverse(node.left, callback);
    callback(node.key);
    this._inOrderTraverse(node.right, callback);
  }
}

如上是中序遍歷。
這里需要理解的一點(diǎn)是遞歸。要知道,函數(shù)的執(zhí)行可以抽象為一種數(shù)據(jù)結(jié)構(gòu)——棧。針對(duì)函數(shù)的執(zhí)行,會(huì)維護(hù)一個(gè)棧,來(lái)存儲(chǔ)函數(shù)的執(zhí)行。函數(shù)在每一次遞歸時(shí),都會(huì)將當(dāng)前的執(zhí)行環(huán)境入棧并記錄執(zhí)行的位置。以上述代碼為例,有如下一個(gè)數(shù)據(jù)

其會(huì)從11開(kāi)始,執(zhí)行{1}入棧,然后進(jìn)入7,接著執(zhí)行{1}入棧,然后到5,執(zhí)行{1}入棧,再到3,執(zhí)行{1}入棧,此時(shí)發(fā)現(xiàn)節(jié)點(diǎn)3的左子節(jié)點(diǎn)為null,因此開(kāi)始出棧,此時(shí)彈出節(jié)點(diǎn)3的執(zhí)行環(huán)境,執(zhí)行{2},{3},發(fā)現(xiàn)3的右側(cè)子節(jié)點(diǎn)也為null,{3}的遞歸執(zhí)行完畢,接著彈出節(jié)點(diǎn)5,執(zhí)行{2}{3},接著彈出7,執(zhí)行{2}{3}入棧,執(zhí)行{3}時(shí),發(fā)現(xiàn)節(jié)點(diǎn)7有右節(jié)點(diǎn),因此繼續(xù)執(zhí)行{1},到節(jié)點(diǎn)8,再執(zhí)行{1},8沒(méi)有左子節(jié)點(diǎn),{1}執(zhí)行完畢,執(zhí)行{2}{3},以此類(lèi)推。
而前序與中序的不同點(diǎn)在于其先訪問(wèn)節(jié)點(diǎn)本身,也就是代碼的執(zhí)行順序?yàn)?2 1 3。
后序同理,執(zhí)行順序?yàn)? 3 2
不難發(fā)現(xiàn),無(wú)論前中后序,永遠(yuǎn)都是先遞歸左節(jié)點(diǎn),當(dāng)左節(jié)點(diǎn)遍歷完畢時(shí)再?gòu)棾鰲?,遍歷有節(jié)點(diǎn)。他們唯一不同的點(diǎn)在與訪問(wèn)該節(jié)點(diǎn)本身的時(shí)機(jī)。

二叉搜索樹(shù)的查找

查找很簡(jiǎn)單,根據(jù)左子節(jié)點(diǎn)比該節(jié)點(diǎn)小,右子節(jié)點(diǎn)比該節(jié)點(diǎn)大的原則進(jìn)行循環(huán)判斷即可。

search(value) {
  return this._search(value, this.root);
}
_search(value, node) {
  if (node === null) {
    return false;
  } else if (value > node.value) {
    return this._search(value, node.right);
  } else if (value < node.value) {
    return this._search(value, node.left);
  } else {
    return true;
  }
}
二叉搜索樹(shù)的刪除

刪除較為復(fù)雜,需要根據(jù)不同情況判斷
首先判斷該節(jié)點(diǎn)是否有左子樹(shù),如果沒(méi)有左子節(jié)樹(shù),則直接將右子樹(shù)的根節(jié)點(diǎn)替換被刪除節(jié)點(diǎn);
如果有,則將右子樹(shù)的最小節(jié)點(diǎn)替換被刪除節(jié)點(diǎn);

remove(value) {
  this.root = this._removeNode(this.root, value);
}
_removeNode(node, value) {
  if (!node) {
    return null;
  }
  if (value > node.value) {
    node.right = this._removeNode(node.right, value);
    return node;
  } else if (value < node.value) {
    console.log(value);
    node.left = this._removeNode(node.left, value);
    return node;
  } else {
    // 如果左右子節(jié)點(diǎn)都沒(méi)有
    if (!node.left && !node.right) {
      return null;
    }
    // 如果只有一個(gè)子節(jié)點(diǎn)
    if (node.left === null) {
      return node.right;
    }
    if (node.right === null) {
      return node.left;
    }
    // 如果同時(shí)擁有兩個(gè)節(jié)點(diǎn),就取有子節(jié)點(diǎn)最小值來(lái)替換當(dāng)前被刪除節(jié)點(diǎn)
    const minNode = this._minNode(node.right);
    node.value = minNode.value;
    node.right = this._removeNode(node.right, minNode.value);
    return node;
  }
}
總結(jié)

總的來(lái)說(shuō),通過(guò)這次簡(jiǎn)單的二叉搜索樹(shù)的學(xué)習(xí),讓我重新認(rèn)識(shí)了遞歸,以前對(duì)于遞歸的理解只是一些簡(jiǎn)單的理論概念,這次深入實(shí)踐讓我對(duì)遞歸的理解又加深了許多。
這讓我想到了數(shù)學(xué)的學(xué)習(xí),數(shù)學(xué)的理論公式是很容易記住掌握的,如果說(shuō)對(duì)一個(gè)知識(shí)點(diǎn)的掌握滿分是十分,那么直到真正去實(shí)踐它之前,只看公式的掌握只能是2分,因?yàn)楣胶芎?jiǎn)單,就幾句話幾個(gè)原則,但是遇到的問(wèn)題是千變?nèi)f化的,只有真正將理論付諸實(shí)踐,經(jīng)過(guò)各種實(shí)踐的打磨蹂躪,才能真正理解它其中的奧秘。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/88548.html

相關(guān)文章

  • 學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法二叉搜索樹(shù)

    摘要:二叉搜索樹(shù)是二叉樹(shù)的一種,其特征是左側(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)就在二叉搜索樹(shù)的最左反之,最大的就在最右。 本系列所有文章:第一篇文章:學(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)...

    denson 評(píng)論0 收藏0
  • PHPer面試必看:分門(mén)別類(lèi)帶你擼《劍指Offer》二叉樹(shù)

    摘要:例如輸入前序遍歷序列和中序遍歷序列,則重建二叉樹(shù)并返回。操作給定的二叉樹(shù),將其變換為源二叉樹(shù)的鏡像。劍指中還有一道類(lèi)似的變種題目,就是下面的這道,之字形遍歷二叉樹(shù)。最后下面的兩道題目分別運(yùn)用了二叉樹(shù)先序中序遍歷算法。 開(kāi)篇 以下內(nèi)容可能偏應(yīng)試但很好理解,所以大家一定要堅(jiān)持看下去,因?yàn)槲覀冏儚?qiáng)的過(guò)程注定孤獨(dú)的,堅(jiān)持下來(lái)就會(huì)看到明天的太陽(yáng)。 回顧 showImg(https://user-...

    li21 評(píng)論0 收藏0
  • 算法基礎(chǔ)二叉樹(shù)

    摘要:本文主要包括樹(shù)相關(guān)的算法,二叉樹(shù)結(jié)點(diǎn)基本結(jié)構(gòu)如下本文還會(huì)繼續(xù)更新。判斷是否平衡二叉樹(shù)判斷是否對(duì)稱二叉樹(shù)判斷是否完全二叉樹(shù)判斷是否滿二叉樹(shù)堆操作默認(rèn)大根堆獲取堆大小查看堆頂元素添加一個(gè)元素打印堆取出對(duì)頂元素 本文主要包括樹(shù)相關(guān)的算法,二叉樹(shù)結(jié)點(diǎn)基本結(jié)構(gòu)如下 function TreeNode(x) { this.val = x; this.left = null; this....

    趙連江 評(píng)論0 收藏0
  • Java TreeMap 源碼解析

    摘要:源碼剖析由于紅黑樹(shù)的操作我這里不說(shuō)了,所以這里基本上也就沒(méi)什么源碼可以講了,因?yàn)檫@里面重要的算法都是,這里的是指,他們是算法導(dǎo)論的作者,也就是說(shuō)里面算法都是參照算法導(dǎo)論的偽代碼。因?yàn)榧t黑樹(shù)是平衡的二叉搜索樹(shù),所以其包含操作的時(shí)間復(fù)雜度都為。 本文章首發(fā)于個(gè)人博客,鑒于sf博客樣式具有賞心悅目的美感,遂發(fā)表于此,供大家學(xué)習(xí)、批評(píng)。本文還在不斷更新中,最新版可移至個(gè)人博客。? 繼上篇文章...

    rubyshen 評(píng)論0 收藏0
  • 利用PHP實(shí)現(xiàn)常用的數(shù)據(jù)結(jié)構(gòu)二叉樹(shù)(小白系列文章五)

    摘要:回來(lái)更新一波,最近刷劍指,才又發(fā)現(xiàn)樹(shù)真是一個(gè)大頭,二叉樹(shù)的題目和變化運(yùn)用好多啊二叉樹(shù)算法引子很多人說(shuō)二叉樹(shù)沒(méi)什么卵用,我覺(jué)得是他的工資和公司讓他跨不過(guò)這個(gè)坎還有很多人學(xué)了一些樹(shù)的知識(shí),發(fā)現(xiàn)也用不上,我想說(shuō)的是,讀一本書(shū)體現(xiàn)不了這本書(shū) 回來(lái)更新一波,最近刷《劍指offer》,才又發(fā)現(xiàn)樹(shù)真是一個(gè)大頭,二叉樹(shù)的題目和變化運(yùn)用好多啊~ /** * PHP二叉樹(shù)算法 * Create...

    developerworks 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<