二叉树总结:入口
二叉树的基本操作:
5、判断一个二叉树是否是BST树,判断一个BST树是否是AVl树
7、把BST树满足[begin,end]区间的值放在集合中、打印出来
1、前序遍历
前序遍历:若树为空,则空操作返回。否则,先访问根节点,然后前序遍历左子树,再前序遍历右子树,访问顺序:中 左 右
递归:先打印根节点,递归优先进入左子树打印根节点,以此类推
非递归:1操作(让二叉树的左子树依次先打印然后入栈,接着出栈 检查是否有右孩子,如果有则进入右孩子),然后重复1操作。
//前序遍历
//递归
public void n_preOrder(){
n_preOrder(this.root);
}
private void n_preOrder(BSTNode root){
if(root==null)
return;
System.out.print(root.getData() +" ");
n_preOrder(root.getLeft());
n_preOrder(root.getRight());
}
//非递归栈
//左子树依次入栈 然后回退入一个右子树,接着右子树的所有左子树再入栈,以此类推。
public void non_PreOrder(){
non_PreOrder(this.root);
}
private void non_PreOrder(BSTNode root){
if(root==null){
return;
}
Stack<BSTNode> st=new Stack<>();
while(!st.isEmpty() || root!=null) {
while (root != null) {
System.out.print(root.getData() + " ");
st.push(root);
root = root.getLeft();
}
if (!st.isEmpty()) {
root = st.peek();
st.pop();
root = root.getRight();
}
}
}
2、中序遍历
中序遍历:若树为空,则空操作返回。否则,从根节点开始(注意并不是先访问根节点),中序遍历根节点的左子树,然后是访问根节点,最后中序遍历根节点的右子树。 访问顺序:左 中 右
递归:先进入左孩子,再打印,再进入右孩子,以此类推。
非递归:与前序遍历不同,中序遍历出栈的时候再打印。从根节点开始一直将左孩子入栈,然后出栈并打印,出栈以后找出栈元素是否有右子树,如果存在,将右孩子左子树入栈,以此类推。
//中序遍历
//递归
public void n_miOrder(){
n_miOrder(this.root);
}
private void n_miOrder(BSTNode root){
if(root==null){
return;
}
n_miOrder(root.getLeft());
System.out.print(root.getData() +" ");
n_miOrder(root.getRight());
}
/**
* 非递归中序遍历
* 从根节点开始到左孩子的left一直入栈
* 出栈,并打印 ,如果当前出栈元素的右孩子不为NULL(以及右孩子的左子树不为NULL)就全部入栈,
* 如果为null 继续出栈下一个元素;
*/
public void non_miInOder(BSTNode root){
if(root==null){
return;
}
Stack<BSTNode> st=new Stack<BSTNode>();
while(!st.isEmpty() || root!=null) {
while (root != null) {
st.push(root);
root = root.getLeft();
}
root = st.peek();
st.pop();
System.out.print(root.getData() + " ");
root = root.getRight(); //右孩子以及右孩子的左子树都入栈;
}
}
3、后序遍历
后序遍历:若树为空,则空操作返回。否则,从左到右先叶子后节点的方式遍历访问左右子树,最后访问根节点。访问顺序:左右 中
递归:先进左子树,再进右子树,再打印。
非递归:从根节点开始将左子树入栈,出栈前判断栈顶元素右子树是否为空,不为空则将出栈的元素重新入栈,再将根节点指向原根节点的右子树。为空就出栈打印栈顶元素。注意出栈之前先把右孩子以及右孩子的左子树都入栈。
// 后序遍历
//递归
public void n_lastOrder(){
n_lastOrder(root);
}
private void n_lastOrder(BSTNode root){
if(root==null){
return;
}
n_lastOrder(root.getLeft());
n_lastOrder(root.getRight());
System.out.print(root.getData() +" ");
}
/**
* 非递归后序
* 从根节点开始往left一直入栈
* 出栈之前先判断当前栈顶元素的右孩子以及右孩子的左子树是否为NULL 不为null时先入栈
* 为NULL时,就出栈并 打印栈顶元素
**/
//LRV 出栈之前先把右孩子以及右孩子的左子树都入栈
public void non_LastOrder(){
if(root==null){
return;
}
Stack<BSTNode> st=new Stack<BSTNode>();
BSTNode tag=null;//记录 是否搜索过此条右子树
while (!st.isEmpty() || root!=null){
while(root!=null){
st.push(root);
root=root.getLeft();
}
root=st.peek();
st.pop();
if(root.getRight()==null || root.getRight()==tag){ //找栈顶值的右孩子
System.out.print(root.getData()+" ");
tag=root;
root=null;
}else{ //有右孩子
st.push(root);
root=root.getRight();
}
}
}
4、层序遍历
非递归:使用队列,先将根节点入队,然后再出队 打印值,再将出队元素的左右孩子入队。再循环出队,以此类推。由于队列是先入先出,所以可以保证先入的节点 先打印,即 一层遍历完了,再遍历下一层。
//层序遍历
//非递归队列(出队打印后把左右孩子都入队)
public void levelOrder(){
if(root==null){
return;
}
Queue<BSTNode> qu=new LinkedList<>();
qu.add(root);
while (!qu.isEmpty()){
root=qu.peek();
qu.poll();
System.out.print(root.getData()+" ");
if(root.getLeft()!=null){
qu.add(root.getLeft());
}
if(root.getRight()!=null){
qu.add(root.getRight());
}
}
}
//递归层序遍历
public void LeveOrder(){
int height=n_getHeight();//算BST树高度。
for(int i=0;i<=height;i++){
leve(root,i);
}
System.out.println();
}
private void leve(BSTNode root, int i) {
if(root==null){ //BST不一定是一颗完全树
return;
}
if(i==1) {
System.out.print(root.getData() +" ");
}
leve(root.getLeft(),i-1);
leve(root.getRight(),i-1);
}
//求BST树的高度
public int n_getHeight(){
return n_getHeight(root);
}
private int n_getHeight(BSTNode root){
if(root==null){
return 0;
}
int leftheight= n_getHeight(root.getLeft());
int rightheight= n_getHeight(root.getRight());
return Math.max(leftheight, rightheight)+1;
}