树是一个非空元素的集合,其中一个元素为根,其余元素为子树,树根是唯一没有父母的元素,相同父母的孩子是兄弟。
树的高度是指树的级的个数,元素的度是指孩子的个数,叶子节点的度为0,如图所示。
二叉树是一种特殊的树,二叉树的区别如下:
(1)二叉树的每个元素正好有两棵子树,树可以有任意棵
(2)二叉树中每个元素是有序的(左右不能互换),二树是无序的
(3)二叉树允许为空(根节点=null),树不能为空(有争议)
二叉树典型结构如图所示
有以下特性:
(1)一棵二叉树有n个元素,有n-1条边
(2)一棵二叉树的高度为h(≥0),则最少有h个元素,最多有2^h-1个元素
(3)一棵二叉树有n个元素(>0),二叉树的最大高度是n,最小高度是log2(n+1)
(4)叶子节点数目=度为2的节点数目+1
二叉树可以采用链表描述和数组描述
采用链表描述:
采用链表描述需要首先描述单个节点,每个节点需要保持的信息包括左孩子、有孩子和元素值,左孩子和右孩子可以用指针描述,代码如下:
1 class BinaryTreeNode{ 2 public BinaryTreeNode left, right;//左子数,右子数 3 int val;//节点元素 4 //提供不同的初始化函数 5 public BinaryTreeNode(){ 6 left = right = null; 7 } 8 public BinaryTreeNode(int val){ 9 this.val = val; 10 left = right = null; 11 } 12 public BinaryTreeNode(int val, BinaryTreeNode left, BinaryTreeNode right){ 13 this.val = val; 14 this.left = left; 15 this.right = right; 16 } 17 }
然后实现二叉树的操作,二叉树需要实现的操作有元素的增删改查以及打印等信息,二叉树主要实现功能如下:
public class BinaryTree { private BinaryTreeNode root; private int treeSize; class BinaryTreeNode{ public BinaryTreeNode left, right;//左子数,右子数 int val;//节点元素 //提供不同的初始化函数 public BinaryTreeNode(){ left = right = null; } public BinaryTreeNode(int val){ this.val = val; left = right = null; } public BinaryTreeNode(int val, BinaryTreeNode left, BinaryTreeNode right){ this.val = val; this.left = left; this.right = right; } } //前序遍历 public void preOrder(BinaryTreeNode binaryTreeNode){ } //中序遍历 public void inOrder(BinaryTreeNode binaryTreeNode){ } //后续遍历 public void postOrder(BinaryTreeNode binaryTreeNode){ } //层次遍历 public void levelOrder(BinaryTreeNode binaryTreeNode){ } //返回节点数目 public final int size(){ return treeSize; } //检查是树否为空 public final boolean isEmpty() { return treeSize == 0; } //确定二叉树的高度 public int heightRoot(){ } //查找结点 public BinaryTreeNode find(int value){ return current; } //增加节点 public void insert(int value){ } //查找最小值 public int minimum(){ } //根据值,删除节点 public boolean delete(int value){ return true; } }
在所有功能中,节点的数目以及检查树是否为空代码较为简单不做叙述,其他功能实现方式如下。
前序遍历(DLR):又叫先跟遍历,属于深度优先遍历,遍历方式是根->左->右
中序遍历(LDR):又叫中跟遍历,属于深度优先遍历,遍历方式是左->根->右
后续遍历(LRD):又叫后根遍历,属于深度优先遍历,遍历方式是左->右->根
层次遍历:属于广度优先遍历,自上而下,自左向右逐层遍历节点。
各个遍历方式如下图所示:
前序遍历反映了深度优先搜索的思想,沿着二叉树的枝干从左到右游历一圈就是前序遍历,如图所示。
中序遍历能够应用在BST(Binary Sort Tree|二叉排序树)中,遍历出来的结果一定是有序的,对于一个二叉树进行垂直投影也可以得到中序遍历结果,如图所示:
此外,中序遍历还可以用于表示中缀表达式,后续遍历可以用于后缀表达式,效果如图所示:
层次遍历,层次遍历反应的是广度优先搜索思想,对于四种遍历方式,知道任意一种不能唯一的确定数据结构,如果知道中序遍历和另外任意一种遍历方式,就能够唯一的确定一棵树。
前序遍历、中序遍历和后续遍历的实现代码如下:
//前序遍历 public void preOrder(int binaryTreeNode){ //前序遍历二叉树 if(binaryTreeNode >= 0 && binaryTreeNode < treeSize){ visitTreeNode(binaryTreeNode); preOrder(2*binaryTreeNode+1); preOrder(2*binaryTreeNode+2); } } //中序遍历 public void inOrder(int binaryTreeNode){ //中序遍历二叉树 if(binaryTreeNode >= 0 && binaryTreeNode < treeSize){ inOrder(2*binaryTreeNode+1); visitTreeNode(binaryTreeNode); inOrder(2*binaryTreeNode+2); } } //后续遍历 public void postOrder(int binaryTreeNode){ //后续遍历二叉树 if(binaryTreeNode >= 0 && binaryTreeNode < treeSize){ postOrder(2*binaryTreeNode+1); postOrder(2*binaryTreeNode+2); visitTreeNode(binaryTreeNode); } }
层次遍历的实现方式稍微复杂,层次遍历首先需要记录每一层的换行的地方,我们可以采用nlast指针始终指向最右的节点来实现,其次需要将每一层的节点依次打印,我们可以借助链表实现,整体的访问过程如下图所示:
代码实现如下:
//层次遍历 public void levelOrder(BinaryTreeNode binaryTreeNode){ //层次遍历二叉树 Queue<BinaryTreeNode> nodeQueue = new LinkedList<BinaryTreeNode>(); BinaryTreeNode last=binaryTreeNode; BinaryTreeNode nlast=binaryTreeNode; while(binaryTreeNode != null){ visitTreeNode(binaryTreeNode); last = binaryTreeNode; //将孩子加入队列 if(binaryTreeNode.left != null){ nodeQueue.offer(binaryTreeNode.left); } if(binaryTreeNode.right != null){ nodeQueue.offer(binaryTreeNode.right); } //提取下一个要访问的节点 if(nodeQueue.isEmpty() == true){ return;//此处可以退出循环 } binaryTreeNode = nodeQueue.poll(); if(last == nlast){ //该层打印结束,需要换行 System.out.println(); if(nlast.right != null){ nlast = nlast.right; } } } }
树的高度确定只需要递归判定左右子树的高度即可,实现代码如下:
//确定二叉树的高度 public int heightRoot(){ return height(root); } private int height(BinaryTreeNode binaryTreeNode){ int hl, hr;//左树高度,右树高度 if(binaryTreeNode == null){ return 0; } hl = height(binaryTreeNode.left); hr = height(binaryTreeNode.right); if(hl > hr) return ++hl; else return ++hr; }
节点的插入:插入节点从根节点出发,如果小于根节点,就向左子树移动,与左孩子比较,如果大于根节点就向右子树移动,与有孩子比较,知道遇到空节点,放到该位置,实现代码如下:
//增加节点 public void insert(int value){ BinaryTreeNode node = new BinaryTreeNode(value); if(root == null){ //将增加的节点设置为根节点 root = node; }else{ BinaryTreeNode current = root; BinaryTreeNode parent = root; while(current != null){ parent = current;//记录父类信息,防止丢失父类信息 if(value < current.val){ current = current.left; }else{ current = current.right; } } if(value < parent.val){ parent.left = node; }else{ parent.right = node; } } treeSize++; }
查找最小值:根据二叉树的插入方式可以看出,该二叉树属于二叉查找树,所有节点都满足左子树<该节点<右子树,因此我们按照这个顺序查找最小值即可,代码如下。同理,也可以查找最大值。
//查找最小值 public int minimum(){ BinaryTreeNode current = new BinaryTreeNode(); current = root; while(current.left != null){ current = current.left; } return current.val; }
查找结点:根据查找二叉树的性质查找即可,代码如下
//查找结点 public BinaryTreeNode find(int value){ BinaryTreeNode current = root; while(value != current.val){ if(value < current.val){ current = current.left; }else{ current = current.right; } if(current == null) return null;//没有找到 } return current; }
删除节点:对于二叉树来说,删除节点最为复杂,删除节点首先要查找结点,按照节点二叉树的特性首先找到要删除的节点,查找的代码如下:
BinaryTreeNode current; BinaryTreeNode parent = new BinaryTreeNode(); boolean isLeftTrue = false; current = root; //首先查找这个节点 while(current.val != value){ parent = current;//保存父类信息 if(value < current.val){ current = current.left; isLeftTrue = true; }else{ current = current.right; isLeftTrue = false; } if(current == null){ //判断是否找到 return false; } }
然后根据要删除节点的情况分为四种情况,分别是没有孩子的节点(叶子)、有左孩子的节点、有有孩子的节点和有两个孩子的节点。
对于没有孩子的节点,直接删除即可
//删除一个子节点的情况 if(current.left == null && current.right == null){ //节点是叶子节点 if(current == root)//判断是根节点 root = null; else if(isLeftTrue)//删除左节点 parent.left = null; else//删除右节点 parent.right = null; }
对于只有一个孩子的节点,先删除该节点,然后将该孩子节点直接放到该节点的位置即可,代码如下:
else if(current.left == null){ //只有右节点 if(current == root)//判断是根节点 root = null; else if(isLeftTrue)//删除左节点 parent.left = current.right; else//删除右节点 parent.right = current.right; }else if(current.right == null){ //只有左节点 if(current == root)//判断是根节点 root = null; else if(isLeftTrue)//删除左节点 parent.left = current.left; else//删除右节点 parent.right = current.left; }
对于两个孩子的节点,首先要找到后继节点,然后将后继节点来代替该节点即可,所谓后续节点即也就是中序后继(比这个节点大一点的数),对于某一结点的后继节点一定存在于右子树,因为只有右子树比这个节点大,然后找大的最少的树,寻找右子树的最小值即可(沿着左孩子寻找即可)。寻找后继节点的代码如下:
//查找后继节点 private BinaryTreeNode getSuccessor(BinaryTreeNode delNode){ BinaryTreeNode current = delNode.right;//先定位到右子树 BinaryTreeNode parent = delNode; //寻找右子树的最小值 while(current.left!=null){ parent = current; current = current.left; } //如果继点有分支(一定是右分支),因为这个继点要移动到删除节点的位置,需要将继点的右分支放在继点的位置 if(current != delNode.right){ parent.left = current.right;//继点的右分支放在继点的位置 current.right = delNode.right;//将继点放到删除节点的位置 } return current; }
然后将继点放在删除的节点位置即可,代码如下:
else{ //有两个分支节点 BinaryTreeNode successor = getSuccessor(current); if(current == root){ root = successor; }else if(isLeftTrue){ parent.left = successor; }else{ parent.right = successor; } successor.left = current.left; }
二叉树删除节点的整体代码如下:
//根据值,删除节点 public boolean delete(int value){ BinaryTreeNode current; BinaryTreeNode parent = new BinaryTreeNode(); boolean isLeftTrue = false; current = root; //首先查找这个节点 while(current.val != value){ parent = current;//保存父类信息 if(value < current.val){ current = current.left; isLeftTrue = true; }else{ current = current.right; isLeftTrue = false; } if(current == null){ //判断是否找到 return false; } } //删除一个子节点的情况 if(current.left == null && current.right == null){ //节点是叶子节点 if(current == root)//判断是根节点 root = null; else if(isLeftTrue)//删除左节点 parent.left = null; else//删除右节点 parent.right = null; }else if(current.left == null){ //只有右节点 if(current == root)//判断是根节点 root = null; else if(isLeftTrue)//删除左节点 parent.left = current.right; else//删除右节点 parent.right = current.right; }else if(current.right == null){ //只有左节点 if(current == root)//判断是根节点 root = null; else if(isLeftTrue)//删除左节点 parent.left = current.left; else//删除右节点 parent.right = current.left; }else{ //有两个分支节点 BinaryTreeNode successor = getSuccessor(current); if(current == root){ root = successor; }else if(isLeftTrue){ parent.left = successor; }else{ parent.right = successor; } successor.left = current.left; } return true; } //查找后继节点 private BinaryTreeNode getSuccessor(BinaryTreeNode delNode){ BinaryTreeNode current = delNode.right;//先定位到右子树 BinaryTreeNode parent = delNode; //寻找右子树的最小值 while(current.left!=null){ parent = current; current = current.left; } //如果继点有分支(一定是右分支),因为这个继点要移动到删除节点的位置,需要将继点的右分支放在继点的位置 if(current != delNode.right){ parent.left = current.right;//继点的右分支放在继点的位置 current.right = delNode.right;//将继点放到删除节点的位置 } return current; }
二叉树所有代码及测试程序如下所示:
package dataStructure; import java.util.LinkedList; import java.util.Queue; public class BinaryTree { private BinaryTreeNode root; private int treeSize; class BinaryTreeNode{ public BinaryTreeNode left, right;//左子数,右子数 int val;//节点元素 //提供不同的初始化函数 public BinaryTreeNode(){ left = right = null; } public BinaryTreeNode(int val){ this.val = val; left = right = null; } public BinaryTreeNode(int val, BinaryTreeNode left, BinaryTreeNode right){ this.val = val; this.left = left; this.right = right; } } //访问一个节点 private void visitTreeNode(BinaryTreeNode binaryTreeNode){ System.out.print(binaryTreeNode.val+" "); } //前序遍历 public void preOrder(BinaryTreeNode binaryTreeNode){ //前序遍历二叉树 if(binaryTreeNode != null){ visitTreeNode(binaryTreeNode); preOrder(binaryTreeNode.left); preOrder(binaryTreeNode.right); } } //中序遍历 public void inOrder(BinaryTreeNode binaryTreeNode){ //中序遍历二叉树 if(binaryTreeNode != null){ inOrder(binaryTreeNode.left); visitTreeNode(binaryTreeNode); inOrder(binaryTreeNode.right); } } //后续遍历 public void postOrder(BinaryTreeNode binaryTreeNode){ //后续遍历二叉树 if(binaryTreeNode != null){ postOrder(binaryTreeNode.left); postOrder(binaryTreeNode.right); visitTreeNode(binaryTreeNode); } } //层次遍历 public void levelOrder(BinaryTreeNode binaryTreeNode){ //层次遍历二叉树 Queue<BinaryTreeNode> nodeQueue = new LinkedList<BinaryTreeNode>(); BinaryTreeNode last=binaryTreeNode; BinaryTreeNode nlast=binaryTreeNode; while(binaryTreeNode != null){ visitTreeNode(binaryTreeNode); last = binaryTreeNode; //将孩子加入队列 if(binaryTreeNode.left != null){ nodeQueue.offer(binaryTreeNode.left); } if(binaryTreeNode.right != null){ nodeQueue.offer(binaryTreeNode.right); } //提取下一个要访问的节点 if(nodeQueue.isEmpty() == true){ return;//此处可以退出循环 } binaryTreeNode = nodeQueue.poll(); if(last == nlast){ //该层打印结束,需要换行 System.out.println(); if(nlast.right != null){ nlast = nlast.right; } } } } //返回节点数目 public final int size(){ return treeSize; } //检查是树否为空 public final boolean isEmpty() { return treeSize == 0; } //确定二叉树的高度 public int heightRoot(){ return height(root); } private int height(BinaryTreeNode binaryTreeNode){ int hl, hr;//左树高度,右树高度 if(binaryTreeNode == null){ return 0; } hl = height(binaryTreeNode.left); hr = height(binaryTreeNode.right); if(hl > hr) return ++hl; else return ++hr; } //查找结点 public BinaryTreeNode find(int value){ BinaryTreeNode current = root; while(value != current.val){ if(value < current.val){ current = current.left; }else{ current = current.right; } if(current == null) return null;//没有找到 } return current; } //增加节点 public void insert(int value){ BinaryTreeNode node = new BinaryTreeNode(value); if(root == null){ //将增加的节点设置为根节点 root = node; }else{ BinaryTreeNode current = root; BinaryTreeNode parent = root; // while(true){ // if(value < parent.val){ // current = parent.left; // if(current == null){ // parent.left = node;//插入节点 // return; // }else{ // parent = parent.left; // } // }else{ // current = parent.right; // if(current == null){ // parent.right = node;//插入节点 // return; // }else{ // parent = parent.right; // } // } // } while(current != null){ parent = current;//记录父类信息,防止丢失父类信息 if(value < current.val){ current = current.left; }else{ current = current.right; } } if(value < parent.val){ parent.left = node; }else{ parent.right = node; } } treeSize++; } //查找最小值 public int minimum(){ BinaryTreeNode current = new BinaryTreeNode(); current = root; while(current.left != null){ current = current.left; } return current.val; } //根据值,删除节点 public boolean delete(int value){ BinaryTreeNode current; BinaryTreeNode parent = new BinaryTreeNode(); boolean isLeftTrue = false; current = root; //首先查找这个节点 while(current.val != value){ parent = current;//保存父类信息 if(value < current.val){ current = current.left; isLeftTrue = true; }else{ current = current.right; isLeftTrue = false; } if(current == null){ //判断是否找到 return false; } } //删除一个子节点的情况 if(current.left == null && current.right == null){ //节点是叶子节点 if(current == root)//判断是根节点 root = null; else if(isLeftTrue)//删除左节点 parent.left = null; else//删除右节点 parent.right = null; }else if(current.left == null){ //只有右节点 if(current == root)//判断是根节点 root = null; else if(isLeftTrue)//删除左节点 parent.left = current.right; else//删除右节点 parent.right = current.right; }else if(current.right == null){ //只有左节点 if(current == root)//判断是根节点 root = null; else if(isLeftTrue)//删除左节点 parent.left = current.left; else//删除右节点 parent.right = current.left; }else{ //有两个分支节点 BinaryTreeNode successor = getSuccessor(current); if(current == root){ root = successor; }else if(isLeftTrue){ parent.left = successor; }else{ parent.right = successor; } successor.left = current.left; } return true; } //查找后继节点 private BinaryTreeNode getSuccessor(BinaryTreeNode delNode){ BinaryTreeNode current = delNode.right;//先定位到右子树 BinaryTreeNode parent = delNode; //寻找右子树的最小值 while(current.left!=null){ parent = current; current = current.left; } //如果继点有分支(一定是右分支),因为这个继点要移动到删除节点的位置,需要将继点的右分支放在继点的位置 if(current != delNode.right){ parent.left = current.right;//继点的右分支放在继点的位置 current.right = delNode.right;//将继点放到删除节点的位置 } return current; } public static void main(String[] args){ BinaryTree tree = new BinaryTree(); // 二叉树结构如下 // 10 // 6 15 // 4 8 12 18 // 1 5 7 9 11 13 16 19 tree.insert(10); tree.insert(6); tree.insert(15); tree.insert(4); tree.insert(8); tree.insert(1); tree.insert(5); tree.insert(7); tree.insert(9); tree.insert(12); tree.insert(18); tree.insert(11); tree.insert(13); tree.insert(16); tree.insert(19); System.out.println(" 前序遍历"); tree.preOrder(tree.root); System.out.println(" 中序遍历"); tree.inOrder(tree.root); System.out.println(" 后序遍历"); tree.postOrder(tree.root); System.out.println(" 层次遍历"); tree.levelOrder(tree.root); System.out.println(" 寻找"+tree.find(10).val); tree.delete(8); tree.levelOrder(tree.root); System.out.println(" "); tree.delete(11); tree.levelOrder(tree.root); System.out.println(" "); tree.delete(12); tree.levelOrder(tree.root); System.out.println(" "); tree.delete(4); tree.levelOrder(tree.root); } }
运行结果如下:
前序遍历
10 6 4 1 5 8 7 9 15 12 11 13 18 16 19
中序遍历
1 4 5 6 7 8 9 10 11 12 13 15 16 18 19
后序遍历
1 5 4 7 9 8 6 11 13 12 16 19 18 15 10
层次遍历
10
6 15
4 8 12 18
1 5 7 9 11 13 16 19
寻找10
10
6 15
4 9 12 18
1 5 7 11 13 16 19
10
6 15
4 9 12 18
1 5 7 13 16 19
10
6 15
4 9 13 18
1 5 7 16 19
10
6 15
5 9 13 18
1 7 16 19
此外二叉树还可与用数组实现,采用数组实现不用采用指针记录连接关系,每个节点的左节点是index*2+1,右节点是诗index*2+2,在节点删除的时候,需要手动将节点置空。采用数组实现的二叉树,会存在空间浪费,效率也不是很高,空间表示二叉树的结果如图所示:
完整代码实现如下所示:
package dataStructure; import java.util.LinkedList; import java.util.Queue; public class BinaryTreeInArray { private int root; private int treeSize; private int[] nodeArray = new int[30]; public BinaryTreeInArray(){ root = 0; treeSize = 0; for(int i=0; i<30; i++) nodeArray[i] = -1; } //访问一个节点 private void visitTreeNode(int binaryTreeNode){ System.out.print(nodeArray[binaryTreeNode]+" "); } //前序遍历 public void preOrder(int binaryTreeNode){ //前序遍历二叉树 if(binaryTreeNode >= 0 && binaryTreeNode < treeSize){ visitTreeNode(binaryTreeNode); preOrder(2*binaryTreeNode+1); preOrder(2*binaryTreeNode+2); } } //中序遍历 public void inOrder(int binaryTreeNode){ //中序遍历二叉树 if(binaryTreeNode >= 0 && binaryTreeNode < treeSize){ inOrder(2*binaryTreeNode+1); visitTreeNode(binaryTreeNode); inOrder(2*binaryTreeNode+2); } } //后续遍历 public void postOrder(int binaryTreeNode){ //后续遍历二叉树 if(binaryTreeNode >= 0 && binaryTreeNode < treeSize){ postOrder(2*binaryTreeNode+1); postOrder(2*binaryTreeNode+2); visitTreeNode(binaryTreeNode); } } //层次遍历 public void levelOrder(int binaryTreeNode){ //层次遍历二叉树 Queue<Integer> nodeQueue = new LinkedList<Integer>(); int last=binaryTreeNode; int nlast=binaryTreeNode; while(binaryTreeNode >= 0 && binaryTreeNode < treeSize){ visitTreeNode(binaryTreeNode); last = binaryTreeNode; //将孩子加入队列 if(2*binaryTreeNode+1 >= 0 && 2*binaryTreeNode+1 < treeSize){ nodeQueue.offer(2*binaryTreeNode+1); } if(2*binaryTreeNode+2 >= 0 && 2*binaryTreeNode+2 < treeSize){ nodeQueue.offer(2*binaryTreeNode+2); } //提取下一个要访问的节点 if(nodeQueue.isEmpty() == true){ return;//此处可以退出循环 } binaryTreeNode = nodeQueue.poll(); if(last == nlast){ //该层打印结束,需要换行 System.out.println(); if(2*nlast+2 >= 0 && 2*nlast+2 < treeSize){ nlast = 2*nlast+2; } } } } //返回节点数目 public final int size(){ return treeSize; } //检查是树否为空 public final boolean isEmpty() { return treeSize == 0; } //确定二叉树的高度 public int heightRoot(){ return height(root); } private int height(int binaryTreeNode){ int hl, hr;//左树高度,右树高度 if(binaryTreeNode <= 0 && binaryTreeNode < treeSize){ return 0; } hl = height(2*binaryTreeNode+1); hr = height(2*binaryTreeNode+2); if(hl > hr) return ++hl; else return ++hr; } //查找结点 public int find(int value){ int current = root; while(value != nodeArray[current]){ if(value < nodeArray[current]){ if(2*current+1 < treeSize) current = nodeArray[2*current+1]; else return -1;//没有找到 }else{ if(2*current+2 < treeSize) current = nodeArray[2*current+2]; else return -1;//没有找到 } } return nodeArray[current]; } //增加节点 public void insert(int value){ int node = value; if(nodeArray[root] == -1){ //将增加的节点设置为根节点 nodeArray[root] = node; }else{ int current = root; int parent = root; // while(true){ // if(value < nodeArray[parent]){ // current = nodeArray[2*parent+1]; // if(current >= 0 && current < treeSize){ // nodeArray[2*parent+1] = node;//插入节点 // return; // }else{ // nodeArray[parent] = nodeArray[2*parent+1]; // } // }else{ // current = nodeArray[2*parent+2]; // if(current >= 0 && current < treeSize){ // nodeArray[2*parent+2] = node;//插入节点 // return; // }else{ // parent = nodeArray[2*parent+2]; // } // } // } while(nodeArray[current] != -1){ parent = current;//记录父类信息,防止丢失父类信息 if(value < nodeArray[current]){ current = 2*current + 1; }else{ current = 2*current + 2; } } nodeArray[current] = node; } treeSize++; } //查找最小值 public int minimum(){ int current = root; while(nodeArray[2*current + 1] != -1){ current = nodeArray[2*current + 1]; } return nodeArray[current]; } //根据值,删除叶子 public boolean delete(int value){ int current; int parent = -1; boolean isLeftTrue = false; current = root; //首先查找这个节点 while(nodeArray[current] != value){ parent = current;//保存父类信息 if(value < nodeArray[current]){ if(2*current+1 < treeSize){ current = 2*current+1; isLeftTrue = true; }else return false; }else{ if(2*current+2 < treeSize){ current = 2*current+2; isLeftTrue = false; }else return false; } } //删除一个子节点的情况 if(nodeArray[2*current+1] == -1 && nodeArray[2*current+2] == -1){ //节点是叶子节点 if(current == root)//判断是根节点 nodeArray[root] = -1; else if(isLeftTrue)//删除左节点 nodeArray[2*parent+1] = -1; else//删除右节点 nodeArray[2*parent+2] = -1; }else if(nodeArray[2*current+1] == -1){ //只有右节点 if(current == root)//判断是根节点 nodeArray[root] = nodeArray[2*current+2]; else if(isLeftTrue)//删除左节点 nodeArray[2*parent+1] = nodeArray[2*current+2]; else//删除右节点 nodeArray[2*parent+2] = nodeArray[2*current+2]; nodeArray[2*current+2] = -1; }else if(nodeArray[2*current+2] == -1){ //只有左节点 if(current == root)//判断是根节点 nodeArray[root] = nodeArray[2*current+1]; else if(isLeftTrue)//删除左节点 nodeArray[2*parent+1] = nodeArray[2*current+1]; else//删除右节点 nodeArray[2*parent+2] = nodeArray[2*current+1]; nodeArray[2*current+1] = -1; }else{ //有两个分支节点 int successor = getSuccessor(current); if(current == root){ nodeArray[root] = nodeArray[successor]; }else if(isLeftTrue){ nodeArray[2*parent+1] = nodeArray[successor]; }else{ nodeArray[2*parent+2] = nodeArray[successor]; } nodeArray[successor] = -1; } return true; } //查找后继节点 private int getSuccessor(int delNode){ int current = 2*delNode+2; int parent = delNode; while(nodeArray[2*current+1] != -1){ parent = current; current = 2*current+1; } //此处是删除子节点有分支的方法 // if(current != 2*delNode+2){ // nodeArray[2*parent+1] = nodeArray[2*current+2];//将继点的右节点连接到父类的左节点,空出继点 //// nodeArray[2*parent+2] = -1;//右 // } return current; } public static void main(String[] args){ BinaryTreeInArray tree = new BinaryTreeInArray(); // 二叉树结构如下 // 10 // 6 15 // 4 8 12 18 // 1 5 7 9 11 13 16 19 tree.insert(10); tree.insert(6); tree.insert(15); tree.insert(4); tree.insert(8); tree.insert(1); tree.insert(5); tree.insert(7); tree.insert(9); tree.insert(12); tree.insert(18); tree.insert(11); tree.insert(13); tree.insert(16); tree.insert(19); System.out.println(" 前序遍历"); tree.preOrder(tree.root); System.out.println(" 中序遍历"); tree.inOrder(tree.root); System.out.println(" 后序遍历"); tree.postOrder(tree.root); System.out.println(" 层次遍历"); tree.levelOrder(tree.root); System.out.println(" 寻找"+tree.find(10)); tree.delete(8); tree.levelOrder(tree.root); System.out.println(" "); tree.delete(11); tree.levelOrder(tree.root); System.out.println(" "); tree.delete(12); tree.levelOrder(tree.root); System.out.println(" "); tree.delete(4); tree.levelOrder(tree.root); } }
运行结果如下:
前序遍历
10 6 4 1 5 8 7 9 15 12 11 13 18 16 19
中序遍历
1 4 5 6 7 8 9 10 11 12 13 15 16 18 19
后序遍历
1 5 4 7 9 8 6 11 13 12 16 19 18 15 10
层次遍历
10
6 15
4 8 12 18
1 5 7 9 11 13 16 19
寻找10
10
6 15
4 9 12 18
1 5 7 -1 11 13 16 19
10
6 15
4 9 12 18
1 5 7 -1 -1 13 16 19
10
6 15
4 9 13 18
1 5 7 -1 -1 -1 16 19
10
6 15
5 9 13 18
1 -1 7 -1 -1 -1 16 19