資料結構與演算法簡記:通過前序中序或中序後序構建二叉樹
阿新 • • 發佈:2019-02-15
上次記錄了廣義表生成二叉樹的過程,我們也可以通過前序和中序,或者中序和後序,來確定和構建一棵唯一的二叉樹。
還是同樣的圖,它的前序,中序,後序遍歷序列分別是:
pre: ABCDEF
in: CBDAEF
post: CDBFEA
以下是通過前序和中序構建二叉樹的過程:
- 獲取前序字串的第一個字元A,它作為當前根節點,然後掃描中序字串,找到A的位置,建立根節點儲存結構。
- 然後在中序字串中確定左子樹中序為CBD,再去前序字串中擷取相同長度的子串,確定左子樹前序為BCD,有了左子樹的前序和中序,就可以遞迴呼叫建立左子樹,跟當前根節點關聯起來。
- 同樣地,我們可以確定右子樹的前序為EF,中序為EF,然後遞迴呼叫建立右子樹,跟當前根節點關聯起來。
- 整個過程是遞迴的,直到前序和中序字串只有一個字元時,直接建立葉子節點並跟父節點關聯起來。
通過中序和後序構建二叉樹跟上述過程類似,由後序確定當前根節點後,再通過中序確定左子樹和右子樹序列,然後遞迴建立左子樹和右子樹,並與當前根節點關聯。
下面是實現程式碼:
JS版:
//二叉樹節點結構
function BinTreeNode(data) {
this.data = data;
this.leftChild = null;
this.rightChild = null;
}
//根據前序和中序建立二叉樹
function createBinTreeByPreIn(preOrder, inOrder) {
//如果只剩一個字元,則直接建立節點並返回
if (preOrder.length === 1) {
return new BinTreeNode(preOrder.charAt(0));
}
//從前序獲取當前根節點字元
var c = preOrder.charAt(0);
//中序索引和前序節點個數
var i = 0;
var number = preOrder.length;
//遍歷中序序列,直到發現當前根節點
while (i < number && inOrder.charAt(i) != c) i++;
//求出左子樹和右子樹節點個數
var leftNumber = i;
var rightNumber = number - i - 1;
//建立當前根節點
var node = new BinTreeNode(c);
//建立左子樹
if (leftNumber >= 1) {
var leftPre = preOrder.substring(1, 1 + leftNumber);
var leftIn = inOrder.substring(0, leftNumber);
node.leftChild = createBinTreeByPreIn(leftPre, leftIn);
}
//建立右子樹
if (rightNumber >= 1) {
var rightPre = preOrder.substring(leftNumber + 1);
var rightIn = inOrder.substring(leftNumber + 1);
node.rightChild = createBinTreeByPreIn(rightPre, rightIn);
}
//返回當前根節點
return node;
}
//根據中序和後序建立二叉樹
function createBinTreeByInPost(inOrder, postOrder) {
//如果只剩一個字元,則直接建立節點並返回
if (postOrder.length === 1) {
return new BinTreeNode(postOrder.charAt(0));
}
//從後序獲取當前根節點字元
var c = postOrder.charAt(postOrder.length - 1);
//中序索引和前序節點個數
var i = 0;
var number = postOrder.length;
//遍歷中序序列,直到發現當前根節點
while (i < number && inOrder.charAt(i) != c) i++;
//求出左子樹和右子樹節點個數
var leftNumber = i;
var rightNumber = number - i - 1;
//建立當前根節點
var node = new BinTreeNode(c);
//建立左子樹
if (leftNumber >= 1) {
var leftIn = inOrder.substring(0, leftNumber);
var leftPost = postOrder.substring(0, leftNumber);
node.leftChild = createBinTreeByInPost(leftIn, leftPost);
}
//建立右子樹
if (rightNumber >= 1) {
var rightIn = inOrder.substring(leftNumber + 1);
var rightPost = postOrder.substring(leftNumber, postOrder.length - 1);
node.rightChild = createBinTreeByInPost(rightIn, rightPost);
}
//返回當前根節點
return node;
}
//前序遍歷
function preOrderTraverse(node, orderArray) {
if (node) {
orderArray.push(node.data);
preOrderTraverse(node.leftChild, orderArray);
preOrderTraverse(node.rightChild, orderArray);
}
}
//後序遍歷
function postOrderTraverse(node, orderArray) {
if (node) {
postOrderTraverse(node.leftChild, orderArray);
postOrderTraverse(node.rightChild, orderArray);
orderArray.push(node.data);
}
}
//前序,中序,後序
var preOrder = 'ABCDEF';
var inOrder = 'CBDAEF';
var postOrder = 'CDBFEA';
//根據前序和中序建立二叉樹
var binTree = createBinTreeByPreIn(preOrder, inOrder);
//用於存放節點遍歷序列
var orderArray = [];
//後序遍歷驗證其正確性
postOrderTraverse(binTree, orderArray);
console.log('post order: ', orderArray.join(' '));
//清空遍歷序列陣列
orderArray.length = 0;
//根據中序和後序建立二叉樹
binTree = createBinTreeByInPost(inOrder, postOrder);
//前序遍歷驗證其正確性
preOrderTraverse(binTree, orderArray);
console.log('pre order: ', orderArray.join(' '));
Java版:
//BinTreeNode.java
package algorithm;
//二叉樹節點結構
public class BinTreeNode {
private char data;
private BinTreeNode leftChild;
private BinTreeNode rightChild;
public BinTreeNode(char data) {
this.data = data;
}
public char getData() {
return data;
}
public void setData(char data) {
this.data = data;
}
public BinTreeNode getLeftChild() {
return leftChild;
}
public void setLeftChild(BinTreeNode leftChild) {
this.leftChild = leftChild;
}
public BinTreeNode getRightChild() {
return rightChild;
}
public void setRightChild(BinTreeNode rightChild) {
this.rightChild = rightChild;
}
}
//BinTreeCreator.java
package algorithm;
public class BinTreeCreator {
//根據前序和中序建立二叉樹
public static BinTreeNode createBinTreeByPreIn(String pre, String in) {
if (pre.length() == 1) {
return new BinTreeNode(pre.charAt(0));
}
char c = pre.charAt(0);
int i = 0;
int number = pre.length();
while (i < number && in.charAt(i) != c) i++;
int leftNumber = i;
int rightNumber = number - i - 1;
BinTreeNode node = new BinTreeNode(c);
if (leftNumber >= 1) {
String leftPre = pre.substring(1, 1 + leftNumber);
String leftIn = in.substring(0, leftNumber);
node.setLeftChild(createBinTreeByPreIn(leftPre, leftIn));
}
if (rightNumber >= 1) {
String rightPre = pre.substring(leftNumber + 1);
String rightIn = in.substring(leftNumber + 1);
node.setRightChild(createBinTreeByPreIn(rightPre, rightIn));
}
return node;
}
//根據中序和後序建立二叉樹
public static BinTreeNode createBinTreeByInPost(String in, String post) {
if (post.length() == 1) {
return new BinTreeNode(post.charAt(0));
}
char c = post.charAt(post.length() - 1);
int i = 0;
int number = post.length();
while (i < number && in.charAt(i) != c) i++;
int leftNumber = i;
int rightNumber = number - i - 1;
BinTreeNode node = new BinTreeNode(c);
if (leftNumber >= 1) {
String leftIn = in.substring(0, leftNumber);
String leftPost = post.substring(0, leftNumber);
node.setLeftChild(createBinTreeByInPost(leftIn, leftPost));
}
if (rightNumber >= 1) {
String rightIn = in.substring(leftNumber + 1);
String rightPost = post.substring(leftNumber, post.length() - 1);
node.setRightChild(createBinTreeByInPost(rightIn, rightPost));
}
return node;
}
//前序遍歷
public static void preOrderTraverse(BinTreeNode node) {
if (node != null) {
System.out.print(node.getData());
preOrderTraverse(node.getLeftChild());
preOrderTraverse(node.getRightChild());
}
}
//後序遍歷
public static void postOrderTraverse(BinTreeNode node) {
if (node != null) {
postOrderTraverse(node.getLeftChild());
postOrderTraverse(node.getRightChild());
System.out.print(node.getData());
}
}
public static void main(String[] args) {
String pre = "ABCDEF";
String in = "CBDAEF";
String post = "CDBFEA";
BinTreeNode rootNode = BinTreeCreator.createBinTreeByPreIn(pre, in);
System.out.print("post order: ");
BinTreeCreator.postOrderTraverse(rootNode);
rootNode = BinTreeCreator.createBinTreeByInPost(in, post);
System.out.print(System.lineSeparator() + "pre order: ");
BinTreeCreator.preOrderTraverse(rootNode);
}
}
C語言版:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
char data;
struct node *lchild, *rchild;
} BinTreeNode;
BinTreeNode * createBinTreeByPreIn(char *pre, char *in, int number);
BinTreeNode * createBinTreeByInPost(char *in, char *post, int number);
void preOrderTraverse(BinTreeNode *node);
void inOrderTraverse(BinTreeNode *node);
void postOrderTraverse(BinTreeNode *node);
int main(int argc, const char * argv[]) {
char *pre = "ABCDEF";
char *in = "CBDAEF";
char *post = "CDBFEA";
BinTreeNode *rootNode = createBinTreeByPreIn(pre, in, 6);
printf("post order: ");
postOrderTraverse(rootNode);
rootNode = createBinTreeByInPost(in, post, 6);
printf("\npre order: ");
preOrderTraverse(rootNode);
return 0;
}
//根據前序和中序建立二叉樹
BinTreeNode * createBinTreeByPreIn(char *pre, char *in, int number) {
if (number == 0) return NULL;
char c = pre[0];
int i = 0;
while (i < number && in[i] != c) i++;
int leftNumber = i;
int rightNumber = number - i - 1;
BinTreeNode *node = (BinTreeNode *) malloc(sizeof(BinTreeNode));
node->data = c;
node->lchild = createBinTreeByPreIn(&pre[1], &in[0], leftNumber);
node->rchild = createBinTreeByPreIn(&pre[leftNumber + 1], &in[leftNumber + 1], rightNumber);
return node;
}
//根據中序和後序建立二叉樹
BinTreeNode * createBinTreeByInPost(char *in, char *post, int number) {
if (number == 0) return NULL;
char c = post[number - 1];
int i = 0;
while (i < number && in[i] != c) i++;
int leftNumber = i;
int rightNumber = number - i - 1;
BinTreeNode *node = (BinTreeNode *) malloc(sizeof(BinTreeNode));
node->data = c;
node->lchild = createBinTreeByInPost(&in[0], &post[0], leftNumber);
node->rchild = createBinTreeByInPost(&in[leftNumber + 1], &post[leftNumber], rightNumber);
return node;
}
//前序遍歷
void preOrderTraverse(BinTreeNode *node) {
if (node != NULL) {
printf("%c", node->data);
preOrderTraverse(node->lchild);
preOrderTraverse(node->rchild);
}
}
//後序遍歷
void postOrderTraverse(BinTreeNode *node) {
if (node != NULL) {
postOrderTraverse(node->lchild);
postOrderTraverse(node->rchild);
printf("%c", node->data);
}
}