树的相关概念术语
1)节点< node>
树中每个元素都叫节点
2)根节点或树根< root>
树顶端的节点称之为根节点,也叫树根
3)子树< subTree>
除根节点之外,其他节点可以分为多个树的集合,叫做子树,在上图中,
K这个节点可以称之为一颗子树,而H、K、L三个节点组合起来也可以叫做一颗子树
4)节点的度
一个节点直接含有的子树的个数,称之为节点的度。
比如上图中B节点的度为3,C节点的度是2,I、J、K、L节点的度是0
5)叶子节点、叶节点、终端节点
度为0的节点叫做叶子节点,也叫叶节点、终端节点,其实就是
没有子节点的节点,或者说没有子树的节点
6)双亲节点、父节点
父节点就是一个节点上头的那个节点,如果一个节点包含若干子节点,
那么这个节点就是这些子节点的父节点,也叫双亲节点
7)兄弟节点
拥有相同父节点的节点互称为兄弟节点
8)树的度
一棵树中最大节点的度称之为树的度,即树中哪个节点的子节点最多,那么这个节点的度也就是树的度
9)节点的层次
从根这一层开始,根算1层,根的子节点算2层,一直到最下面一层
10)树的高度、深度
树的深度是从根节点开始、自顶向下逐层累加(根节点的高度是1)助记:深度从上到下
树的高度是从叶节点开始、自底向上逐层累加(叶节点的高度是1)助记:高度由下向上
虽然树的高度和深度一样,但是具体到某个节点上,其高度和深度通常是不一样的。
11)堂兄弟节点
堂兄弟节点是同一层,父节点不同,或者说双亲节点在同一层的节点称之为堂兄弟节点
12)节点的祖先
从根节点到某一节点一路顺下来的除了该节点的所有节点都是该节点的祖先节点
13)节点的子孙
以某节点为根的子树中,任何一个节点都是其子孙,也就是说这个节点下面与这
个节点有关的节点都是这个节点的子孙
14)森林
由m棵不相交的树组成的集合,叫做森林
都有哪些树
树的种类有很多,我们接触到的树有二叉树、平衡二叉树、二叉查找树、B树、B+树、哈夫曼树、B*树、红黑树和trie树等。
java实现树的一般操作
树的节点结构:
package tree;
/**
* TreeNode: 普通的树节点
*
*/
public class TreeNode<T> {
T value;
TreeNode<T> leftChild;
TreeNode<T> rightChild;
TreeNode(T value) {
this.value = value;
}
TreeNode() {
}
/** 增加左子节点
* addLeft:
* @param value
* void 返回类型
*/
public void addLeft(T value){
TreeNode<T> leftChild = new TreeNode<T>(value);
this.leftChild = leftChild;
}
/**
* addRight: 增加右子节点
* @param value
* void 返回类型
*/
public void addRight(T value){
TreeNode<T> rightChild = new TreeNode<T>(value);
this.rightChild = rightChild;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
* 重载equal方法
*/
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(!(obj instanceof TreeNode)){
return false;
}
return this.value.equals(((TreeNode<?>)obj).value);
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
* 重载hashCode方法
*/
@Override
public int hashCode() {
// TODO Auto-generated method stub
return this.value.hashCode();
}
@Override
public String toString(){
return this.value==null?"":this.value.toString();
}
}
树的基本操作类:
package tree;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/**
* TreeTools:树的操作类
*
*/
public class TreeTools {
/**
* getTreeNum: 判断树中节点个数
*
* @param root
* 根节点
* @return int 返回类型
*/
public static <T> int getTreeNum(TreeNode<T> root) {
if (root == null) {
return 0;
}
return getTreeNum(root.leftChild) + getTreeNum(root.rightChild) + 1;
}
/**
* getTreeDepth: 判断树的深度
*
* @param root
* 根节点
* @return int 返回类型
*/
public static <T> int getTreeDepth(TreeNode<T> root) {
if (root == null) {
return 0;
}
int leftDepth = getTreeDepth(root.leftChild) + 1;
int rightDepth = getTreeDepth(root.rightChild) + 1;
return Math.max(leftDepth, rightDepth);
}
/**
* preOrderTravel: 前序遍历
*
* @param root
* void 返回类型
*/
public static <T> void preOrderTravel(TreeNode<T> root) {
if (root == null) {
return;
}
visitNode(root);
preOrderTravel(root.leftChild);
preOrderTravel(root.rightChild);
}
/**
* midOrderTravel: 中序遍历
*
* @param root
* void 返回类型
*/
public static <T> void midOrderTravel(TreeNode<T> root) {
if (root == null) {
return;
}
midOrderTravel(root.leftChild);
visitNode(root);
midOrderTravel(root.rightChild);
}
/**
* backOrderTravel: 后序遍历
*
* @param root
* void 返回类型
*/
public static <T> void backOrderTravel(TreeNode<T> root) {
if (root == null) {
return;
}
backOrderTravel(root.leftChild);
backOrderTravel(root.rightChild);
visitNode(root);
}
/**
* visitNode: 访问node节点
*
* @param node
* void 返回类型
*/
private static <T> void visitNode(TreeNode<T> node) {
System.out.print(node.value + "\t");
}
/**
* levelTravel: 分层遍历
*
* @param root
* void 返回类型
*/
public static <T> void levelTravel(TreeNode<T> root) {
Queue<TreeNode<T>> q = new LinkedList<TreeNode<T>>();
q.offer(root);
while (!q.isEmpty()) {
TreeNode<T> temp = q.poll();
visitNode(temp);
if (temp.leftChild != null) {
q.offer(temp.leftChild);
}
if (temp.rightChild != null) {
q.offer(temp.rightChild);
}
}
}
/**
* getNumForKlevel: 求第K层节点个数
*
* @param root
* @param k
* @return int 返回类型
*/
public static <T> int getNumForKlevel(TreeNode<T> root, int k) {
if (root == null || k < 1) {
return 0;
}
if (k == 1) {
return 1;
}
int leftNum = getNumForKlevel(root.leftChild, k - 1);
int rightNum = getNumForKlevel(root.rightChild, k - 1);
return leftNum + rightNum;
}
/**
* getLeafNum: 求二叉树中叶子节点的个数
*
* @param root
* @return int 返回类型
*/
public static <T> int getLeafNum(TreeNode<T> root) {
if (root == null) {
return 0;
}
if (root.leftChild == null && root.rightChild == null) {
return 1;
}
int leftNum = getLeafNum(root.leftChild);
int rightNum = getLeafNum(root.rightChild);
return leftNum + rightNum;
}
/**
* exchange: 交换根节点的左右子树
*
* @param root
* @return TreeNode 返回类型
*/
public static <T> TreeNode<T> exchange(TreeNode<T> root) {
if (root == null) {
return null;
}
TreeNode<T> left = exchange(root.leftChild);
TreeNode<T> right = exchange(root.rightChild);
root.leftChild = right;
root.rightChild = left;
return root;
}
/**
* nodeIsChild: 查看node是否是root的子节点
*
* @param root
* @param node
* @return boolean 返回类型
*/
public static <T> boolean nodeIsChild(TreeNode<T> root, TreeNode<T> node) {
if (root == null || node == null) {
return false;
}
if (root == node) {
return true;
}
boolean isFind = nodeIsChild(root.leftChild, node);
if (!isFind) {
isFind = nodeIsChild(root.rightChild, node);
}
return isFind;
}
/**
* findAllFatherNode: 返回两个节点lnode和rnode的以root为根节点的公共父节点
*
* @param root
* 根节点
* @param lNode
* @param rNode
* @return TreeNode 返回类型
*/
public static <T> TreeNode<T> findAllFatherNode(TreeNode<T> root,
TreeNode<T> lNode, TreeNode<T> rNode) {
if (lNode == root || rNode == root) {
return root;
}
if (root == null || lNode == null || rNode == null) {
return null;
}
// 如果lNode是左子树的节点
if (nodeIsChild(root.leftChild, lNode)) {
if (nodeIsChild(root.rightChild, rNode)) {
return root;
} else {
return findAllFatherNode(root.leftChild, lNode, rNode);
}
} else {
if (nodeIsChild(root.leftChild, rNode)) {
return root;
} else {
return findAllFatherNode(root.rightChild, lNode, rNode);
}
}
}
/**
* getTreeFromPreAndMid: 根据前序和中序构建二叉树
*
* @param pre
* 前序序列
* @param mid
* 中序序列
* @return TreeNode 返回类型
*/
public static <T> TreeNode<T> getTreeFromPreAndMid(List<T> pre, List<T> mid) {
if (pre == null || mid == null || pre.size() == 0 || mid.size() == 0) {
return null;
}
if (pre.size() == 1) {
return new TreeNode<T>(pre.get(0));
}
TreeNode<T> root = new TreeNode<T>(pre.get(0));
// 找出根节点在中序中的位置
int index = 0;
while (!mid.get(index++).equals(pre.get(0))) {
}
// 构建左子树的前序
List<T> preLeft = new ArrayList<T>(index);
// 左子树的中序
List<T> midLeft = new ArrayList<T>(index);
for (int i = 1; i < index; i++) {
preLeft.add(pre.get(i));
}
for (int i = 0; i < index - 1; i++) {
midLeft.add(mid.get(i));
}
// 重建左子树
root.leftChild = getTreeFromPreAndMid(preLeft, midLeft);
// 右子树的前序
List<T> preRight = new ArrayList<T>(pre.size() - index - 1);
// 右子树的中序
List<T> midRight = new ArrayList<T>(pre.size() - index - 1);
for (int i = 0; i <= pre.size() - index - 1; i++) {
preRight.add(pre.get(index + i));
}
for (int i = 0; i <= pre.size() - index - 1; i++) {
midRight.add(mid.get(index + i));
}
// 重建→子树
root.rightChild = getTreeFromPreAndMid(preRight, midRight);
return root;
}
/**
* equals: 查看node1和node2两棵树是否相等(两棵树所有节点都相等)
*
* @param node1
* node2 两个节点
* @return boolean 返回类型
*/
public static <T> boolean equals(TreeNode<T> node1, TreeNode<T> node2) {
// TODO Auto-generated method stub
if (node1 == null && node2 == null) {
return true;
} else if (node1 == null || node2 == null) {
return false;
}
boolean isEqual = node1.value.equals(node2.value);
boolean isLeftEqual = equals(node1.leftChild, node2.leftChild);
boolean isRightEqual = equals(node1.rightChild, node2.rightChild);
return isEqual && isLeftEqual && isRightEqual;
}
}