1 二叉树概念
二叉树(Binary Tree)是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者有一个根节点和两颗互不相交的,方便称为根节点的左子树和右子树的二叉树组成
一般的树都可以使用孩子兄弟表示法转换为二叉树表示
(二)特殊的二叉树
1.斜二叉树
或者
所有的结点都只有左子树的二叉树叫做左斜树
所有的结点都只有右子树的二叉树叫做右斜树
相当于链表,所以线性结构可以理解为是树的一种极其特殊的表现形式
2.满二叉树(完美二叉树)
所有分支结点都存在左子树和右子树。
所有叶子结点都在同一层
3.完全二叉树
对树按照上->下,左->右,编号为i的与满二叉树中为i的位置相同
(三)二叉树的几个重要性质
性质一:第i层最大结点数位2^(i-1)个,(i>=1)
性质二:深度为k的二叉树至多有2^k-1个结点
性质三:叶结点n0与度为2的结点n2的个数关系n0=n2+1
设n1为度为1的非叶结点数
那么按照边来计算
n0+n1+n2-1 每个结点向上都有一条边指向双亲结点,除了根结点
n0*0+n1*1+n2*2 度为二,向下有2条边,度为1向下有一条边,度为0的叶子节点无下边。
两者边相等,所以得出:n0=n2+1
性质四:具有n个结点的完全二叉树的深度为[log2n]+1
性质五:对一棵有n个结点的完全二叉树,从第一层到最大层,对任一结点i(1=<i<=n)有:
1.非根节点的父节点序号是[i/2]
2.结点(序号i)的左孩子为2i,若2i>n没有左孩子
2.结点(序号i)的右孩子为2i+1,若2i+1>n没有右孩子
2 遍历方式
前序遍历:根结点 ---> 左子树 ---> 右子树
中序遍历:左子树---> 根结点 ---> 右子树
后序遍历:左子树 ---> 右子树 ---> 根结点
树的结构定义
package org.buptdavid.datastructure.tree;
/**
* 树的节点
* @author
*
*/
public class TreeNode<T> {
T data;
TreeNode<T> left;
TreeNode<T> right;
public TreeNode(T data){
this.data = data;
}
}
创建一个1-10的树,并查询具体一个value所经过的树路径
public class TreeSearchTest {
private static TreeNode<Integer> root;
@BeforeClass
public static void beforeClass(){
TreeNode<Integer> node1 = new TreeNode<Integer>(1);
TreeNode<Integer> node2 = new TreeNode<Integer>(2);
TreeNode<Integer> node3 = new TreeNode<Integer>(3);
TreeNode<Integer> node4 = new TreeNode<Integer>(4);
TreeNode<Integer> node5 = new TreeNode<Integer>(5);
TreeNode<Integer> node6 = new TreeNode<Integer>(6);
TreeNode<Integer> node7 = new TreeNode<Integer>(7);
TreeNode<Integer> node8 = new TreeNode<Integer>(8);
TreeNode<Integer> node9 = new TreeNode<Integer>(9);
TreeNode<Integer> node10 = new TreeNode<Integer>(10);
node1.left = node2;
node1.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;
node3.right = node7;
node4.left = node8;
node7.right = node9;
node9.left = node10;
root = node1;
}
/**
* 前序遍历测试
*/
@Test
public void preorderTraversalTest(){
TreeSearch<Integer> treeSearch = new TreeSearch<Integer>();
Integer value = 5;
String expectedSearchPath = "1->2->4->8->5";
treeSearch.preorderTraversal(root, value);
Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString()));
treeSearch = new TreeSearch<Integer>();
value = 6;
expectedSearchPath = "1->2->4->8->5->3->6";
treeSearch.preorderTraversal(root, value);
Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString()));
}
/**
* 中序遍历测试
*/
@Test
public void inorderTraversalTest(){
TreeSearch<Integer> treeSearch = new TreeSearch<Integer>();
Integer value = 5;
String expectedSearchPath = "8->4->2->5";
treeSearch.inorderTraversal(root, value);
Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString()));
treeSearch = new TreeSearch<Integer>();
value = 6;
expectedSearchPath = "8->4->2->5->1->6";
treeSearch.inorderTraversal(root, value);
Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString()));
}
/**
* 后序遍历测试
*/
@Test
public void postorderTraversalTest(){
TreeSearch<Integer> treeSearch = new TreeSearch<Integer>();
Integer value = 5;
String expectedSearchPath = "8->4->5";
treeSearch.postorderTraversal(root, value);
Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString()));
treeSearch = new TreeSearch<Integer>();
value = 6;
expectedSearchPath = "8->4->5->2->6";
treeSearch.postorderTraversal(root, value);
Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString()));
}
}
具体的路径算法,其实就是一个递归过程
public class TreeSearch<T> {
StringBuffer searchPath = new StringBuffer();
private boolean isSearched = false;
/**
* 前序遍历root查询item
* @param item
* @return
*/
public void preorderTraversal(TreeNode<T> root, T data){
if(root == null){
return;
}
if(!isSearched){
if(!searchPath.toString().equals("")){
searchPath.append("->");
}
searchPath.append(root.data);
if(root.data.equals(data))
isSearched = true;
}
if(!isSearched)
preorderTraversal(root.left, data);
if(!isSearched)
preorderTraversal(root.right, data);
}
/**
* 中序遍历root查询item
* @param root
* @param item
* @return
*/
public void inorderTraversal(TreeNode<T> root, T data){
if(root == null){
return;
}
if(!isSearched)
inorderTraversal(root.left, data);
if(!isSearched){
if(!searchPath.toString().equals("")){
searchPath.append("->");
}
searchPath.append(root.data);
if(root.data.equals(data))
isSearched = true;
}
if(!isSearched)
inorderTraversal(root.right, data);
}
/**
* 后续遍历root查询item
* @param item
* @return
*/
public void postorderTraversal(TreeNode<T> root, T data){
if(root == null){
return;
}
if(!isSearched)
postorderTraversal(root.left, data);
if(!isSearched)
postorderTraversal(root.right, data);
if(!isSearched){
if(!searchPath.toString().equals("")){
searchPath.append("->");
}
searchPath.append(root.data);
if(root.data.equals(data))
isSearched = true;
}
}
}