資料結構與演算法簡記:按層次順序遍歷和儲存二叉樹
阿新 • • 發佈:2019-02-09
前面曾經記錄過,給出一個按層次順序排放的儲存資料,進而可以構建出一棵二叉樹,今天就來簡單記錄一下,如何按層次順序遍歷二叉樹,最後又如何根據二叉樹生成按層次順序儲存的資料,對於滿二叉樹來講,這十分有必要。
對與這棵二叉樹來說,它的層次遍歷順序和層次儲存順序分別為:
A B E C D F
A B E C D # F
按層次遍歷思路:
- 首先將根節點放入佇列。
- 取出隊首元素並訪問該節點,然後探索其左子樹,如果左子樹不為空,則重複步驟1,之後再探索右子樹,如果右子樹不為空,則同樣重複步驟1。
- 重複步驟2。
按層次儲存思路:
上面的按層次遍歷不能用來儲存,原因是某些位置的空節點直接被跳過了,如果我們想要生成一份用來儲存的資料,這些節點必須使用特殊符號佔位的,所以需要在原來基礎上稍作改動:
- 對於一個節點來講,如果不存在左子節點,則將一個佔位節點放入佇列,同樣,如果不存在右子節點,則將一個佔位節點放入佇列。
- 在取出隊首元素後,如果這個節點是佔位節點,則無需探索左右子節點,直接進行下一輪遍歷。
- 遍歷完成後,儲存資料的末端會有一些冗餘的佔位節點,移除即可。
還是先來個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);
}