(剑指offer笔记)根据前序遍历和后序遍历重建二叉树
2014-05-26 22:30
411 查看
问题:输入某二叉树的前序遍历和中序遍历的结果,重建出该二叉树,假设输入的前序遍历和终须遍历的结果都不含有重复数字。最后按层遍历输出二叉树结果。
规定二叉树结点不含父节点字段。
解答:
前序遍历(根-左-右)
[java] view
plaincopy
preOrder(t){
if(t非空){
访问t的根元素;
preOrder(t的左子树);
preOrder(t的右子树);
}
}
中序遍历(左-根-右)
[java] view
plaincopy
inOrder(t){
if(t非空){
inOrder(t的左子树);
访问t的根元素;
inOrder(t的右子树);
}
}
前序遍历结果数组最左边总是根节点,而中序遍历结果数组中间某位置是根节点,左子树在根节点左边,右子树在根节点右边。我们现在前序遍历结果数组中得到根节点的值,然后在中序遍历结果数组中查找它,找到后对左右子树用同样方法迭代发现其根节点、左子树、右子树,由此构建二叉树。
程序使用泛型和迭代:
构建二叉树的函数分为两层,一层为public方法,可供外界程序调用;一层为private方法,实现构建功能:
重建完毕后需要按层遍历输出
逐层遍历(宽度优先遍历)
[java] view
plaincopy
breadthFirst(t){
//queue为二叉树(引用)的队列
//t为二叉树(引用)
if(t非空){
queue.enqueue(t);
while(queue不空){
queue.dequeue(t); //从队列中移除根结点
访问被移除的根;
if(tree的左子树非空)
queue.enqueue(tree的左子树);
if(tree的右子树非空)
queue.enqueue(tree的右子树);
}
}
}
核心思想是利用队列的先进先出特点,根结点先进去,叶子节点后进去。用一个队列保存一层的结点,当访问该层某结点的子节点时,就被该结点移除出队列,访问它,然后在队列末尾插入子节点。在while循环中不断重复该过程。于是所有节点就按照从根开始一层一层地从左到右地访问完毕。
输出结果为[a, b, c, d, e, f, g, h]
public static void main(String[] args) { // TODO 自动生成的方法存根 Character[] preOrder = new Character[] { 'a','b','d','g','c','e','f','h' }; Character[] inOrder = { 'd','g','b','a','e','c','h','f'}; Entry<Character> root = construct(preOrder, inOrder); System.out.println(toString(root)); }
规定二叉树结点不含父节点字段。
private static class Entry<E> { Entry<E> left, right; E element; Entry() { } Entry(E element) { this.element = element; } }
解答:
前序遍历(根-左-右)
[java] view
plaincopy
preOrder(t){
if(t非空){
访问t的根元素;
preOrder(t的左子树);
preOrder(t的右子树);
}
}
中序遍历(左-根-右)
[java] view
plaincopy
inOrder(t){
if(t非空){
inOrder(t的左子树);
访问t的根元素;
inOrder(t的右子树);
}
}
前序遍历结果数组最左边总是根节点,而中序遍历结果数组中间某位置是根节点,左子树在根节点左边,右子树在根节点右边。我们现在前序遍历结果数组中得到根节点的值,然后在中序遍历结果数组中查找它,找到后对左右子树用同样方法迭代发现其根节点、左子树、右子树,由此构建二叉树。
程序使用泛型和迭代:
构建二叉树的函数分为两层,一层为public方法,可供外界程序调用;一层为private方法,实现构建功能:
public static <E> Entry<E> construct(E[] preOrder, E[] inOrder) { if (preOrder == null || inOrder == null || preOrder.length != inOrder.length || inOrder.length <= 0) return null;//检查输入的数组是否有效 return coreConstruct(preOrder, 0, preOrder.length - 1, inOrder, 0, preOrder.length - 1); }
private static <E> Entry<E> coreConstruct(E[] preOrder, int startPreOrder, int endPreOrder, E[] inOrder, int startInOrder, int endInOrder) { Entry<E> root = new Entry<E>(preOrder[startPreOrder]);// 前序遍历数组的最左边的元素是二叉树的根节点 // 在中序遍历数组中找到该根节点元素,它左边是左子树,右边是右子树 int rootInOrder = search(inOrder, root.element);//找到根结点索引 if (rootInOrder == -1) {//如果没找到该结点元素,说明给定的数组有问题 throw new IllegalArgumentException("输入数组无效"); } int leftLength = rootInOrder - startInOrder;//左子树长度 int leftEndPreOrder = startPreOrder + leftLength;//前序遍历结果数组里当前根结点的左子树的最后一个元素的位置。 // 对其左子树和右子树迭代重建 if (leftLength > 0) { // 如果左子树长度大于0,那就对左子树进行重建 root.left = coreConstruct(preOrder, startPreOrder + 1, leftEndPreOrder, inOrder, startInOrder, rootInOrder - 1); } if (leftEndPreOrder < endPreOrder) { //如果左子树最后一个元素的索引位置小于整个前序遍历数组最后一个索引位置,说明有右子树存在, 重建右子树 root.right = coreConstruct(preOrder, leftEndPreOrder + 1, endPreOrder, inOrder, rootInOrder + 1, endInOrder); } return root; }
/** * @param array 待搜索的数组 * @param e 要被搜索的元素 * @return 被搜索的元素在数组中的位置。如果没有找到,就返回-1 */ public static <E> int search(E[] array, E e) { for (int i = 0; i < array.length; i++) { if (array[i].equals(e)) return i; } return -1; }
重建完毕后需要按层遍历输出
逐层遍历(宽度优先遍历)
[java] view
plaincopy
breadthFirst(t){
//queue为二叉树(引用)的队列
//t为二叉树(引用)
if(t非空){
queue.enqueue(t);
while(queue不空){
queue.dequeue(t); //从队列中移除根结点
访问被移除的根;
if(tree的左子树非空)
queue.enqueue(tree的左子树);
if(tree的右子树非空)
queue.enqueue(tree的右子树);
}
}
}
核心思想是利用队列的先进先出特点,根结点先进去,叶子节点后进去。用一个队列保存一层的结点,当访问该层某结点的子节点时,就被该结点移除出队列,访问它,然后在队列末尾插入子节点。在while循环中不断重复该过程。于是所有节点就按照从根开始一层一层地从左到右地访问完毕。
/** * 宽度遍历,用一个链表保存结果 * * @param root * @return */ public static <E> List<E> breadthFirst(Entry<E> root) { LinkedList<Entry<E>> list = new LinkedList<Entry<E>>(); ArrayList<E> result = new ArrayList<E>(); if (root != null) list.addLast(root); while (!list.isEmpty()) { Entry<E> p = list.removeFirst(); result.add(p.element); if (p.left != null) { list.addLast(p.left); } if (p.right != null) { list.addLast(p.right); } } return result; }
/** * 使用宽度遍历逐层打印元素 * * @param root * 根节点 * @return */ public static <E> String toString(Entry<E> root) { return breadthFirst(root).toString(); }
输出结果为[a, b, c, d, e, f, g, h]
相关文章推荐
- 根据前序遍历(或者是后序遍历)和中序遍历得到的序列可以重建二叉树
- 剑指Offer_06 根据前序遍历和中序遍历序列 重建二叉树
- 刷题之路----根据前序遍历和中序遍历或者后序遍历和中序遍历重建二叉树
- 笔试算法题(36):寻找一棵二叉树中最远节点的距离 & 根据二叉树的前序和后序遍历重建二叉树
- 根据前序遍历和中序遍历重建二叉树
- POJ 2255Tree Recovery 二叉树重建(根据前序遍历和中序遍历写出后序遍历)
- 根据二叉树的前序遍历和中序遍历的结果,重建二叉树
- 根据二叉树的前序遍历和中序遍历重建二叉树
- 根据前序遍历和中序遍历重建二叉树
- 根据前序遍历和中序遍历结果重建二叉树(递归方法)
- 根据前序遍历、中序遍历构建二叉树,并后序遍历输出。
- 根据后序和中序遍历重建二叉树
- Python练手之根据前序和中序&根据中序和后序重建二叉树,输出前序、中序和后序遍历结果
- 根据二叉树的前序遍历序列和中序遍历序列求二叉树的后序遍历序列
- 根据前序遍历和中序遍历构建二叉树以及根据中序遍历后序遍历构建二叉树
- 根据二叉树前序遍历和中序遍历的结果,重建出该二叉树并后序遍历之 java代码
- 根据二叉树的前序遍历和中序遍历结果重建出该二叉树
- 027根据前序遍历和中序遍历,重建二叉树(keep it up)
- LeetCode(Construct Binary Tree from Preorder and Inorder Traversal )根据二叉树的中序遍历和后序遍历重建二叉树
- 根据前序遍历序列和中序遍历序列重建二叉树