数据结构与算法--第19篇(树结构)

一,树结构

1,元素存储方式:

  1. 数组存储方式:
    优点:下标方式访问元素,速度快,对于有序数组,可以通过查找算法提高检索速度;
    缺点:如果插入某个值,可能涉及到整体移动,效率慢;
  2. 链式存储方式:
    优点:在一定程度上对数组进行优化,插入或删除元素只需要将其节点从其链表中添加或删除;
    缺点:检索时没有索引效率较低;
  3. 树存储方式:
    可以同时提高数据的读取、存储效率,比如二叉树,既可以保证数据的检索速率也可以保证数据的插入、删除、修改速率;

2,树的常用术语:

在这里插入图片描述

二,二叉树

1,二叉树简介

二叉树: 最多只有两个子子节点的树结构,称为左节点,右节点;
满二叉树: 所有的叶子节点(没有下一级的节点为叶子节点,如同树叶)都在最后一层,并且节点总数:2n-1;
完全二叉树: 所有叶子节点都在最后一层或者倒数第二层,且最后一层在左连续,倒数第二层在右连续;

2,二叉树遍历

前序遍历: 先输出父节点,在遍历左子树和右子树;
中序遍历: 先遍历左子树,再输出父节点,最后遍历右子树;
后序遍历: 先遍历左子树,再遍历右子树,最后输出父节点;
注: 根据父节点的输出位置就可以区分属于何种遍历;

代码实现:
package com.tree;

/**
 * @param
 * @Author: AaNeei
 * @Date: 2019/7/7  16:23
 * @Description: 游学网
 * @throws:
 */
public class BinaryTreeDemo {

    public static void main(String[] args) {
        //创建二叉树
        BinaryTree binaryTree = new BinaryTree();
        //模拟二叉树节点
        Node root = new Node(1, "军队");
        Node node1 = new Node(2, "陆军");
        Node node2 = new Node(3, "海军");
        Node node3 = new Node(4, "空军");
        Node node4 = new Node(5, "火箭军");
        Node node5 = new Node(6, "武警部队");
        binaryTree.setRoot(root);
        

    }
}

class BinaryTree {
    private Node root;

    public void setRoot(Node root) {
        this.root = root;
    }

    //调用前序
    public void preOrder() {
        if (this.root != null) {
            this.root.preOrder();
        } else {
            throw new RuntimeException("二叉树节点为空");
        }
    }

    //调用中序
    public void infixOrder() {
        if (this.root != null) {
            this.root.infixOrder();
        } else {
            throw new RuntimeException("二叉树节点为空");
        }
    }

    //调用后序
    public void postOrder() {
        if (this.root != null) {
            this.root.postOrder();
        } else {
            throw new RuntimeException("二叉树节点为空");
        }
    }
}

class Node {
    private int no;
    private String name;
    private Node left;
    private Node right;

    public Node(int no, String name) {
        this.no = no;
        this.name = name;
    }

    //前序遍历
    public void preOrder() {
        System.out.println(this);
        if (this.left != null) {
            //向左子树遍历
            this.left.preOrder();
        }
        if (this.right != null) {
            //向右子树遍历
            this.right.preOrder();
        }
    }

    //中序遍历
    public void infixOrder() {

        if (this.left != null) {
            //向左子树遍历
            this.left.infixOrder();
        }
        System.out.println(this);
        if (this.right != null) {
            //向右子树遍历
            this.right.infixOrder();
        }

    }

    //后序遍历
    public void postOrder() {
        if (this.left != null) {
            //向左子树遍历
            this.left.postOrder();
        }

        if (this.right != null) {
            //向右子树遍历
            this.right.postOrder();
        }
        System.out.println(this);
    }

    public Node(Node left, Node right) {
        this.left = left;
        this.right = right;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "Node{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}

3,二叉树查找

使用前中后序查询指定节点
前序查找:
1,先判断当前节点的no是否等于查找的值,如果相等则返回当前节点;
2,如果不相等,判断当前节点左子节点是否为空,不为空则递归前序查找;
3,如果左递归查找到,则返回节点,否则判断当前节点右子节点是否为空,非空则右递归查找;
中序查找:
1,判断当前节点左子节点是否为空,非空则递归中序查找;
2,如果找到就返回,没找到,就和当前节点比较,是则返回,否则继续向右递归中序查找;
3,如果找到就返回,否则返回null;
后序查找:
1,判断当前左子节点是否为空,非空则递归后序查找;
2,如果找到即返回,否则判断当前右子节点是否为空,非空则右递归后序查找,如果找到即返回,3,没找到,就和当前节点比较,如果是,则返回,否则返回null;

	//递归前序查找
    public Node preOrderSearch(int no) {
        if (this.no == no) {
            return this;
        }
        Node node = null;
        if (this.left != null) {
            node = this.left.preOrderSearch(no);
        }
        if (node != null) {
            return node;
        }
        if (this.right != null) {
            node = this.right.preOrderSearch(no);
        }
        return node;
    }

    //递归中序查找
    public Node infixOrderSearch(int no) {
        Node node = null;
        if (this.left != null) {
            node = this.left.infixOrderSearch(no);
        }
        if (node != null) {
            return node;
        }
        if (this.no == no) {
            return this;
        }
        if (this.right != null) {
            node = this.right.infixOrderSearch(no);
        }
        return node;
    }

    //递归后序查找
    public Node postOrderSearch(int no) {
        Node node = null;
        if (this.left != null) {
            node = this.left.postOrderSearch(no);
        }
        if (node != null) {
            return node;
        }
        if (this.right != null) {
            node = this.right.postOrderSearch(no);
        }
        if (node != null) {
            return node;
        }
        if (this.no == no) {
            return this;
        }
        return node;
    }

4,二叉树删除

分析:
1,如果删除叶子节点,则直接删除该叶子节点;
2,如果删除非叶子节点,则删除该子树(包含该节点其其下所有节点);
思路:
1,如果整个树没有子节点,并且是要删除的,则直接删除整个树;
2,因为二叉树是单项的,所以只能判断当前节点的子节点是否要删除的节点,而不能去判断当前节点就是要删除的节点;
3,如果当前节点的左子节点不为空,并且左子节点就是要删除的节点,则this.left=null,并且返回;
4,如果当前节点的右子节点不为空,并且右子节点就是要删除的节点,则this.right=null,并且返回;
5,如果2,3没有删除节点,就需要向左子树进行递归删除;
6,如果4没有删除,就需要向右子树进行递归删除;

	//删除节点
    public void delNode(int no) {
        if (root != null) {
            if (root.getNo() == no) {
                root = null;
            } else {
                root.delNode(no);
            }
        } else {
            System.out.println("二叉树为空,不能删除");
        }
    }
	
	//二叉树删除
    public void delNode(int no) {
        if (this.left != null && this.left.no == no) {
            this.left = null;
            return;
        }
        if (this.right != null && this.right.no == no) {
            this.right = null;
            return;
        }
        if (this.left != null) {
            this.left.delNode(no);
        }
        if (this.right != null) {
            this.right.delNode(no);
        }
    }

4,顺序存储二叉树

特点:
1,顺序二叉树通常是完全二叉树;
2,第n个元素的左子节点为2n+1,右子节点为2n+2,父节点为(n-1)/2;
3,n表示第几个元素,从0开始;

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值