1. 程式人生 > >資料結構與演算法簡記:按層次順序遍歷和儲存二叉樹

資料結構與演算法簡記:按層次順序遍歷和儲存二叉樹

前面曾經記錄過,給出一個按層次順序排放的儲存資料,進而可以構建出一棵二叉樹,今天就來簡單記錄一下,如何按層次順序遍歷二叉樹,最後又如何根據二叉樹生成按層次順序儲存的資料,對於滿二叉樹來講,這十分有必要。

對與這棵二叉樹來說,它的層次遍歷順序和層次儲存順序分別為:

A B E C D F
A B E C D # F

按層次遍歷思路:

  1. 首先將根節點放入佇列。
  2. 取出隊首元素並訪問該節點,然後探索其左子樹,如果左子樹不為空,則重複步驟1,之後再探索右子樹,如果右子樹不為空,則同樣重複步驟1。
  3. 重複步驟2。

按層次儲存思路:

上面的按層次遍歷不能用來儲存,原因是某些位置的空節點直接被跳過了,如果我們想要生成一份用來儲存的資料,這些節點必須使用特殊符號佔位的,所以需要在原來基礎上稍作改動:

  1. 對於一個節點來講,如果不存在左子節點,則將一個佔位節點放入佇列,同樣,如果不存在右子節點,則將一個佔位節點放入佇列。
  2. 在取出隊首元素後,如果這個節點是佔位節點,則無需探索左右子節點,直接進行下一輪遍歷。
  3. 遍歷完成後,儲存資料的末端會有一些冗餘的佔位節點,移除即可。

還是先來個JS版的吧,JS中的陣列是天然的佇列,再方便不過了:

//二叉樹節點結構
function BinTreeNode(data) {
  this.data = data;
  this.leftChild = null;
  this.rightChild = null;
}

//按層次遍歷
function traverseByLevel
(node, visitFn) {
if (!node) return; //佇列 var queue = []; //根節點入隊 queue.push(node); while (queue.length) { //隊首元素出隊 node = queue.shift(); //訪問節點 visitFn(node); //如果左子節點存在,則將其入隊 if (node.leftChild) queue.push(node.leftChild); //如果右子節點存在,則將其入隊 if (node.rightChild) queue.push(node.rightChild); } } //按層次儲存
function preserveByLevel(node) { if (!node) return; //佇列 var queue = []; //根節點入隊 queue.push(node); //順序儲存資料 var storage = []; //佔位節點 var holderNode = new BinTreeNode('#'); while (queue.length) { //隊首元素出隊 node = queue.shift(); //儲存當前節點資料 storage.push(node.data); //如果隊首的節點為佔位節點,則不再繼續探索其左右節點了 if (node.data === '#') continue; //將左子節點或佔位節點入隊 if (node.leftChild) { queue.push(node.leftChild); } else { queue.push(holderNode); } //將右子節點或佔位節點入隊 if (node.rightChild) { queue.push(node.rightChild); } else { queue.push(holderNode); } } //接下來移除末端多餘的佔位符 var data = storage[storage.length - 1]; while (data === '#') { //移除末端佔位符 storage.pop(); data = storage[storage.length - 1]; } console.log(storage); }