六 二叉树
- 28.树结构概述
- 29.二叉树的概述
- 30.创建二叉树
- 31.遍历二叉树
- 32.二叉树中节点的查找
- 33.删除二叉树的子树
- 34.顺序存储的二叉树的概述
- 35.顺序存储的二叉树的遍历
- 36.常用排序算法之堆排序
- 37.线索二叉树的概述
- 38.线索二叉树代码实现
- 39.线索二叉树的遍历
树结构概述
为什么使用树?其中一个原因:
- 顺序表查找方便,插入删除麻烦
- 链表,插入删除简单,但是查找麻烦
- 树综合考虑了以上问题,他的修改和查找能力比较中和。
基本概念:
二叉树的概述
能连续数满就是完全二叉树
创建二叉树
- 二叉树的五种形态:
package demo5;
public class Node {
//节点的权
int value;
//左儿子
Node leftNode;
//右儿子
Node rightNode;
public Node(int value) {
this.value=value;
}
//设置左儿子
public void setLeftNode(Node leftNode) {
this.leftNode = leftNode;
}
//设置右儿子
public void setRightNode(Node rightNode) {
this.rightNode = rightNode;
}
//前序遍历
public void frontShow() {
//先遍历当前节点的内容
System.out.println(value);
//左节点
if(leftNode!=null) {
leftNode.frontShow();
}
//右节点
if(rightNode!=null) {
rightNode.frontShow();
}
}
//中序遍历
public void midShow() {
//左子节点
if(leftNode!=null) {
leftNode.midShow();
}
//当前节点
System.out.println(value);
//右子节点
if(rightNode!=null) {
rightNode.midShow();
}
}
//后序遍历
public void afterShow() {
//左子节点
if(leftNode!=null) {
leftNode.afterShow();
}
//右子节点
if(rightNode!=null) {
rightNode.afterShow();
}
//当前节点
System.out.println(value);
}
//前序查找
public Node frontSearch(int i) {
Node target=null;
//对比当前节点的值
if(this.value==i) {
return this;
//当前节点的值不是要查找的节点
}else {
//查找左儿子
if(leftNode!=null) {
//有可能可以查到,也可以查不到,查不到的话,target还是一个null
target = leftNode.frontSearch(i);
}
//如果不为空,说明在左儿子中已经找到
if(target!=null) {
return target;
}
//查找右儿子
if(rightNode!=null) {
target=rightNode.frontSearch(i);
}
}
return target;
}
//删除一个子树
public void delete(int i) {
Node parent = this;
//判断左儿子
if(parent.leftNode!=null&&parent.leftNode.value==i) {
parent.leftNode=null;
return;
}
//判断右儿子
if(parent.rightNode!=null&&parent.rightNode.value==i) {
parent.rightNode=null;
return;
}
//递归检查并删除左儿子
parent=leftNode;
if(parent!=null) {
parent.delete(i);
}
//递归检查并删除右儿子
parent=rightNode;
if(parent!=null) {
parent.delete(i);
}
}
}
package demo5;
public class BinaryTree {
Node root;
//设置根节点
public void setRoot(Node root) {
this.root = root;
}
//获取根节点
public Node getRoot() {
return root;
}
public void frontShow() {
if(root!=null) {
root.frontShow();
}
}
public void midShow() {
if(root!=null) {
root.midShow();
}
}
public void afterShow() {
if(root!=null) {
root.afterShow();
}
}
public Node frontSearch(int i) {
return root.frontSearch(i);
}
public void delete(int i) {
if(root.value==i) {
root=null;
}else {
root.delete(i);
}
}
package demo5;
public class TestBinaryTree {
public static void main(String[] args) {
//创建一颗树
BinaryTree binTree = new BinaryTree();
//创建一个根节点
Node root = new Node(1);
//把根节点赋给树
binTree.setRoot(root);
//创建一个左节点
Node rootL = new Node(2);
//把新创建的节点设置为根节点的子节点
root.setLeftNode(rootL);
//创建一个右节点
Node rootR = new Node(3);
//把新创建的节点设置为根节点的子节点
root.setRightNode(rootR);
//为第二层的左节点创建两个子节点
rootL.setLeftNode(new Node(4));
rootL.setRightNode(new Node(5));
//为第二层的右节点创建两个子节点
rootR.setLeftNode(new Node(6));
rootR.setRightNode(new Node(7));
//前序遍历树
binTree.frontShow();
System.out.println("===============");
//中序遍历
binTree.midShow();
System.out.println("===============");
//后序遍历
binTree.afterShow();
System.out.println("===============");
//前序查找
Node result = binTree.frontSearch(5);
System.out.println(result);
System.out.println("===============");
//删除一个子树
binTree.delete(4);
binTree.frontShow();
}
}
遍历二叉树
A:根节点、B:左节点、C:右节点,前序顺序是ABC(根节点排最先,然后同级先左后右);中序顺序是BAC(先左后根最后右);后序顺序是BCA(先左后右最后根)。
- 实例:
二叉树中节点的查找
删除二叉树的子树
顺序存储的二叉树的概述
- 顺序存储二叉树
但其实
顺序存储的二叉树的遍历
package demo6;
public class ArrayBinaryTree {
int[] data;
public ArrayBinaryTree(int[] data) {
this.data=data;
}
public void frontShow() {
frontShow(0);
}
//前序遍历
public void frontShow(int index) {
if(data==null||data.length==0) {
return;
}
//先遍历当前节点的内容
System.out.println(data[index]);
//2*index+1:处理左子树
if(2*index+1<data.length) {
frontShow(2*index+1);
}
//2*index+2:处理右子树
if(2*index+2<data.length) {
frontShow(2*index+2);
}
}
}
package demo6;
public class TestArrayBinaryTree {
public static void main(String[] args) {
int[] data = new int[] {1,2,3,4,5,6,7};
ArrayBinaryTree tree = new ArrayBinaryTree(data);
//前序遍历
tree.frontShow();
}
}
常用排序算法之堆排序
package demo4;
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int[] arr = new int[] {9,6,8,7,0,1,10,4,2};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void heapSort(int[] arr) {
//开始位置是最后一个非叶子节点,即最后一个节点的父节点
int start = (arr.length-1)/2;
//调整为大顶堆
for(int i=start;i>=0;i--) {
maxHeap(arr, arr.length, i);
}
//先把数组中的第0个和堆中的最后一个数交换位置,再把前面的处理为大顶堆
for(int i=arr.length-1;i>0;i--) {
int temp = arr[0];
arr[0]=arr[i];
arr[i]=temp;
maxHeap(arr, i, 0);
}
}
public static void maxHeap(int[] arr,int size,int index) {
//左子节点
int leftNode = 2*index+1;
//右子节点
int rightNode = 2*index+2;
int max = index;
//和两个子节点分别对比,找出最大的节点
if(leftNode<size&&arr[leftNode]>arr[max]) {
max=leftNode;
}
if(rightNode<size&&arr[rightNode]>arr[max]) {
max=rightNode;
}
//交换位置
if(max!=index) {
int temp=arr[index];
arr[index]=arr[max];
arr[max]=temp;
//交换位置以后,可能会破坏之前排好的堆,所以,之前的排好的堆需要重新调整
maxHeap(arr, size, max);
}
}
}
线索二叉树的概述
线索二叉树代码实现
package demo7;
public class ThreadedNode {
//节点的权
int value;
//左儿子
ThreadedNode leftNode;
//右儿子
ThreadedNode rightNode;
//标识指针类型
int leftType;
int rightType;
public ThreadedNode(int value) {
this.value=value;
}
//设置左儿子
public void setLeftNode(ThreadedNode leftNode) {
this.leftNode = leftNode;
}
//设置右儿子
public void setRightNode(ThreadedNode rightNode) {
this.rightNode = rightNode;
}
//前序遍历
public void frontShow() {
//先遍历当前节点的内容
System.out.println(value);
//左节点
if(leftNode!=null) {
leftNode.frontShow();
}
//右节点
if(rightNode!=null) {
rightNode.frontShow();
}
}
//中序遍历
public void midShow() {
//左子节点
if(leftNode!=null) {
leftNode.midShow();
}
//当前节点
System.out.println(value);
//右子节点
if(rightNode!=null) {
rightNode.midShow();
}
}
//后序遍历
public void afterShow() {
//左子节点
if(leftNode!=null) {
leftNode.afterShow();
}
//右子节点
if(rightNode!=null) {
rightNode.afterShow();
}
//当前节点
System.out.println(value);
}
//前序查找
public ThreadedNode frontSearch(int i) {
ThreadedNode target=null;
//对比当前节点的值
if(this.value==i) {
return this;
//当前节点的值不是要查找的节点
}else {
//查找左儿子
if(leftNode!=null) {
//有可能可以查到,也可以查不到,查不到的话,target还是一个null
target = leftNode.frontSearch(i);
}
//如果不为空,说明在左儿子中已经找到
if(target!=null) {
return target;
}
//查找右儿子
if(rightNode!=null) {
target=rightNode.frontSearch(i);
}
}
return target;
}
//删除一个子树
public void delete(int i) {
ThreadedNode parent = this;
//判断左儿子
if(parent.leftNode!=null&&parent.leftNode.value==i) {
parent.leftNode=null;
return;
}
//判断右儿子
if(parent.rightNode!=null&&parent.rightNode.value==i) {
parent.rightNode=null;
return;
}
//递归检查并删除左儿子
parent=leftNode;
if(parent!=null) {
parent.delete(i);
}
//递归检查并删除右儿子
parent=rightNode;
if(parent!=null) {
parent.delete(i);
}
}
}
package demo7;
public class ThreadedBinaryTree {
ThreadedNode root;
//用于临时存储前驱节点
ThreadedNode pre=null;
//遍历线索二叉树
public void threadIterate() {
//用于临时存储当前遍历节点
ThreadedNode node = root;
while(node!=null) {
//循环找到最开始的节点
while(node.leftType==0) {
node=node.leftNode;
}
//打印当前节点的值
System.out.println(node.value);
//如果当前节点的右指针指向的是后继节点,可能后继节点还有后继节点、
while(node.rightType==1) {
node=node.rightNode;
System.out.println(node.value);
}
//替换遍历的节点
node=node.rightNode;
}
}
//设置根节点
public void setRoot(ThreadedNode root) {
this.root = root;
}
//中序线索化二叉树
public void threadNodes() {
threadNodes(root);
}
public void threadNodes(ThreadedNode node) {
//当前节点如果为null,直接返回
if(node==null) {
return;
}
//处理左子树
threadNodes(node.leftNode);
//处理前驱节点
if(node.leftNode==null){
//让当前节点的左指针指向前驱节点
node.leftNode=pre;
//改变当前节点左指针的类型
node.leftType=1;
}
//处理前驱的右指针,如果前驱节点的右指针是null(没有指下右子树)
if(pre!=null&&pre.rightNode==null) {
//让前驱节点的右指针指向当前节点
pre.rightNode=node;
//改变前驱节点的右指针类型
pre.rightType=1;
}
//每处理一个节点,当前节点是下一个节点的前驱节点
pre=node;
//处理右子树
threadNodes(node.rightNode);
}
//获取根节点
public ThreadedNode getRoot() {
return root;
}
//前序遍历
public void frontShow() {
if(root!=null) {
root.frontShow();
}
}
//中序遍历
public void midShow() {
if(root!=null) {
root.midShow();
}
}
//后序遍历
public void afterShow() {
if(root!=null) {
root.afterShow();
}
}
//前序查找
public ThreadedNode frontSearch(int i) {
return root.frontSearch(i);
}
//删除子树
public void delete(int i) {
if(root.value==i) {
root=null;
}else {
root.delete(i);
}
}
}
package demo7;
public class TestThreadedBinaryTree {
public static void main(String[] args) {
//创建一颗树
ThreadedBinaryTree binTree = new ThreadedBinaryTree();
//创建一个根节点
ThreadedNode root = new ThreadedNode(1);
//把根节点赋给树
binTree.setRoot(root);
//创建一个左节点
ThreadedNode rootL = new ThreadedNode(2);
//把新创建的节点设置为根节点的子节点
root.setLeftNode(rootL);
//创建一个右节点
ThreadedNode rootR = new ThreadedNode(3);
//把新创建的节点设置为根节点的子节点
root.setRightNode(rootR);
//为第二层的左节点创建两个子节点
rootL.setLeftNode(new ThreadedNode(4));
ThreadedNode fiveNode = new ThreadedNode(5);
rootL.setRightNode(fiveNode);
//为第二层的右节点创建两个子节点
rootR.setLeftNode(new ThreadedNode(6));
rootR.setRightNode(new ThreadedNode(7));
//中序遍历树
binTree.midShow();
System.out.println("===============");
//中前线索化二叉树
binTree.threadNodes();
binTree.threadIterate();
}
}