Java实现树的有关操作(一)

1.树的定义及存储方式

1.1树的定义

/**
 * 树的定义
 * 每一棵子树又可以看成一棵树,所以树的定义用到了递归
 */
public class TreeNode<T>{
    private int index;
    private T data;
    private TreeNode leftChild;
    private TreeNode rightChild;
}

1.2存储方式

因为二叉树的运用较多,所以只以二叉树为例
/**
 * 使用双向链表存储二叉树
 */
class TreeNode{
    int data;
    TreeNode leftChild;
    TreeNode rightChild;
}

2.二叉树的遍历

2.1递归实现二叉树遍历

/**
 * 前序遍历(中左右)
 */
    public void preOrder(TreeNode root){
        if(root == null){
            return;
        } else{
            System.out.println("preOrder data:"+root.data);
            preOrder(root.leftChild);
            preOrder(root.rightChild);
        }
    }
/**
 * 中序遍历(左中右)
 */
    public void midOrder(TreeNode root){
        if(root == null){
            return;
        } else{
            midOrder(root.leftChild);
            System.out.println("midOrder data:"+root.data);
            midOrder(root.rightChild);
        }
    }

/**
 * 后序遍历(左右中)
 */
    public void postOrder(TreeNode root){
        if(root == null){
            return;
        } else{
            postOrder(root.leftChild);
            postOrder(root.rightChild);
            System.out.println("postOrder data:"+root.data);
        }
    }

2.2非递归实现二叉树遍历

非递归前序遍历
每访问一个结点后,在向左子树遍历下去之前,利用栈来记录该结点的右子女(如果有的话),以便在左子树退回时可以直接从栈顶取得右子树的根结点,继续其右子树的遍历。上图是过程的演示,先将null压入栈中,当栈中无元素时将其推出,表示结束。
/**
 * 非递归前序遍历二叉树
 */
public void preOrderNonRecursive(TreeNode root){
    Stack<TreeNode> stack = new Stack<>();
    stack.push(null);
    while(root != null){
        //访问根节点
        System.out.println("preOrderNonRecursive data:"+root.data);
        //当前节点右子树不为空则放入栈中
        if(root.rightChild != null){
            stack.push(root.rightChild);
        }
        //访问左子树
        if(root.leftChild != null){
            root = root.leftChild;
        } else{
            root = stack.pop();
        }
    }
}
非递归中序遍历
从根结点开始沿着leftChild到最下角的结点,将指针依次压入栈中,直到该结点的leftChild指针为NULL。访问它的数据后,再遍历该结点的右子树。此时该结点为栈中推出的指针。
/**
 * 非递归中序遍历二叉树
 */
public void midOrderNonRecursive(TreeNode root){
    Stack<TreeNode> stack = new Stack<>();
    do{
        while(root != null){
            stack.push(root.leftChild);
            root = root.leftChild;
        }
        if(!stack.empty()){
            root = stack.pop();
            System.out.println("preOrderNonRecursive data:"+root.data);
            root = root.rightChild;
        }
    } while(root != null || !stack.empty());
}
非递归后序遍历
因为后序遍历的访问顺序为左右根,所以在访问的时候比较麻烦,需要考虑到访问完左结点后,当前结点有无右结点需要访问,若有则需要右进访问右子树,所以要有一个变量来记录当前结点。 
  • 从根结点开始沿着leftChild到最下角的结点,将指针依次压入栈中,直到该结点的leftChild指针为NULL。
  • 判断当前结点有无右子树,若有,则优先访问右子树
  • 无右子树货已经访问过右子树则访问当前结点
    /**
     * 后序遍历非递归算法
     * output:D-E-B-F-C-A
     *
     * @param root
     */
public void postOrderNonRecursive(TreeNode root) {

    Stack<TreeNode> nodeStack = new Stack<>();
    // 上一个结点
    TreeNode prev = root;
    do {
        while (root != null) {
            nodeStack.push(root);
            root = root.leftChild;
        }

        // 访问当前结点的右结点
        if (!nodeStack.empty()) {
            // 获取右子树,但先不弹出
            TreeNode temp = nodeStack.peek().rightChild;
            // 不存在右子树或右子树已经访问过,可以访问父结点
            if (temp == null || temp == prev) {

                root = nodeStack.pop();
                System.out.println("postOrderNonRecursive data:" + root.getData());
                // 记录访问过的结点
                prev = root;
                // 当前结点置空
                root = null;
            } else {
                // 存在右子树,需要优先访问右子树
                root = temp;
            }
        }
    } while (root != null || !nodeStack.empty());
}
发布了5 篇原创文章 · 获赞 3 · 访问量 325

猜你喜欢

转载自blog.csdn.net/weixin_42323041/article/details/105623962