在非空树中,有且仅有一个根节点(Root)
当N>1时,其余节点分为m个互不相交的有限集,T1,T2… Tm.
节点的度:节点拥有的子树
叶子节点:度为0的节点(没有子节点)
分支节点:度不为0的节点(还有子节点)
树的度:树内各个节点的度的最大值(有的节点度为0,1,2,3)
那么树的度应该为3
孩子:节点子树的根
兄弟:同一父亲的孩子
堂兄弟:双亲在同一层次的节点的那些节点,比如EF和和HIJ
祖先:从根到该节点所经分支的所有节点
子孙:以某节点为根的子树的任意一节点
深度:树中节点的最大层次即有几层
有序树:树的各个节点的各个子树都看成是有序的
二叉树:每一个节点最多有两个子树即度<=2,子树有左右之分
满二叉树和完全二叉树的区别:
满二叉树:深度为k且有2^k-1个节点的二叉树,也就是说二叉树要平衡,而且子节点都有左右节点(叶子节点除外)
完全二叉树:首先必须有叶子节点,叶子节点的顺序是从左往右的,可以没有右孩子,但是不能没有左孩子,否则就不是完全二叉树
如果前一个节点都不存在左右节点,而后边存在左节点或者有节点,或者某一个节点存在右节点,但是没有左节点都不是完全二叉树
性质:
- 完全二叉树的节点数如果为n那么,深度是+1;
- 对于每一个完全二叉树的节点x,如果x=1,就是根节点,否则这个节点父节点为x/2;
- 如果节点x*2>节点个数(n),那么表示没有左孩子结点,比如7*2>12表示7这个节点没有左孩子
- 如果x*2+1 > 表示没有右孩子节点6*2+1>12,表示没有右孩子节点
二叉树的存储结构:
顺序存储结构:
将完全二叉树上编号为I的节点元素存储在一维数组下标为(i-1)上。
即(2i)一定是左节点,2i+1一定是右节点
链式存储结构:
为了避免空间的浪费,可以采用链式存储结构,因为非完全二叉树很有可能有很多地方都没有子节点,如果空着的话,空间就浪费了
遍历二叉树和线索二叉树
先序遍历:
访问根节点,先序遍历左子树,先序遍历右子树
中序遍历:
中序遍历左子树,访问根节点,中序遍历右子树
后续遍历:
后续遍历左子树,后续遍历右子树,访问根节点
其实就是看访问跟节点的先后顺序。
package com.dataStructure.tree;
import java.util.Stack;
public class TreeBean {
private String nodeName;
private TreeBean leftChild;
private TreeBean rightChild;
public TreeBean() {
}
public TreeBean(String nodeName, TreeBean leftChild, TreeBean rightChild) {
this.nodeName = nodeName;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
protected TreeBean initTree(){
TreeBean leafNode1 = new TreeBean();
leafNode1.setNodeName("D");
TreeBean leafNode2 = new TreeBean();
leafNode2.setNodeName("E");
TreeBean leafNode3 = new TreeBean();
leafNode3.setNodeName("F");
TreeBean leafNode4 = new TreeBean();
leafNode4.setNodeName("G");
TreeBean brachNode1 = new TreeBean();
brachNode1.setNodeName("B");
brachNode1.setLeftChild(leafNode1);
brachNode1.setRightChild(leafNode2);
TreeBean brachNode2 = new TreeBean();
brachNode2.setNodeName("C");
brachNode2.setLeftChild(leafNode3);
brachNode2.setRightChild(leafNode4);
TreeBean rootNode = new TreeBean();
rootNode.setNodeName("A");
rootNode.setLeftChild(brachNode1);
rootNode.setRightChild(brachNode2);
return rootNode;
}
protected void visit(TreeBean node){
System.out.print(node.getNodeName());
}
/**
* 前序排列的算法
* @param node
*/
protected void preOrderTraversal(TreeBean node){
if(node == null ){
return;
}
visit(node);//遍历root
preOrderTraversal(node.getLeftChild());//遍历左节点
preOrderTraversal(node.getRightChild());//遍历右节点
}
/**
* 中序遍历的算法
* @param node
*/
protected void inOrderTraversal(TreeBean node){
if(node == null ){
return;
}
inOrderTraversal(node.getLeftChild());//遍历左节点
visit(node);//遍历root
inOrderTraversal(node.getRightChild());//遍历右节点
}
/**
* 后序遍历的算法
* @param node
*/
protected void postOrderTraversal(TreeBean node){
if(node == null ){
return;
}
postOrderTraversal(node.getLeftChild());//遍历左节点
postOrderTraversal(node.getRightChild());//遍历右节点
visit(node);//遍历root
}
/**
* 非递归实现先序遍历
* @param node
*/
protected void preOrderNonRecursive_1(TreeBean node){
//create a stack
Stack<TreeBean> stack = new Stack<TreeBean>();
if(node == null){
return;
}
//先把父节点入栈
stack.push(node);
while(!stack.isEmpty()){
node = stack.pop();//及入及出
visit(node);
//先放置右节点,后入先出
if(node.getRightChild() != null){
stack.push(node.getRightChild());
}
if(node.getLeftChild() != null){
stack.push(node.getLeftChild());
}
}
}
/**
* 非遞歸先序遍历
* @param node
*/
protected void preOrderNonRecursive_2(TreeBean node){
//create a stack
Stack<TreeBean> stack = new Stack<TreeBean>();
if(node == null){
return;
}
TreeBean bean = node;
while(bean != null || stack.size() > 0){
//所有左节点入栈
while(bean != null ){
visit(bean);
stack.push(bean);
bean = bean.getLeftChild();
}
//画图一目了然
if(stack.size() > 0){
bean = stack.pop();
bean = bean.getRightChild();
}
}
}
/**
* 非递归后序遍历双栈法
* @param node
*/
protected void postOrderNonRecursive_doubleStack(TreeBean node){
Stack<TreeBean> stack = new Stack<TreeBean>();
Stack<TreeBean> tmpStack = new Stack<TreeBean>();
TreeBean bean = node;
while (bean != null || stack.size() > 0) {
while (bean != null) {
tmpStack.push(bean);
stack.push(bean);
bean = bean.getRightChild();
}
if (stack.size() > 0) {
bean = stack.pop();
bean = bean.getLeftChild();
}
}
while (tmpStack.size() > 0) {
bean = tmpStack.pop();
visit(bean);
}
}
/**
* 非递归后序遍历单栈法
* @param node
*/
protected void postOrderNonRecursive_singleStack(TreeBean node) {
Stack<TreeBean> stack = new Stack<TreeBean>();
TreeBean bean = node, prev = node;
while (bean != null || stack.size() > 0) {
while (bean != null) {
stack.push(bean);
bean = bean.getLeftChild();
}
if (stack.size() > 0) {
TreeBean temp = stack.peek().getRightChild();
if (temp == null || temp == prev) {
bean = stack.pop();
visit(bean);
prev = bean;
bean = null;
} else {
bean = temp;
}
}
}
}
/**
* 非递归中序遍历
* @param node
*/
protected void iterativeInorder2(TreeBean bean) {
Stack<TreeBean> stack = new Stack<TreeBean>();
TreeBean node = bean;
while (node != null || stack.size() > 0) {
while (node != null) {
stack.push(node);
node = node.getLeftChild();
}
if (stack.size() > 0) {
node = stack.pop();
visit(node);
node = node.getRightChild();
}
}
}
/**
* 层次遍历(广度优先遍历)
* @param root
*/
protected void levelOrder(TreeBean root){
if(root == null){
return;
}
System.out.println("Level:");
Queue<TreeBean> queue = new LinkedList<TreeBean>();
TreeBean currentNode = null;
TreeBean leftChildNode = null;
TreeBean rightChildNode = null;
queue.add(root);
while(!queue.isEmpty()){
currentNode = queue.poll();//出队列
visit(currentNode);
leftChildNode = currentNode.getLeftChild();
rightChildNode = currentNode.getRightChild();
//左右节点入队列
if(leftChildNode != null){
queue.add(leftChildNode);
}
if(rightChildNode != null){
queue.add(rightChildNode);
}
}
}
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
public TreeBean getLeftChild() {
return leftChild;
}
public void setLeftChild(TreeBean leftChild) {
this.leftChild = leftChild;
}
public TreeBean getRightChild() {
return rightChild;
}
public void setRightChild(TreeBean rightChild) {
this.rightChild = rightChild;
}
}