二叉樹的完成

觀點

二叉樹(Binary Tree)是另一種樹型構造,它的特點是每一個結點最多只要兩棵子樹(即二叉樹中不存在度大於 2 的結點),而且,二叉樹的子樹有擺布之分(其序次不能恣意倒置。)

性子

  • 二叉樹的第 i 層上最多有 2 的(i-1)方個節點。(i>=1)
  • 深度為 k 的樹最多有 2 的 k 次方-1 個節點。(k>=1)
  • 對任何一棵二叉樹 T,假如其終端結點數為 n0,度為 2 的結點數為 n2,則 n0 = n2 + 1;
    _ 一棵深度為 k 且有 2 的 k 次方-1 個結點的二叉樹稱為滿二叉樹
    _ 深度為 k 的,有 n 個結點的二叉樹,當且僅當其每一個結點都與深度為 k 的滿二叉樹中編號從 1 至 n 的結點一一對應時,稱之為完整二叉樹
    <!– more –>

初始化二叉樹構造

// 建立節點
class Node {
  constructor(key) {
    this.key = key
    this.left = null
    this.right = null
  }
}
// 建立二叉樹花樣
class BinaryTree {
  constructor(...args) {
    this.root = null
    // 初始化順次插進去數據
    args.forEach(key => {
      this.insert(key)
    })
  }
  // 實例化
  static create(args) {
    return new BinaryTree(...args)
  }
}

新增要領

思緒:推斷插進去的節點和當前節點,若大於當前節點,去右子樹插進去,不然左子樹插進去。

insert(key) {
  const newNode = new Node(key);
  const insertNode = function(node, newNode) {
    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);
      }
    }
  };
  if (this.root === null) {
    // 假如root不存在,將newNode設為根節點
    this.root = newNode
  } else {
    insertNode(this.root, newNode)
  }
}

挪用情勢

const nodes = [8, 3, 10, 1, 6, 14, 4, 7, 13]
const binaryTree = BinaryTree.create(nodes)
binaryTree.insert(55)
console.log(binaryTree.root)

遍歷要領

二叉樹的遍歷(traversing binary tree)是指從根結點動身,依據某種序次順次接見二叉樹中所有結點,使得每一個結點被接見一次且僅被接見一次。

前序遍歷(DLR)

起首接見根結點,然後遍歷左子樹,末了遍歷右子樹。簡記根-左-右。

  • 用處:用於複製一顆二叉樹
  • 算法思緒
    若二叉樹為空,則遍歷完畢;不然 1. 接見根結點 2. 先序遍歷左子樹(遞歸挪用本算法) 3. 先序遍歷右子樹(遞歸挪用本算法)
// 前序遍歷
preOrderTraverse () {
    const preOrderTraverse = node => {
      if (node !== null) {
        console.log(node.key)
        preOrderTraverse(node.left)
        preOrderTraverse(node.right)
      }
    }
    preOrderTraverse(this.root)
}

中序遍歷(LDR)

起首遍歷左子樹,然後接見根結點,末了遍歷右子樹。簡記左-根-右。

  • 用處:用於從小到大排序二叉樹
  • 算法思緒
    若二叉樹為空,則遍歷完畢;不然 1. 中序遍歷左子樹(遞歸挪用本算法) 2. 接見根結點 3. 中序遍歷右子樹(遞歸挪用本算法)
//運用遞歸體式格局完成中序遍歷
inOrderTraverse () {
    const inOrderTraverseNode = node => {
      if (node !== null) {
        // 假如當前節點非空,則接見左子樹
        inOrderTraverseNode(node.left)
        // 直到接見到最底部的左子樹才進入callback,每一個節點都邑有callback
        console.log(node.key)
        // 此時已經是最底部的左子樹
        inOrderTraverseNode(node.right)
      }
      // 詮釋:起首進入8,發明左側有3,實行左側遍歷,遍歷完后實行3的回調,在實行3的右側的回調,
    }
    inOrderTraverseNode(this.root)
}

後序遍歷(LRD)

起首遍歷左子樹,然後遍歷右子樹,末了接見根結點。簡記左-右-根。

  • 算法思緒
    若二叉樹為空,則遍歷完畢;不然 1. 後序遍歷左子樹(遞歸挪用本算法); 2. 後序遍歷右子樹(遞歸挪用本算法) ; 3. 接見根結點 。
postOrderTraverse () {
    const postOrderTraverse = node => {
      if (node !== null) {
        postOrderTraverse(node.left)
        postOrderTraverse(node.right)
        console.log(node.key)
      }
    }
    postOrderTraverse(this.root)
  }

查找算法

查找最大值

思緒:傳入二叉樹,尋覓右子樹,直到找到不存在右子樹的節點。

// 查找最大值
max () {
    const maxNode = node => {
      if (node !== null) {
        if (node.right) {
          return maxNode(node.right)
        } else {
          return node.key
        }
      }
    }
    return maxNode(this.root)
}

查找最小值

思緒:傳入二叉樹,尋覓左子樹,直到找到不存在左子樹的節點。

// 查找最小值
min () {
    const minNode = node => {
      if (node !== null) {
        if (node.left) {
          return minNode(node.left)
        } else {
          return node.key
        }
      }
    }
    return minNode(this.root)
}

查找恣意值

思緒:依據傳入的 key 與當前節點比較,假如大於當前 key 則去右子樹查找,不然去左子樹查找。

// 查找指定值
search (key) {
  const 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
    }
  }
  return searchNode(this.root, key)
}

刪除算法

思緒:假如刪除的 key 小於當前節點,去左子樹種查找,不然去右子樹查找。找到節點后,推斷是不是存在子節點,若不存在,直接刪除,若只存在左節點或許右節點,將當前節點替換為它的子節點。若擺布節點都存在,將右節點中的最小值(左子樹)移除並替換為刪除的節點位置(為了滿足二叉樹的左子樹小於右子樹)

remove (key) {
  // 用於查找最小節點
  const findMinNode = node => {
    if (node) {
      // 假如node的左孩子存在
      while (node && node.left !== null) {
        // 將node設為node的左孩子再次進入輪迴
        node = node.left
      }
      // 直到返回沒有左孩子的node
      return node
    }
  }
  const removeNode = (node, key) => {
    if (node === null) {
      return false
    }
    if (key < node.key) {
      // 當前node大於刪除key,去左孩子中查找
      node.left = removeNode(node.left, key)
      return node
    } else if (key > node.key) {
      // 當前node小於刪除key,去右孩子中查找
      node.right = removeNode(node.right, key)
    } else {
      // key和當前node相稱
      if (node.left === null && node.right === null) {
        node = null
        return node
      }
      // 恣意一邊沒有值,取另一邊
      if (node.left === null) {
        node = node.right
        return node
      } else if (node.right === null) {
        node = node.left
        return node
      }
      // 同時存在左孩子和右孩子
      // 找出右側的最小值
      const aux = findMinNode(node.right)
      // 將最小值替換為刪除的key
      node.key = aux.key
      // 在右孩子中刪除最小值
      node.right = removeNode(node.right, aux.key)
      return node
    }
  }
  const result = removeNode(this.root, key)
  console.log(result)
}
    原文作者:影綽
    原文地址: https://segmentfault.com/a/1190000015357630
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞