как построить двоичное дерево из обходов предзаказа и inorder
Я выполняю задание по построению двоичного дерева из предзаказа и обхода inorder (символ в каждом узле), и я пытаюсь обернуть свой мозг вокруг того, как построить фактическое дерево.
вот мой мыслительный процесс о том, как добиться этого:
- сохраните первую запись в предзаказе как корневой узел
- поиск inorder для этой записи.
- возьмите символы слева от корневого узла и сохраните их как символ матрица.
- возьмите символы справа от корневого узла и сохраните их как массив символов.
- создать новое дерево с корнем в качестве родителя и 2 детей левой и правой char массивы.
- продолжайте рекурсивно, пока длина предзаказа не будет равна 0.
У меня есть шаги 1-4, но я не слишком уверен, как правильно построить мое дерево, и было интересно, есть ли у кого-нибудь указатели. Спасибо.
5 ответов
выполните рекурсию перед построением нового дерева. Итак, ваш список будет выглядеть так:
- если массивы имеют длину 1, просто верните листовой узел с этим единственным элементом в нем. (Это основа рекурсии.) (O (1))
- сохраните первую запись в массиве предзаказа в качестве корневого узла. (O (1))
- Поиск массива inorder для этой записи. (O (n))
- возьмите символы слева от корня узел в массиве inorder и сохраните их как массив char. Возьмите такое же количество символов из массива предзаказа (после корня). (O(n) или O (1), когда просто бросают указатели/индексы вокруг.)
- возьмите символы справа от корневого узла и сохраните их как массив символов. Возьмите такое же количество символов из массива предзаказа (после первой части – это должна быть только оставшаяся часть). (O (n) или O (1), когда просто бросают указатели / индексы вокруг.)
- рекурсивно создайте дерево из обоих левых массивов символов.
- рекурсивно создайте дерево из обоих правых массивов символов.
- объединить оба дерева с корневым узлом. (O (1).)
нерекурсивные части могут быть выполнены в o(n) в целом, и суммирование их для каждого уровня рекурсии также O(n) каждый. Таким образом, общее время выполнения зависит от количества уровней рекурсии. Если у вас есть приблизительно сбалансированное дерево, глубина является O(log n), таким образом, мы получаем O (N · log n) вообще. Поскольку единственная обязательно медленная часть-это поиск корневого узла в массиве inorder, я думаю, мы могли бы оптимизировать это еще немного, если бы мы знали больше о дереве.
в худшем случае у нас есть один уровень рекурсии для каждого узла в дереве, доходящий до сложности O(n·n).
пример: предварительный заказ ABCDEF, Inorder FEDCBA, Tree:
+---+
| A |
++--+
|
+---+ |
| B +<--+
++--+
|
+---+ |
| C +<--+
++--+
|
+---+ |
| D +<--+
++--+
|
+---+ |
| E +<--+
++--+
|
+---+ |
| F +<--+
+---+
вы можете использовать ниже код, я просто написал для той же проблемы. Это работает на меня.
public class TreeFromInorderAndPreOrder {
public static List<Integer> inOrder = new ArrayList<Integer>();
public static List<Integer> preOrder = new ArrayList<Integer>();
public static void main(String[] args) {
Node root = new Node();
root.createRoot(5);
for(int i = 0 ; i < 9 ; i++){
if(i != 5){
root.insert(i);
}
}
inOrder(root);
preOrder(root);
for(Integer temp : inOrder){
System.out.print(temp + " ");
}
System.out.println();
for(Integer temp : preOrder){
System.out.print(temp + " ");
}
Node node1 = null;
node1 = reConstructTree(root, (ArrayList<Integer>) inOrder, true);
System.out.println();
inOrder(node1);
for(Integer temp : inOrder){
System.out.print(temp + " ");
}
System.out.println();
for(Integer temp : preOrder){
System.out.print(temp + " ");
}
}
public static void inOrder(Node node){
if(node!= null){
inOrder(node.leftchild);
inOrder.add(node.key);
inOrder(node.rightChild);
}
}
public static void preOrder(Node node){
if(node != null){
preOrder.add(node.key);
preOrder(node.leftchild);
preOrder(node.rightChild);
}
}
public static Node reConstructTree(Node root, ArrayList<Integer> inOrder,
boolean isLeft){
if(preOrder.size() != 0 && inOrder.size() != 0){
return null;
}
Node node = new Node();
node.createRoot(preOrder.get(0));
if(root != null && isLeft){
root.leftchild = node;
}else if(root != null && !isLeft){
root.rightChild = node;
}
int indx = inOrder.get(preOrder.get(0));
preOrder.remove(0);
List<Integer> leftInorder = getSublist(0, indx);
reConstructTree(node, (ArrayList<Integer>) leftInorder, true);
List<Integer> rightInorder = getSublist(indx+1, inOrder.size());
reConstructTree(node, (ArrayList<Integer>)rightInorder, false);
return node;
}
public static ArrayList<Integer> getSublist(int start, int end){
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i = start ; i < end ; i++){
list.add(inOrder.get(i));
}
return list;
}
}
Я написал пример программы с использованием подхода divide and conquer с использованием рекурсии в java
import java.util.LinkedList;
import java.util.Queue;
public class BinaryTreeNode {
private char data;
public char getData() {
return data;
}
public void setData(char data) {
this.data = data;
}
public BinaryTreeNode getLeft() {
return left;
}
public void setLeft(BinaryTreeNode left) {
this.left = left;
}
public BinaryTreeNode getRight() {
return right;
}
public void setRight(BinaryTreeNode right) {
this.right = right;
}
private BinaryTreeNode left;
private BinaryTreeNode right;
public static void levelTravesal(BinaryTreeNode node)
{
Queue queue = new LinkedList();
if(node == null)
return;
queue.offer(node);
queue.offer(null);
int level =0;
while(!queue.isEmpty())
{
BinaryTreeNode temp = (BinaryTreeNode) queue.poll();
if(temp == null)
{
System.out.println("Level: "+level);
if(!queue.isEmpty())
queue.offer(null);
level++;
}else {
System.out.println(temp.data);
if(temp.getLeft()!=null)
queue.offer(temp.getLeft());
if(temp.getRight()!=null)
queue.offer(temp.getRight());
}
}
}
static int preIndex = 0;
public static void main(String[] args) {
if(args.length < 2)
{
System.out.println("Usage: preorder inorder");
return;
}
char[] preOrderSequence = args[0].toCharArray();
char[] inOrderSequence = args[1].toCharArray();
//char[] preOrderSequence = {'A','B','D','E','C','F'};
//char[] inOrderSequence = "DBEAFC".toCharArray();
if(preOrderSequence.length != inOrderSequence.length)
{
System.out.println("Pre-order and in-order sequences must be of same length");
return;
}
BinaryTreeNode root = buildBinaryTree(preOrderSequence, inOrderSequence, 0, preOrderSequence.length-1);
System.out.println();
levelTravesal(root);
}
static BinaryTreeNode buildBinaryTree(char[] preOrder, char[] inOrder, int start, int end)
{
if(start > end)
return null;
BinaryTreeNode rootNode = new BinaryTreeNode();
rootNode.setData(preOrder[preIndex]);
preIndex++;
//System.out.println(rootNode.getData());
if(start == end)
return rootNode;
int dataIndex = search(inOrder, start, end, rootNode.getData());
if(dataIndex == -1)
return null;
//System.out.println("Left Bounds: "+start+" "+(dataIndex-1));
rootNode.setLeft(buildBinaryTree(preOrder, inOrder, start, dataIndex - 1));
//System.out.println("Right Bounds: "+(dataIndex+1)+" "+end);
rootNode.setRight(buildBinaryTree(preOrder, inOrder, dataIndex+1, end));
return rootNode;
}
static int search(char[] inOrder,int start,int end,char data)
{
for(int i=start;i<=end;i++)
{
if(inOrder[i] == data)
return i;
}
return -1;
}
}
вот математический подход для достижения вещи очень упрощенным способом:
используемый язык: Java
`
/*
Алгоритм построения двоичного дерева из заданных обходов Inorder и Preorder.
Ниже используется терминология:
i: представляет массив inorder, поставляемый
p: представляет массив предзаказа, поставляемый
beg1: начальный индекс массива inorder
beg2 : начиная индекс массива предзаказа
end1: конечный индекс массива inorder
end2: конечный индекс массива предзаказа
*/
публичный статический пустота constructTree(корневой узел, инт[] я, инт[] Р, инт beg1, конец1 инт, инт beg2, инт end2)
{
if(beg1==end1 && beg2 == end2)
{
root.data = i[beg1];
}
else if(beg1<=end1 && beg2<=end2)
{
root.data = p[beg2];
int mid = search(i, (int) root.data);
root.left=new Node();
root.right=new Node();
constructTree(root.left, i, p, beg1, mid-1, beg2+1, beg2+mid-beg1);
System.out.println("Printing root left : " + root.left.data);
constructTree(root.right, i, p, mid+1, end1, beg2+1+mid-beg1, end2);
System.out.println("Printing root left : " + root.right.data);
}
}
`
вам нужно вызвать функцию следующим кодом:
int[] i ={4,8,7,9,2,5,1,6,19,3,18,10}; //Inorder
int[] p ={1,2,4,7,8,9,5,3,6,19,10,18}; //Preorder
Node root1=new Node();
constructTree(root1, i, p, 0, i.length-1, 0, p.length-1);
в случае, если вам нужно более подробное объяснение кода пожалуйста упомяните об этом в комментариях. Буду рад помочь :).