二叉樹

本文內(nèi)容學習自JavaScript實現(xiàn)二叉樹


二叉樹

  • 二叉樹是每個節(jié)點最多有兩個子樹的樹結(jié)構(gòu)压昼。通常子樹被稱左子樹右子樹

  • 二叉樹的每個結(jié)點至多只有二棵子樹(不存在度大于2的結(jié)點)瘤运,二叉樹的子樹有左右之分窍霞,次序不能顛倒。

  • 二叉樹的第i層至多有2^{i-1} 個結(jié)點(頂層為第一層)

二叉樹遍歷

  • 前序遍歷就是先訪問樹的根節(jié)點拯坟,再訪問樹的左子節(jié)點但金,再訪問右子節(jié)點。

  • 中序遍歷就是先訪問樹的左子節(jié)點郁季,再訪問樹的根節(jié)點冷溃,再訪問右子節(jié)點。

  • 后序遍歷就是先訪問樹的左子節(jié)點梦裂,再訪問樹的右子節(jié)點似枕,再訪問根節(jié)點。



創(chuàng)建二叉樹

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>二叉樹</title>
  </head>
  <body>
    <script>
      function BinaryTree() {

        //創(chuàng)建節(jié)點
        var Node = function (key) {
          this.key = key;
          this.left = null;
          this.right = null;
        }

        //創(chuàng)建根節(jié)點
        var root = null;
        this.insert = function (key) { //創(chuàng)建二叉樹數(shù)據(jù)結(jié)構(gòu)
          var newNode = new Node(key);
          if (root === null) {
            root = newNode;
          } else {
            insertNode(root, newNode);
          }
        }
        var insertNode = function (node, newNode) { // 比較節(jié)點年柠,插入到相應節(jié)點的左右節(jié)點上
          if (newNode.key < node.key) {
            if (node.left === null) {
              node.left = newNode;
            } else {
              insertNode(node.left, newNode);
            }
          } else {
            if (node.right === null) {
              node.right = newNode;
            } else {
              insertNode(node.right, newNode);
            }
          }
        }
      }
    </script>
  </body>
</html>

中序遍歷

      // 中序遍歷
        this.inOrderTraverse = function (callback) {
          inOrderTraverseNode(root, callback);
        }
        var inOrderTraverseNode = function (node, callback) {
          if (node !== null) {
            inOrderTraverseNode(node.left, callback);
            callback(node.key);
            inOrderTraverseNode(node.right, callback);
          }
        }
      var callback = function (key) {
        console.log(key);
      }

前序遍歷

// 前序遍歷
        this.preOrderTraverse = function (callback) {
          preOrderTraverseNode(root, callback);
        }
        var preOrderTraverseNode = function (node, callback) {
          if (node !== null) {
            callback(node.key);
            preOrderTraverseNode(node.left, callback);
            preOrderTraverseNode(node.right, callback);
          }
        }
      var callback = function (key) {
        console.log(key);
      }

后序遍歷

        this.postOrderTraverse = function (callback) {
          postOrderTraverseNode(root, callback);
        }
        var postOrderTraverseNode = function (node, callback) {
          if (node !== null) {
            postOrderTraverseNode(node.left, callback);
            postOrderTraverseNode(node.right, callback);
            callback(node.key);
          }
        }
      var callback = function (key) {
        console.log(key);
      }

最小值

        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.search = function (key) {
          return searchNode(root, key);
        }
        var searchNode = function (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;
          }
        }

刪除末節(jié)點

        this.remove = function (key) {
          root = removeNode(root, key);
        }
        var removeNode = function (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 {
            if (node.left === null && node.right === null) {
              node = null;
              return node;
            }
          }
        }

刪除節(jié)點 包括末節(jié)點中間節(jié)點

        this.remove = function (key) {
          root = removeNode(root, key);
        }
        var removeNode = function (node, key) {
          if (node === null) {
            return null;
          }
          if (key < node.key) { // 小于此節(jié)點的key凿歼,node賦值為 node.left 繼續(xù)遍歷
            node.left = removeNode(node.left, key);
            return node;
          } else if (key > node.key) { // 大于此節(jié)點的key,node賦值為 node.right 繼續(xù)遍歷
            node.right = removeNode(node.right, key);
            return node;
          } else { // 等于此節(jié)點的key 冗恨, 1 末節(jié)點 答憔, 2 中間節(jié)點

            // 末節(jié)點直接把此key賦值為null
            if (node.left === null && node.right === null) {
              node = null;
              return node;
            }
            // 中間節(jié)點
            // 1,有right 或 left時掀抹,把此節(jié)點的left或right賦值為node = node.left 或 node = node.right
            if (node.left === null) {
              node = node.right;
              return node;
            } else if (node.right === null) {
              node = node.left;
              return node;
            }
            // 2攀唯,同時有right和left , 找到此節(jié)點右側(cè)的最小值賦值  node = node.right的最小值
            var aux = findMinNode(node.right);
            node.key = aux.key;
            node.right = removeNode(node.right, aux.key);
            return node;
          }
        }
        //找到最小節(jié)點
        var findMinNode = function (node) {
          if (node) {
            while (node && node.left !== null) {
              node = node.left;
            }
            return node;
          }
          return null;
        }

完整代碼

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>二叉樹</title>
  </head>
  <body>
    <script>
      function BinaryTree() {

        //創(chuàng)建節(jié)點
        var Node = function (key) {
          this.key = key;
          this.left = null;
          this.right = null;
        }

        //創(chuàng)建根節(jié)點
        var root = null;
        this.insert = function (key) { //創(chuàng)建二叉樹數(shù)據(jù)結(jié)構(gòu)
          var newNode = new Node(key);
          if (root === null) {
            root = newNode;
          } else {
            insertNode(root, newNode);
          }
        }
        var insertNode = function (node, newNode) { // 比較節(jié)點渴丸,插入到相應節(jié)點的左右節(jié)點上
          if (newNode.key < node.key) {
            if (node.left === null) {
              node.left = newNode;
            } else {
              insertNode(node.left, newNode);
            }
          } else {
            if (node.right === null) {
              node.right = newNode;
            } else {
              insertNode(node.right, newNode);
            }
          }
        }

        // 中序遍歷
        this.inOrderTraverse = function (callback) {
          inOrderTraverseNode(root, callback);
        }
        var inOrderTraverseNode = function (node, callback) {
          if (node !== null) {
            inOrderTraverseNode(node.left, callback);
            callback(node.key);
            inOrderTraverseNode(node.right, callback);
          }
        }

        // 前序遍歷
        this.preOrderTraverse = function (callback) {
          preOrderTraverseNode(root, callback);
        }
        var preOrderTraverseNode = function (node, callback) {
          if (node !== null) {
            callback(node.key);
            preOrderTraverseNode(node.left, callback);
            preOrderTraverseNode(node.right, callback);
          }
        }

        // 后序遍歷
        this.postOrderTraverse = function (callback) {
          postOrderTraverseNode(root, callback);
        }
        var postOrderTraverseNode = function (node, callback) {
          if (node !== null) {
            postOrderTraverseNode(node.left, callback);
            postOrderTraverseNode(node.right, callback);
            callback(node.key);
          }
        }

        // 最小值
        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.search = function (key) {
          return searchNode(root, key);
        }
        var searchNode = function (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;
          }
        }

        // 刪除末節(jié)點
        // this.remove = function (key) {
        //   root = removeNode(root, key);
        // }
        // var removeNode = function (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 {
        //     if (node.left === null && node.right === null) {
        //       node = null;
        //       return node;
        //     }
        //   }
        // }

        // 刪除節(jié)點
        this.remove = function (key) {
          root = removeNode(root, key);
        }
        var removeNode = function (node, key) {
          if (node === null) {
            return null;
          }
          if (key < node.key) { // 小于此節(jié)點的key,node賦值為 node.left 繼續(xù)遍歷
            node.left = removeNode(node.left, key);
            return node;
          } else if (key > node.key) { // 大于此節(jié)點的key,node賦值為 node.right 繼續(xù)遍歷
            node.right = removeNode(node.right, key);
            return node;
          } else { // 等于此節(jié)點的key 谱轨, 1 末節(jié)點 戒幔, 2 中間節(jié)點

            // 末節(jié)點直接把此key賦值為null
            if (node.left === null && node.right === null) {
              node = null;
              return node;
            }
            // 中間節(jié)點
            // 1,有right 或 left時土童,把此節(jié)點的left或right賦值為node = node.left 或 node = node.right
            if (node.left === null) {
              node = node.right;
              return node;
            } else if (node.right === null) {
              node = node.left;
              return node;
            }
            // 2诗茎,同時有right和left , 找到此節(jié)點右側(cè)的最小值賦值  node = node.right的最小值
            var aux = findMinNode(node.right);
            node.key = aux.key;
            node.right = removeNode(node.right, aux.key);
            return node;
          }
        }
        //找到最小節(jié)點
        var findMinNode = function (node) {
          if (node) {
            while (node && node.left !== null) {
              node = node.left;
            }
            return node;
          }
          return null;
        }

      }
      var callback = function (key) {
        console.log(key);
      }

      var nodes = [8, 3, 10, 1, 6, 14, 4, 7, 13];
      var binaryTree = new BinaryTree();
      nodes.forEach(function (key) {
        binaryTree.insert(key);
      })
      console.log('------中序遍歷---------')
      binaryTree.inOrderTraverse(callback);
      console.log('------前序遍歷---------')
      binaryTree.preOrderTraverse(callback);
      console.log('------后序遍歷---------')
      binaryTree.postOrderTraverse(callback);
      console.log('------最小值---------')
      console.log(binaryTree.min());
      console.log('------最大值---------')
      console.log(binaryTree.max());
      console.log('------某個值---------')
      console.log(binaryTree.search(3));
      console.log(binaryTree.search(2));
      // console.log('------刪除末節(jié)點‘1’值---------')
      // binaryTree.remove(1);
      // binaryTree.postOrderTraverse(callback);
      console.log('------刪除節(jié)點3---------')
      binaryTree.remove(3);
      binaryTree.postOrderTraverse(callback);
    </script>
  </body>
</html>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末献汗,一起剝皮案震驚了整個濱河市敢订,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌罢吃,老刑警劉巖楚午,帶你破解...
    沈念sama閱讀 222,946評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異尿招,居然都是意外死亡矾柜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評論 3 399
  • 文/潘曉璐 我一進店門就谜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怪蔑,“玉大人,你說我怎么就攤上這事丧荐±掳辏” “怎么了?”我有些...
    開封第一講書人閱讀 169,716評論 0 364
  • 文/不壞的土叔 我叫張陵虹统,是天一觀的道長弓坞。 經(jīng)常有香客問我,道長窟却,這世上最難降的妖魔是什么昼丑? 我笑而不...
    開封第一講書人閱讀 60,222評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮夸赫,結(jié)果婚禮上菩帝,老公的妹妹穿的比我還像新娘。我一直安慰自己茬腿,他們只是感情好呼奢,可當我...
    茶點故事閱讀 69,223評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著切平,像睡著了一般握础。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悴品,一...
    開封第一講書人閱讀 52,807評論 1 314
  • 那天禀综,我揣著相機與錄音简烘,去河邊找鬼。 笑死定枷,一個胖子當著我的面吹牛孤澎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播欠窒,決...
    沈念sama閱讀 41,235評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼覆旭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了岖妄?” 一聲冷哼從身側(cè)響起型将,我...
    開封第一講書人閱讀 40,189評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荐虐,沒想到半個月后七兜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,712評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡缚俏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,775評論 3 343
  • 正文 我和宋清朗相戀三年惊搏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忧换。...
    茶點故事閱讀 40,926評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡恬惯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亚茬,到底是詐尸還是另有隱情酪耳,我是刑警寧澤,帶...
    沈念sama閱讀 36,580評論 5 351
  • 正文 年R本政府宣布刹缝,位于F島的核電站碗暗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏梢夯。R本人自食惡果不足惜言疗,卻給世界環(huán)境...
    茶點故事閱讀 42,259評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望颂砸。 院中可真熱鬧噪奄,春花似錦、人聲如沸人乓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽色罚。三九已至碰缔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間戳护,已是汗流浹背金抡。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評論 1 274
  • 我被黑心中介騙來泰國打工瀑焦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人梗肝。 一個月前我還...
    沈念sama閱讀 49,368評論 3 379
  • 正文 我出身青樓蝠猬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親统捶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,930評論 2 361

推薦閱讀更多精彩內(nèi)容