树的介绍及对应操作(基础篇)
基本概念
树是一种抽象的数据类型,用来模拟具有树状结构性质的数据集合。它是由n(n >= 0)个有限节点通过连接它们的边组成一个具有层次关系的集 合。n = 0时称为空树;n > 0时,有且仅有一个节点被称为根节点(Root),如果n = 1,树只有根节点一个节点。
树的特点是层次结构,根节点在最上层,叶节点在最下层。每个节点都有一个子树,每个子树又是一个新的节点。节点的度是指其拥有的子树数量。
树的种类有二叉树、平衡二叉树、红黑树、AVL树、B树、B+树、Trie树等。它们分别具有不同的性质和用途,如二叉树每个节点最多有两个子节点,平衡二叉树保持树的平衡以提高查找效率,红黑树是一种自平衡的二叉查找树等。
总之,树是一种重要的数据结构,它可以用来组织和管理数据,还可以实现各种算法操作。
操作
先序·中序·后序遍历(递归)
按层遍历
判断相等树
判断镜面树
二叉树的最大深度
用先序数组和中序数组重建一棵树
二叉树按层遍历搜集节点
判断平衡二叉树
判断搜索二叉树
判断完全二叉树
判断满二叉树
能否组成路径和
搜集达标路径和
二叉树序列化和反序列化
n叉树序列化和反序列化
求最大距离
求树的最大宽度
返回该节点的后继节点
先序·中序·后序遍历(递归)
public static void Traver(Node head){
if(head == null){
return;
}
System.out.print(head.val + " ");//先序
Traver(head.left);
//中序
Traver(head.right);
//后序
}
按层遍历
public static void levelTraver(Node head){
if(head == null){
return;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
while (!queue.isEmpty()){
Node cur = queue.poll();
System.out.print(cur.val+" ");
if(cur.left != null){
queue.add(cur.left);
}
if(cur.right != null){
queue.add(cur.right);
}
}
}
判断相等树
public static boolean isSameTree(Node n1,Node n2){
if(n1 == null ^ n2 == null){
return false;
}
if(n1 == null && n2 == null){
return true;
}
return n1.val == n2.val && isSameTree(n1.left,n2.left) && isSameTree(n1.right,n2.right);
}
判断镜面树
public static boolean isMirror(Node head){
if(head == null){
return true;
}
return isMirrorMethod(head.left,head.right);
}
public static boolean isMirrorMethod(Node n1,Node n2){
if(n1 == null ^ n2 == null){
return false;
}
if(n1 == null && n2 == null){
return true;
}
return n1.val == n2.val && isSameTree(n1.left,n2.right) && isSameTree(n1.right,n2.left);
}
二叉树的最大深度
public static int MaxDepth(Node head){
if(head == null){
return 0;
}
return Math.max(MaxDepth(head.left),
MaxDepth(head.right)) + 1;
}
用先序数组和中序数组重建一棵树
public static TreeNode buildTree2(int[] pre, int[] in) {
if (pre == null || in == null || pre.length != in.length) {
return null;
}
HashMap<Integer,Integer> valueIndexMap = new HashMap<>();
for (int i = 0; i < in.length; i++) {
valueIndexMap.put(in[i],i);
}
return f2(pre, 0, pre.length - 1, in, 0, in.length - 1,valueIndexMap);
}
public static TreeNode f2(int[] pre, int L1, int R1, int[] in, int L2, int R2, HashMap<Integer,Integer> valueIndexMap) {
if (L1 > R1) {
return null;
}
TreeNode head = new TreeNode(pre[L1]);
if (L1 == R1) {
return head;
}
int find = valueIndexMap.get(pre[L1]);
head.left = f2(pre, L1+1, L1 + find-L2, in, L2, find - 1,valueIndexMap);
head.right = f2(pre, L1 + find-L2 + 1, R1, in, find + 1, R2,valueIndexMap);
return head;
}
二叉树按层遍历搜集节点
public static List<List<Integer>> levelOrderBottom(TreeNode root){
List<List<Integer>> ans = new LinkedList<>();
if(root == null){
return ans;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()){
int size = queue.size();
List<Integer> curAns = new LinkedList<>();
for (int i = 0; i < size; i++) {
TreeNode curNode = queue.poll();
curAns.add(curNode.val);
if(curNode.left != null){
queue.add(curNode.left);
}
if(curNode.right != null){
queue.add(curNode.right);
}
}
ans.add(0,curAns);
}
return ans;
}
判断平衡二叉树
public static boolean isBalancedTree(TreeNode root){
return process(root).isBalanced;
}
public static class Info{
public boolean isBalanced;
public int height;
public Info(boolean isBalanced, int height) {
this.isBalanced = isBalanced;
this.height = height;
}
}
public static Info process(TreeNode x){
if(x == null){
return new Info(true,0);
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int height = Math.max(leftInfo.height,rightInfo.height) + 1;
boolean isBalanced = leftInfo.isBalanced && rightInfo.isBalanced
&& Math.abs(leftInfo.height- rightInfo.height) < 2;
return new Info(isBalanced,height);
}
判断搜索二叉树
两种方法:
(1)中序遍历数组是严格递增的,是搜索二叉树
(2)递归
public static class Info {
public boolean isBST;
public int max;
public int min;
public Info(boolean isBST, int max, int min) {
this.isBST = isBST;
this.max = max;
this.min = min;
}
}
public static Info process(TreeNode x) {
if (x == null) {
return null;
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int max = x.val;
int min = x.val;
if (leftInfo != null) {
max = Math.max(leftInfo.max, max);
min = Math.min(leftInfo.min, min);
}
if (rightInfo != null) {
max = Math.max(rightInfo.max, max);
min = Math.min(rightInfo.min, min);
}
boolean isBST = true;
if (leftInfo != null && !leftInfo.isBST) {
isBST = false;
}
if (rightInfo != null && !rightInfo.isBST) {
isBST = false;
}
boolean leftMaxLessX = leftInfo == null ? true : (leftInfo.max < x.val);
boolean rightMinMoreX = rightInfo == null ? true : (rightInfo.min > x.val);
if (!leftMaxLessX || !rightMinMoreX) {
isBST = false;
}
return new Info(isBST, max, min);
}
判断完全二叉树
public static boolean isCBT1(Node head){
if(head == null){
return true;
}
LinkedList<Node> queue = new LinkedList<>();
boolean leaf = false;
Node l = null;
Node r = null;
queue.add(head);
while (!queue.isEmpty()){
head = queue.poll();
l = head.left;
r = head.right;
if (
(leaf && (l != null) || (r != null))
||
(l == null && r !=null)
){
return false;
}
if(l != null){
queue.add(l);
}
if(r != null){
queue.add(r);
}
if(l == null && r == null){
leaf = true;
}
}
return true;
}
判断满二叉树
public static boolean isFBT(Node head){
if(head == null) {
return true;
}
Info all = process(head);
return (1 << all.height) - 1 == all.nodes;
}
public static class Info{
public int height;
public int nodes;
public Info(int height, int nodes) {
this.height = height;
this.nodes = nodes;
}
}
public static Info process(Node head){
if(head == null){
return new Info(0,0);
}
Info leftInfo = process(head.left);
Info rightInfo = process(head.right);
int height = Math.max(leftInfo.height,rightInfo.height) + 1;
int nodes = leftInfo.nodes + rightInfo.nodes + 1;
return new Info(height,nodes);
}
能否组成路径和
public static boolean isSum = false;
public static boolean hasPathSum(TreeNode root,int sum){
if(root == null){
return false;
}
isSum = false;
process(root,0,sum);
return isSum;
}
public static void process(TreeNode x,int preSum,int sum){
if(x.left == null && x.right == null){
if(x.val + preSum == sum){
isSum = true;
}
return;
}
//非叶节点
preSum += x.val;
if(x.left != null){
process(x.left,preSum,sum);
}
if(x.right != null){
process(x.right,preSum,sum);
}
}
搜集达标路径和
public static List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> ans = new ArrayList<>();
if (root == null) {
return ans;
}
ArrayList<Integer> path = new ArrayList<>();
process(root,path,0,sum,ans);
return ans;
}
public static void process(TreeNode x, List<Integer> path, int preSum, int sum,
List<List<Integer>> ans) {
if (x.left == null && x.right == null) {
if (preSum + x.val == sum) {
path.add(x.val);
ans.add(copy(path));
path.remove(path.size() - 1);
}
return;
}
//x是非叶节点
path.add(x.val);
preSum += x.val;
if(x.left != null){
process(x.left,path,preSum,sum,ans);
}
if(x.right != null){
process(x.right,path,preSum,sum,ans);
}
path.remove(path.size() - 1);
}
public static List<Integer> copy(List<Integer> path) {
List<Integer> ans = new ArrayList<>();
for (Integer num : path) {
ans.add(num);
}
return ans;
}
二叉树序列化和反序列化
前序
public static Queue<String> preSerial(Node head){
Queue<String> ans = new LinkedList<>();
pres(head,ans);
return ans;
}
public static void pres(Node head,Queue<String> ans){
if(head == null){
ans.add(null);
}else {
ans.add(String.valueOf(head.value));
pres(head.left, ans);
pres(head.right, ans);
}
}
public static Node buildByPreQueue(Queue<String> preList){
if(preList == null || preList.size() == 0){
return null;
}
return preb(preList);
}
public static Node preb(Queue<String> preList){
String value = preList.poll();
if(value == null){
return null;
}
Node head = new Node(Integer.valueOf(value));
head.left = preb(preList);
head.right = preb(preList);
return head;
}
按层
public static Queue<String> levelSerial(Node head){
Queue<String> ans = new LinkedList<>();
if(head == null){
ans.add(null);
}else {
ans.add(String.valueOf(head.value));
Queue<Node> queue = new LinkedList<>();
queue.add(head);
while (!queue.isEmpty()){
head = queue.poll();
if(head.left != null){
ans.add(String.valueOf(head.left.value));
queue.add(head.left);
}else {
ans.add(null);
}
if(head.right != null){
ans.add(String.valueOf(head.right.value));
queue.add(head.right);
}else {
ans.add(null);
}
}
}
return ans;
}
public static Node buildByLevelQueue(Queue<String> levelList){
if(levelList == null || levelList.size() == 0){
return null;
}
Node head = generateNode(levelList.poll());
Queue<Node> queue = new LinkedList<>();
if(head != null){
queue.add(head);
}
Node node = null;
while (!queue.isEmpty()){
node = queue.poll();
node.left = generateNode(levelList.poll());
node.right = generateNode(levelList.poll());
if(node.left != null){
queue.add(node.left);
}
if(node.right != null){
queue.add(node.right);
}
}
return head;
}
public static Node generateNode(String val){
if(val == null){
return null;
}
return new Node(Integer.valueOf(val));
}
n叉树序列化和反序列化
public static class Node {
public int val;
public List<Node> children;
public Node() {
}
public Node(int val) {
this.val = val;
}
public Node(int val, List<Node> children) {
this.val = val;
this.children = children;
}
}
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
}
}
class Codec{
public TreeNode encode(Node root){
if(root == null){
return null;
}
TreeNode head = new TreeNode(root.val);
head.left = en(root.children);
return head;
}
public TreeNode en(List<Node> children){
TreeNode head = null;
TreeNode cur = null;
for (Node child : children) {
TreeNode tNode = new TreeNode(child.val);
if(head == null){
head = tNode;
}else {
cur.right = tNode;
}
cur = tNode;
cur.left = en(child.children);
}
return head;
}
public Node decode(TreeNode root){
if(root == null){
return null;
}
return new Node(root.val,de(root.left));
}
public List<Node> de(TreeNode root){
List<Node> children = new ArrayList<>();
while (root != null){
Node cur = new Node(root.val,de(root.left));
children.add(cur);
root = root.right;
}
return children;
}
}
求最大距离
public static int maxDistance1(Node head){
return process(head).maxDistance;
}
public static class Info{
public int maxDistance;
public int height;
public Info(int maxDistance, int height) {
this.maxDistance = maxDistance;
this.height = height;
}
}
public static Info process(Node x){
if (x == null){
return new Info(0,0);
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int height = Math.max(leftInfo.height,rightInfo.height) + 1;
int p1 = leftInfo.maxDistance;
int p2 = rightInfo.maxDistance;
int p3 = leftInfo.height + rightInfo.height + 1;
int maxDistance = Math.max(Math.max(p1,p2),p3);
return new Info(maxDistance,height);
}
求树的最大宽度
public static int maxWidthUseMap(Node head){
if(head == null){
return 0;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
Node curEnd = head;
Node nextEnd = null;
int max = 0;
int curLevelNodes = 0;
while (!queue.isEmpty()){
Node cur = queue.poll();
if (cur.left != null){
queue.add(cur.left);
nextEnd = cur.left;
}
if(cur.right != null){
queue.add(cur.right);
nextEnd = cur.right;
}
curLevelNodes++;
if(cur == curEnd){
max = Math.max(max,curLevelNodes);
curLevelNodes = 0;
curEnd = nextEnd;
}
}
return max;
}
返回该节点的后继节点
public static class Node{
public int value;
public Node left;
public Node right;
public Node parent;
public Node(int value) {
this.value = value;
}
}
public static Node getSuccessorNode(Node node){
if(node == null){
return node;
}
if(node.right != null){
return getLeftMost(node.right);
}else {
Node parent = node.parent;
while (parent != null && parent.right == node){
node = parent;
parent = node.parent;
}
return parent;
}
}
public static Node getLeftMost(Node node){
if(node == null){
return node;
}
while (node.left != null){
node = node.left;
}
return node;
}