javascript生成二叉樹,前中後序遍歷

**二叉樹是一種數據結構。其特色是:javascript

1.由一系列節點組成,具備層級結構。每一個節點的特性包含有節點值、關係指針。節點之間存在對應關係。java

2.樹中存在一個沒有父節點的節點,叫作根節點。樹的末尾存在一系列沒有子節點的節點,稱爲葉子節點。其餘能夠叫作中間節點。node

3.樹的根節點位於第一層,層級數越大,節點位置越深,層級數也叫作樹高。算法

**排序二叉樹爲二叉樹的一種類型,其特色是:數據結構

1.節點分爲左右子樹。this

2.在不爲空的狀況下,左子樹子節點的值都小於父節點的值。spa

3.在不爲空的狀況下,右子樹子節點的值都大於父節點的值。debug

4.每一個節點的左右子樹都按照上述規則排序。
image.png指針

(一)生成二叉樹

// 將值生成節點,節點包括:節點值、左指針、右指針
class Node {
  constructor(key) {
    this.key = key;
    this.left = null;
    this.right = null;
  }
}
// 二叉樹
class BinaryTree {
  constructor() {
    this.root = null; // 根節點
  }
  // 插入,插入的是一個節點,因此應該先把值生成節點(包括節點值,左指針,右指針)
  insert(key) {
    const newNode = new Node(key);
    // 若是根節點爲空,則新節點做爲根節點,不然在根節點下進行插入
    if (this.root === null) {
      this.root = newNode;
    }
    this.insertNode(this.root, newNode);
  }

  // 有根節點的狀況下插入值
  insertNode(root, newNode) {
    if (newNode.key < root.key) {
      // 進入左子樹
      if (root.left === null) {
        // 左子樹爲空
        root.left = newNode;
      } else {
        // 左子樹已存在
        this.insertNode(root.left, newNode);
      }
    } else if (newNode.key > root.key) {
      // 進入右子樹
      if (root.right === null) {
        // 右子樹爲空
        root.right = newNode;
      } else {
        // 右子樹已存在
        this.insertNode(root.right, newNode);
      }
    }
  }
}
const binaryTree = new BinaryTree();
var keys = [19, 8, 15, 24, 45, 12, 5];
keys.forEach((key) => binaryTree.insert(key));
console.log(binaryTree);

image.png

(二)二叉樹的遍歷

1. 中序遍歷

(1)遞歸方法

// 中序遍歷:遞歸方法
var inorderTraversal = function (root) {
  var result = [];
  pushRoot(root, result);
  return result;
};
function pushRoot(root, result) {
  if (root !== null) {
    // 左
    if (root.left !== null) {
      pushRoot(root.left, result);
    }
    // 中
    result.push(root.key);
    // 右
    if (root.right !== null) {
      pushRoot(root.right, result);
    }
  }
}

// 注意這裏傳入的是binaryTree.root,而不是binaryTree
inorderTraversal(binaryTree.root); // [5, 8, 12, 15, 19, 24, 45]

(2)非遞歸方法(棧)

var inorderTraversal = function (root) {
  let result = [];
  let stack = [];
  let node = root;
  while (node !== null || stack.length !== 0) {
    if (node !== null) {
      stack.push(node);
      node = node.left; // 遍歷左,存入棧中
    } else {
      debugger;
      // node===null時說明左邊沒有了,那麼棧頂就是最左邊的(最小的)
      node = stack.pop();
      result.push(node.key);
      node = node.right; //看右邊有沒有
    }
  }
  console.log(result); // [5, 8, 12, 15, 19, 24, 45]

  return result;
};

inorderTraversal(binaryTree.root);

2.前序遍歷

(1)遞歸方法

// 前序遍歷 遞歸
var preOrderTraversal = function (root) {
  var res = [];
  preOrder(root, res);
  return res;
};
function preOrder(root, res) {
  if (root !== null) {
    // 中
    res.push(root.key);
    // 左
    preOrder(root.left, res);
    // 右
    preOrder(root.right, res);
  }
}
console.log(preOrderTraversal(binaryTree.root)); // [19, 8, 5, 15, 12, 24, 45]

(2)非遞歸方法(棧)

var preOrderTraversal = function (root) {
  var res = [];
  var stack = [];
  var node = root;
  while (node !== null || stack.length !== 0) {
    if (node !== null) {
      res.push(node.key);
      stack.push(node);
      node = node.left;
    } else {
      node = stack.pop();
      node = node.right;
    }
  }
  return res
};
console.log(preOrderTraversal(binaryTree.root)) // [19, 8, 5, 15, 12, 24, 45]

3.後序遍歷

(1)遞歸方法

var afterOrderTraversal = function (root) {
  var res = [];
  afterOrder(root, res);
  return res;
};
function afterOrder(root, res) {
  if (root !== null) {
    // 左
    afterOrder(root.left, res);
    // 右
    afterOrder(root.right, res);
    // 中
    res.push(root.key);
  }
}
console.log(afterOrderTraversal(binaryTree.root)); // [5, 12, 15, 8, 45, 24, 19]

(2)非遞歸方法

首先要搞清楚先序、中序、後序的非遞歸算法共同之處:用棧來保存先前走過的路徑,以即可以在訪問完子樹後,能夠利用棧中的信息,回退到當前節點的雙親節點,進行下一步操做。code

後序遍歷的非遞歸算法是三種順序中最複雜的,緣由在於,後序遍歷是先訪問左、右子樹,再訪問根節點,而在非遞歸算法中,利用棧回退到時,並不知道是從左子樹回退到根節點,仍是從右子樹回退到根節點,若是從左子樹回退到根節點,此時就應該去訪問右子樹,而若是從右子樹回退到根節點,此時就應該訪問根節點。因此相比前序和後序,必須得在壓棧時添加信息,以便在退棧時能夠知道是從左子樹返回,仍是從右子樹返回進而決定下一步的操做。

相關文章
相關標籤/搜索