1. 二叉树概念
一棵二叉树是结点的一个有限集合。该集合或者为空,或者是由一个根节点加上两棵分别称为左子树和右子树组成。
满二叉树:在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子节点都在同一层上。
完全二叉树:如果一棵具有N个结点的二叉树的结构与满二叉树的前N个结点的结构相同,称为完全二叉树。
2. 二叉树的特点
- 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。
- 二叉树的子树有左右之分,其子树的次序不能颠倒。
3. 二叉树的遍历
遵循某种次序,遍历二叉树中的所有节点,使得每个结点被访问一次,而且仅访问一次。“访问”:即对结点施行某些操作。
递归遍历:
package com.openlab.node;
public class Node {
public Node parentNode;
public Node leftNode;
public Node rightNode;
public int data;
public Node(int data) {
this.data = data;
}
/**
* 添加节点
* @param newNode 创建的新节点
*/
public void addNode(Node newNode) {
if(newNode.data < this.data) {
if(leftNode == null) {
leftNode = newNode;
newNode.parentNode = this;//保存父节点
}else {
leftNode.addNode(newNode);
}
}else {
if(rightNode == null) {
rightNode = newNode;
newNode.parentNode = this;//保存父节点
}else {
rightNode.addNode(newNode);
}
}
}
/**
* 先序遍历
*/
public void xianXu() {
System.out.println(data);
if(leftNode != null) {
leftNode.xianXu();
}
if(rightNode != null) {
rightNode.xianXu();
}
}
/**
* 中序遍历
*/
public void zhongXu() {
if(leftNode != null) {
leftNode.zhongXu();
}
System.out.println(data);
if(rightNode != null) {
rightNode.zhongXu();
}
}
/**
* 后序遍历
*/
public void houXu() {
if(leftNode != null) {
leftNode.houXu();
}
if(rightNode != null) {
rightNode.houXu();
}
System.out.println(data);
}
}
非递归遍历:
//先序
public void xianXu(Node newNode) {
if(newNode==null) {
System.out.println("空树");
return;
}
Node tmp=newNode;
Stack<Node> s=new Stack<Node>();
s.push(tmp); //根节点入栈
while(!s.empty()) {
//1.访问根节点
Node p=s.pop();
System.out.print(p.data+" ");
//2.如果根节点存在右孩子,则将右孩子入栈
if(p.rightNode!=null) {
s.push(p.rightNode);
}
//3.如果根节点存在左孩子,则将左孩子入栈
if(p.leftNode!=null) {
s.push(p.leftNode);
}
}
}
//中序
public void zhongXu(Node newNode) {
if(newNode==null) {
System.out.println("空树");
return;
}
Node tmp=newNode;
Stack<Node> s=new Stack<Node>();
while(tmp!=null || !s.empty()) {
//1.将根节点入栈
//2.将所有左孩子入栈
while(tmp!=null) {
s.push(tmp);
tmp=tmp.leftNode;
}
//3.访问栈顶元素
tmp=s.pop();
System.out.print(tmp.data+" ");
//4.如果栈顶元素存在右孩子,则将右孩子赋值给tmp,也就是将右孩子入栈
if(tmp.rightNode!=null) {
tmp=tmp.rightNode;
}
//否则,将tmp置为null,表示下次要访问的是栈顶元素
else {
tmp=null;
}
}
}
//后序
public void houXu(Node newNode) {
if(newNode==null) {
System.out.println("空树");
return;
}
Node tmp=newNode; //当前节点
Node prev=null; //上一次访问的节点
Stack<Node> s=new Stack<Node>();
while(tmp!=null || !s.empty()) {
//1.将根节点及其左孩子入栈
while(tmp!=null) {
s.push(tmp);
tmp=tmp.leftNode;
}
if(!s.empty()) {
//2.获取栈顶元素值
tmp=s.peek();
//3.没有右孩子,或者右孩子已经被访问过
if(tmp.rightNode==null || tmp.rightNode==prev) {
//则可以访问栈顶元素
tmp=s.pop();
System.out.print(tmp.data+" ");
//标记上一次访问的节点
prev=tmp;
tmp=null;
}
//4.存在没有被访问的右孩子
else {
tmp=tmp.rightNode;
}
}
}
}
创建树类,调用遍历方法:
package com.openlab.node;
public class MyTree {
private Node root;//保存的是根节点
/**
* 进行数据的保存
* @param data 要保存的数据
*/
public void add(int data) {
Node newNode = new Node(data);
if(root == null)
root = newNode;
else
root.addNode(newNode);
}
public void sortXianXu() {
if(root == null) return;
root.xianXu();
}
public void sortZhongXu() {
if(root == null) return;
root.zhongXu();
}
public void sortHouXu() {
if(root == null) return;
root.houXu();
}
}
测试:
package com.openlab.node;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyTree my = new MyTree();
my.add(20);
my.add(17);
my.add(19);
my.add(22);
my.add(15);
my.add(18);
my.sortXianXu();
System.out.println();
my.sortZhongXu();
System.out.println();
my.sortHouXu();
}
}