剑指Offer——二叉树
剑指Offer——二叉树
前言
数据结构通常是编程面试中考察的重点。在参加面试之前,应聘者需要熟练掌握链表、树、栈、队列和哈希表等数据结构,以及它们的操作。本片博文主要讲解二叉树操作的相关知识,主要包括二叉树的建立、遍历方法的循环和递归写法。
二叉树是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树的形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。
二叉树的java实现
首先创建一棵二叉树如下图,然后对这颗二叉树进行遍历操作(遍历操作的实现分为递归实现和非递归实现),同时还提供一些方法如获取双亲结点、获取左孩子、右孩子等。
package cn.edu.ujn.nk;
import java.util.Stack;
/**
* 二叉树的链式存储
* @author WWX
*/
public class BinaryTree {
private TreeNode root=null;
public BinaryTree(){
root=new TreeNode(1,"rootNode(A)");
}
/**
* 创建一棵二叉树
* <pre>
* A
* B C
* D E F
* </pre>
* @param root
* @author WWX
*/
public void createBinTree(TreeNode root){
TreeNode newNodeB = new TreeNode(2,"B");
TreeNode newNodeC = new TreeNode(3,"C");
TreeNode newNodeD = new TreeNode(4,"D");
TreeNode newNodeE = new TreeNode(5,"E");
TreeNode newNodeF = new TreeNode(6,"F");
root.leftChild=newNodeB;
root.rightChild=newNodeC;
root.leftChild.leftChild=newNodeD;
root.leftChild.rightChild=newNodeE;
root.rightChild.rightChild=newNodeF;
}
public boolean isEmpty(){
return root==null;
}
//树的高度
public int height(){
return height(root);
}
//节点个数
public int size(){
return size(root);
}
private int height(TreeNode subTree){
if(subTree == null)
return 0; // 递归结束:空树高度为0
else{
int i = height(subTree.leftChild);
int j = height(subTree.rightChild);
return (i < j) ? (j + 1) : (i + 1);
}
}
private int size(TreeNode subTree){
if(subTree == null){
return 0;
}else{
return 1 + size(subTree.leftChild) + size(subTree.rightChild);
}
}
//返回双亲结点
public TreeNode parent(TreeNode element){
return (root == null|| root == element) ? null : parent(root, element);
}
public TreeNode parent(TreeNode subTree,TreeNode element){
if(subTree == null)
return null;
if(subTree.leftChild == element || subTree.rightChild == element)
//返回父结点地址
return subTree;
TreeNode p;
// 先在左子树中找,如果左子树中没有找到,才到右子树去找
if((p = parent(subTree.leftChild, element)) != null)
//递归在左子树中搜索
return p;
else
//递归在右子树中搜索
return parent(subTree.rightChild, element);
}
public TreeNode getLeftChildNode(TreeNode element){
return (element != null) ? element.leftChild : null;
}
public TreeNode getRightChildNode(TreeNode element){
return (element != null) ? element.rightChild : null;
}
public TreeNode getRoot(){
return root;
}
//在释放某个结点时,该结点的左右子树都已经释放,
//所以应该采用后续遍历,当访问某个结点时将该结点的存储空间释放
public void destroy(TreeNode subTree){
//删除根为subTree的子树
if(subTree!=null){
//删除左子树
destroy(subTree.leftChild);
//删除右子树
destroy(subTree.rightChild);
//删除根结点
subTree=null;
}
}
public void traverse(TreeNode subTree){
System.out.println("key:"+subTree.key+"--name:"+subTree.data);;
traverse(subTree.leftChild);
traverse(subTree.rightChild);
}
//前序遍历
public void preOrder(TreeNode subTree){
if(subTree!=null){
visted(subTree);
preOrder(subTree.leftChild);
preOrder(subTree.rightChild);
}
}
//中序遍历
public void inOrder(TreeNode subTree){
if(subTree!=null){
inOrder(subTree.leftChild);
visted(subTree);
inOrder(subTree.rightChild);
}
}
//后续遍历
public void postOrder(TreeNode subTree) {
if (subTree != null) {
postOrder(subTree.leftChild);
postOrder(subTree.rightChild);
visted(subTree);
}
}
//前序遍历的非递归实现
public void nonRecPreOrder(TreeNode p){
Stack<TreeNode> stack=new Stack<TreeNode>();
TreeNode node=p;
while(node!=null||stack.size()>0){
while(node!=null){
visted(node);
stack.push(node);
node=node.leftChild;
}
while(stack.size()>0){
node=stack.pop();
node=node.rightChild;
}
}
}
//中序遍历的非递归实现
public void nonRecInOrder(TreeNode p){
Stack<TreeNode> stack =new Stack<BinaryTree.TreeNode>();
TreeNode node =p;
while(node!=null||stack.size()>0){
//存在左子树
while(node!=null){
stack.push(node);
node=node.leftChild;
}
//栈非空
if(stack.size()>0){
node=stack.pop();
visted(node);
node=node.rightChild;
}
}
}
//后序遍历的非递归实现
public void noRecPostOrder(TreeNode p){
Stack<TreeNode> stack=new Stack<BinaryTree.TreeNode>();
TreeNode node =p;
while(p!=null){
//左子树入栈
for(;p.leftChild!=null;p=p.leftChild){
stack.push(p);
}
//当前结点无右子树或右子树已经输出
while(p!=null&&(p.rightChild==null||p.rightChild==node)){
visted(p);
//纪录上一个已输出结点
node =p;
if(stack.empty())
return;
p=stack.pop();
}
//处理右子树
stack.push(p);
p=p.rightChild;
}
}
public void visted(TreeNode subTree){
subTree.isVisted=true;
System.out.println("key:"+subTree.key+"--name:"+subTree.data);;
}
/**
* 二叉树的节点数据结构
* @author WWX
*/
private class TreeNode{
private int key = 0;
private String data = null;
private boolean isVisted = false;
private TreeNode leftChild = null;
private TreeNode rightChild = null;
public TreeNode(){}
/**
* @param key 层序编码
* @param data 数据域
*/
public TreeNode(int key,String data){
this.key = key;
this.data = data;
this.leftChild = null;
this.rightChild = null;
}
}
//测试
public static void main(String[] args) {
BinaryTree bt = new BinaryTree();
bt.createBinTree(bt.root);
System.out.println("the size of the tree is " + bt.size());
System.out.println("the height of the tree is " + bt.height());
System.out.println("***递归实现****(前序遍历)[ABDECF]遍历*****************");
bt.preOrder(bt.root);
System.out.println("***递归实现****(中序遍历)[DBEACF]遍历*****************");
bt.inOrder(bt.root);
System.out.println("***递归实现****(后序遍历)[DEBFCA]遍历*****************");
bt.postOrder(bt.root);
System.out.println("***非递归实现****(前序遍历)[ABDECF]遍历*****************");
bt.nonRecPreOrder(bt.root);
System.out.println("***非递归实现****(中序遍历)[DBEACF]遍历*****************");
bt.nonRecInOrder(bt.root);
System.out.println("***非递归实现****(后序遍历)[DEBFCA]遍历*****************");
bt.noRecPostOrder(bt.root);
}
}
美文美图
剑指Offer——二叉树的更多相关文章
- 剑指offer 二叉树中和为某一个值的路径
剑指offer 牛客网 二叉树中和为某一个值的路径 # -*- coding: utf-8 -*- """ Created on Tue Apr 9 15:53:58 2 ...
- 剑指offer 二叉树的层序遍历
剑指offer 牛客网 二叉树的层序遍历 # -*- coding: utf-8 -*- """ Created on Tue Apr 9 09:33:16 2019 @ ...
- JS数据结构与算法 - 剑指offer二叉树算法题汇总
❗❗ 必看经验 在博主刷题期间,基本上是碰到一道二叉树就不会碰到一道就不会,有时候一个下午都在搞一道题,看别人解题思路就算能看懂,自己写就呵呵了.一气之下不刷了,改而先去把二叉树的基础算法给搞搞懂,然 ...
- 剑指offer——二叉树的镜像
题目:操作给定的二叉树,将其变换为源二叉树的镜像. 思路:前序(根左右的顺序)遍历一棵树,在存储的时候将其左右树进行交换,最后按照处理后的树还原,即得到其镜像. /** public class Tr ...
- 剑指Offer 二叉树中和为某一值的路径(dfs)
题目描述 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径. 思路: 递归,然后深搜,因为题目定义的, ...
- 剑指Offer 二叉树的镜像
题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述: 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ ...
- 剑指Offer——二叉树的下一个结点
题目描述: 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 分析: 如果该结点存在右子树,那么返回右子树的最左结 ...
- 剑指Offer——二叉树的深度
题目描述: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 分析: 二叉树的深度等于其左子树的深度和右子树的深度两个中最大的深 ...
- 剑指Offer——二叉树中和为某一值的路径
题目描述: 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径. 分析: 先序遍历二叉树,找到二叉树中结点值的和 ...
随机推荐
- 2015 多校联赛 ——HDU5302(矩阵快速幂)
The Goddess Of The Moon Sample Input 2 10 50 12 1213 1212 1313231 12312413 12312 4123 1231 3 131 5 5 ...
- VK Cup 2017 - Round 1
和FallDream组队瞎打一通--B两个人写的都挂了233,最后只剩下FallDream写的A和我写的C,最后我yy了个E靠谱做法结果打挂了,结束之后改了改就A了,难受. AC:AC Rank:18 ...
- hdu 4638 树状数组 区间内连续区间的个数(尽可能长)
Group Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Subm ...
- UOJ #11. 【UTR #1】ydc的大树
题目描述: ydc有一棵n个结点的黑白相间的大树,从1到n编号. 这棵黑白树中有m个黑点,其它都是白点. 对于一个黑点我们定义他的好朋友为离他最远的黑点.如果有多个黑点离它最远那么都是它的好朋友.两点 ...
- [BZOJ]1011 遥远的行星(HNOI2008)
由eps引发的血案. Description 直线上N颗行星,X=i处有行星i,行星J受到行星I的作用力,当且仅当i<=A*J.此时J受到作用力的大小为 Fi->j=Mi*Mj/(j-i) ...
- 某些情况下调用函数为什么要在函数名前加“(void)”
我们知道,在定义函数时,加在函数名前的"void"表示该函数没有返回值.但在调用时,在函数名前加"(void)"的作用又是什么呢? 最明显的一点就是表示程序并不 ...
- cisco 的六种模式(cisco 系统)
- vue 组件按需引用,vue-router懒加载,vue打包优化,加载动画
当打包构建应用时,Javascript 包会变得非常大,影响页面加载.如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了. 结合 Vue 的 异步 ...
- HTMLParser使用简介
HTMLParser具有小巧,快速的优点,缺点是相关文档比较少(英文的也少),很多功能需要自己摸索.对于初学者还是要费一些功夫的,而一旦上手以后,会发现HTMLParser的结构设计很巧妙,非常实用, ...
- 前端性能优化之-dns预解析
预解析的实现: 1. 用meta信息来告知浏览器, 当前页面要做DNS预解析:<meta http-equiv="x-dns-prefetch-control" conten ...