二叉树与二叉平衡树

树
简单介绍一下树
度
树的度:找到分支最多的节点,这个节点有多少分支,这棵树的度就为几。
分支最多的节点为D,它有三个分支
这棵树的度为3
深度
树的深度就是树的层数
深度为4
根节点与叶子节点
叶子节点:没有子节点的节点
这棵树的根节点是A
叶子节点为E,F,G,H
二叉树
树的度最高不超过2的树,称为二叉树
满二叉树
如果一个节点有子节点,那么他一定有两个节点并且叶子节点都在树的最后一层
完全二叉树
除了最后一层节点是满的,最后一层的节点都集中在左侧
满二叉树是完全二叉树
二叉树的遍历
前序遍历:先根次序遍历
根左右
先打根节点,再打左子树,再打右子树
1,2,4,5,3,6
中序遍历:中跟次序遍历
左根右
先打印左子树,在打印根节点在打印右子树
4,2,5,1,3,6
后序遍历:后根次序遍历
左右根
先打印左子树,在打印右子树,在打印根节点
4,5,2,6,3,1
以下是代码实现
public static void firstRoot(TreeNode root){
if (root == null)return;
System.out.println(root.val);
firstRoot(root.left);
firstRoot(root.right);
}
public static void midRoot(TreeNode root){
if (root == null)return;
midRoot(root.left);
System.out.println(root.val);
midRoot(root.right);
}
public static void lastRoot(TreeNode root){
if (root == null)return;
lastRoot(root.left);
lastRoot(root.right);
System.out.println(root.val);
}
建立一个二叉树
通过前序和中序建立一个二叉树。
给我们一个前序遍历和中序遍历我们来建立二叉树,首先我们要先找根节点,通过根节点再找到它的左子树和右子树,最后建立二叉树。
以下是代码实现
private static int getIndex(int[] arr , int target){
for (int i = 0 ; i <arr.length ; i++){
if (arr[i] == target)return i;
}
return 0;
}
public static TreeNode buildTree(int[] first,int[] mid){
if (first == null || mid == null || first.length == 0 || mid.length == 0 || first.length != mid.length) return null;
//从前序遍历中找到根节点
TreeNode root = new TreeNode(first[0]);
//在中序遍历中找到根节点位置的索引
int rootIndex = getIndex(mid,root.val);
//找到左子树的前序和中序
int[] leftMid = Arrays.copyOfRange(mid,0,rootIndex);
int[] leftFirst = Arrays.copyOfRange(first,1,rootIndex + 1);
//找到右子树的前序和中序
int[] rightMid = Arrays.copyOfRange(mid,rootIndex-1,mid.length);
int[] rightFirst = Arrays.copyOfRange(first,rootIndex + 1,first.length);
//递归构建左右子树
TreeNode left = buildTree(leftFirst,leftMid);
TreeNode right = buildTree(rightFirst,rightMid);
//将左右子数添加到当前的根节点
root.left = left;
root.right = right;
return root;
}
通过后序和中序建立二叉树的做法与前序和中序建立差不多,后序的根结点是在最后一个。
二叉树的广度和深度优先搜索
深度优先搜索
public static boolean dfs(TreeNode root,int target){
if (root == null)return false;
if (root.val == target)return true;
return dfs(root.left,target) || dfs(root.right,target);
}
广度优先搜索
public static boolean bfs(ArrayList<TreeNode> roots,int target){
if (roots == null || roots.size() == 0)return false;
ArrayList<TreeNode> childRoots = new ArrayList<>();
for (TreeNode temp : roots){
if (temp.val == target)return true;
if (temp.left != null)childRoots.add(temp.left);
if (temp.right != null)childRoots.add(temp.right);
}
return bfs(childRoots,target);
}
public static boolean bfs(TreeNode root,int target){
ArrayList<TreeNode> roots = new ArrayList<>();
roots.add(root);
return bfs(roots,target);
}
二叉树的比较
比较两个二叉树是否相等
public static boolean compareTree(TreeNode root1,TreeNode root2){
if (root1 == null && root2 != null || root1 != null && root2 == null)return false;
if (root1 == null && root2 == null)return true;
if (root1.val != root2.val)return false;
return compareTree(root1.left,root2.left) && compareTree(root1.right,root2.right);
}
如果左右子树互换
public static boolean compareTree2(TreeNode root1,TreeNode root2){
if (root1 == null && root2 != null || root1 != null && root2 == null)return false;
if (root1 == null && root2 == null)return true;
if (root1.val != root2.val)return false;
return compareTree(root1.left,root2.left) && compareTree(root1.right,root2.right)
|| compareTree(root1.left,root2.right) && compareTree(root1.right,root2.left);
}
普利姆算法
我们要将所有点连通,并且让他们之间的距离最小
我们首先
1.任选一个点作为起点
2.找到与已连接部分路径最短的的点。
3.不能形成回路
如何用程序表示一个图
1.点集合
set集合 Set
2.边集合
二维数组· int[][] distance
准备工作
public class MapNode {
public int val;
public int index;
public List<MapNode> neighbor;
public MapNode(int val,int index){
this.val = val;
this.index = index;
neighbor = new ArrayList<>();
}
}
普利姆算法具体实现
public static MapNode getMapNodeByIndex(Set<MapNode> pointSet,int index){
for (MapNode node : pointSet){
if (node.index == index )return node;
}
return null;
}
public static void getMinDis(Set<MapNode> pointSet,int[][] distance,Set<MapNode> linkedPoint){
MapNode start = null;
MapNode end = null;
int minDis = Integer.MAX_VALUE;
//找到距离已有的点最近的点
for (MapNode myPoint : pointSet){
for (int i = 0 ; i < distance[myPoint.index].length ; i++){
if (distance[myPoint.index][i] < minDis//找到比最小距离要小的点
&& myPoint.index != i//除去自己到自己的距离
&& !linkedPoint.contains(getMapNodeByIndex(pointSet,i))){
//已连接的点不能有序号为i的点
start = myPoint;
end = getMapNodeByIndex(pointSet,i);
minDis = distance[myPoint.index][i];
}
}
}
//将距离最近的点连接在一起
start.neighbor.add(end);
end.neighbor.add(start);
linkedPoint.add(end);
}
public static void prim(Set<MapNode> pointSet,int[][] distance,MapNode begin){
Set<MapNode> linkedPoint = new HashSet<>();
linkedPoint.add(begin);
while(linkedPoint.size() < pointSet.size()){
getMinDis(pointSet,distance,linkedPoint);
}
}
克鲁斯卡尔算法
克鲁斯卡尔算法也叫加边法
1.找到最短的边
2.边不能重复
3.边的两个点不能出自同一连通区域(不能形成环)
以下是代码实现
public static List<MapNode> getMapNodeList( List<List<MapNode>> linkedMapNode, MapNode node){
for (List<MapNode> mapNodes : linkedMapNode){
if (mapNodes.contains(node))return mapNodes;
}
return null;
}
public static void getMinDis(Set<MapNode> pointSet,int[][] distance, List<List<MapNode>> linkedMapNode){
//找到最短的边
int minDis = Integer.MAX_VALUE;
MapNode begin = null;
MapNode end = null;
List<MapNode> beginList = null;
List<MapNode> endList = null;
for (int i = 0 ; i < distance.length ; i++){
for (int j = 0 ; j < distance[i].length ; j++){
if (distance[i][j] < minDis && i != j){
MapNode a = getMapNodeByIndex(pointSet,i);
MapNode b = getMapNodeByIndex(pointSet,j);
List<MapNode> alist = getMapNodeList(linkedMapNode,a);
List<MapNode> blist = getMapNodeList(linkedMapNode,b);
if (alist != null && blist != null && alist == blist){
//判断是否出自同一部落
minDis = distance[i][j];
begin = a;
end = a;
beginList = alist;
endList = blist;
}
}
}
}
begin.neighbor.add(end);
end.neighbor.add(begin);
//看看这两个部落是否需要合并
if (beginList == null && endList == null){
//两个都是新的点
List<MapNode> mapNodes = new ArrayList<>();
mapNodes.add(begin);
mapNodes.add(end);
linkedMapNode.add(mapNodes);
}else if (beginList != null && endList == null){
//两个点其中一个是新的
beginList.add(end);
}else if (endList != null && beginList == null){
endList.add(begin);
}else if (beginList != null && endList != null){
beginList.addAll(endList);
linkedMapNode.remove(endList);
}
//判断这个边能不能连接
//1.两个点都是新的
//2.两个点其中一个是新的(其中一个点没有部落)
//3.两个点出自不同的连通区域(两个点来自不同的部落)
//同以上三点等效 ==== 两个点不能出自同一个部落
}
public static void kruskar(Set<MapNode> pointSet,int[][] distance){
List<List<MapNode>> linkedMapNode = new ArrayList<>();//部落的集合
while (linkedMapNode.size() == 1 && linkedMapNode.get(0).size() == pointSet.size()){
//只能有一个部落,并且唯一的一个部落大小是和所有的点的集合大小一样
getMinDis(pointSet,distance,linkedMapNode);
}
}