前面介绍有有序数组和链表,有序数组可以根据下标,查询很快,但是插入和删除效率低,平均要移动N/2次,很是费时。而链表添加删除快,但是查询很慢需要一个一个找。于是树结构就来了,它具备有数组查询快的优点,也具有链表增删快的优点。
树
树(tree)是一种抽象数据类型(ADT),用来模拟具有树状结构性质的数据集合。
二叉树
二叉树:树的每个节点最多有两个节点。
二叉搜索树:若它的左子树不为空,则左子树的所有节点的值均小于根节点的值,若它的的右子树不为空,则右子树的所有节点的值均大于它的根节点的值。
查找节点:
1:查找值比当前节点值大,则搜索右子树
2:查找值等于当前节点值,停止搜索(终止条件)
3:查找值小于当前节点值,则搜索左子树
插入节点
要插入节点,必须先找到插入的位置,与查找操作相似,由于二叉搜索树的特殊性,待插入的节点也需要从根节点开始进行比较,小于根节点则于根节点左子树比较,反之则与右子树比较,直到左子树或右子树为空,则插入到相应为空的位置,在比较的过程中要注意保存父节点的信息及待插入的位置是父节点的左子树还是右子树,才能插入到正确的位置。
遍历树
遍历树是根据一种特定的顺序访问树的每一个节点,比较常用的有前序遍历,中序遍历和后序遍历。而二叉搜索树最常用的是中序遍历。
1.中序遍历:左子树===>根节点===>右子树
2.前序遍历:根节点===>左子树===>右子树
3.后序遍历:左子树===>右子树===>根节点
查找最大值和最小值
找最小值,先找根的左节点,然后一直找这个左节点的左节点,直到找到没有左节点的节点,那么这个节点就是最小值。同理要找最大值,一直找根节点的右节点,直到没有右节点,则就是最大值。
删除节点
删除节点是二叉搜索树中最复杂的操作,删除的节点有三种情况,前两种比较简单,第三种比较复杂。
1.该节点是叶节点(没有子节点)
2.该节点有一个子节点
3.该节点有两个子节点
删除没有子节点的节点
要删除叶节点,只需要改变该节点的父节点引用该节点的值,即将其引用改用为null即可,要删除的节点依然存在,但它已经不是树的一部分了,由于Java语言的垃圾回收机制,我们不需要非得把节点本身删掉,一旦Java意识到程序不在与该节点有关联,就会自动把它清理出存储器。
删除节点,我们要先找到该节点,并记录该节点是否有子节点,如果没有子节点,接着检查是否是根节点,如果是根节点,只需要将其设置为null即可,如果不是根节点,是叶节点,那么断开父节点和其的关系即可。
删除有一个子节点的节点
删除有一个子节点的节点,我们只需要将其父节点原本指向该节点的引用,改为指向该节点的子节点即可。
删除有两个子节点的节点
删除真的有必要么?
通过上面讨论我们发现删除其实挺复杂的,其实我们可以不用真正的删除该节点,只需要在Node类中增加一个标识字段isDelete,当该字段为true时,表示该节点已经删除,反之没有删除,那么我们在做比如find()等操作时,要先判断isDelete字段是否为true,这样删除的节点并不会改变树的结构。