二叉树 的基本操作
二叉树定义
详见我的上一篇博客:
初识二叉树
结点的定义:
结点的定义 有数值域,还有左孩子的引用和右孩子的引用,分别表示以左右孩子为根的左子树和右子树
public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int val) {
this.val = val;
this.left = null;
this.right = null;
}
@Override
public String toString() {
return String.format("TreeNode{%c}", val);
}
}
构建二叉树
我们先进行构建两棵二叉树,方便验证下面操作是否正确:
public class buildTree {
public static TreeNode buildTree1() {
// 让大家练习前中后序的树
TreeNode a = new TreeNode('a');
TreeNode b = new TreeNode('b');
TreeNode c = new TreeNode('c');
TreeNode d = new TreeNode('d');
TreeNode e = new TreeNode('e');
TreeNode f = new TreeNode('f');
TreeNode g = new TreeNode('g');
TreeNode h = new TreeNode('h');
TreeNode i = new TreeNode('i');
TreeNode j = new TreeNode('j');
TreeNode k = new TreeNode('k');
TreeNode l = new TreeNode('l');
TreeNode m = new TreeNode('m');
TreeNode n = new TreeNode('n');
a.left = b; a.right = c;
b.left = d; b.right = e;
c.left = f; c.right = g;
d.right = h;
f.left = i; f.right = j;
g.right = k;
h.right = l;
j.left = m;
m.left = n;
return a;
}
public static TreeNode buildTree2() {
// 构建课件上的树
TreeNode a = new TreeNode('a');
TreeNode b = new TreeNode('b');
TreeNode c = new TreeNode('c');
TreeNode d = new TreeNode('d');
TreeNode e = new TreeNode('e');
TreeNode f = new TreeNode('f');
TreeNode g = new TreeNode('g');
TreeNode h = new TreeNode('h');
a.left = b; a.right = c;
b.left = d; b.right = e;
c.left = f; c.right = g;
e.right = h;
return a;
}
}
前、中、后序遍历
前、中、后序遍历主要就是头结点什么时候处理,我们可以利用递归的思想,简便的求解。
//前序遍历
public static void preOrderTraversal(TreeNode root) {
if (root == null) {
return;
}
System.out.printf("%c ",root.val);
preOrderTraversal(root.left);
preOrderTraversal(root.right);
}
//中序遍历
public static void inOrderTraversal(TreeNode root) {
if (root == null) {
return;
}
inOrderTraversal(root.left);
System.out.printf("%c ",root.val);
inOrderTraversal(root.right);
}
//后序遍历
public static void posteOrderTraversal(TreeNode root) {
if (root == null) {
return;
}
posteOrderTraversal(root.left);
posteOrderTraversal(root.right);
System.out.printf("%c ",root.val);
}
测试:
public static void main(String[] args) {
TreeNode root1 = buildTree.buildTree1();
TreeNode root2 = buildTree.buildTree2();
preOrderTraversal(root1);
System.out.println();
inOrderTraversal(root1);
System.out.println();
posteOrderTraversal(root1);
System.out.println();
System.out.println("================================");
preOrderTraversal(root2);
System.out.println();
inOrderTraversal(root2);
System.out.println();
posteOrderTraversal(root2);
}
遍历求结点的个数
我们可以采用遍历的思想求出结点个数,需要定义一个size,记录节点个数
//遍历求结点的个数
static int size = 0;
public static void getSize1(TreeNode root) {
if (root == null) {
return;
}
size++;
getSize1(root.left);
getSize1(root.right);
}
测试
//测试求解节点数
public static void main(String[] args) {
TreeNode root1 = buildTree.buildTree1();
TreeNode root2 = buildTree.buildTree2();
getSize1(root1);
System.out.println(size);
getSize1(root2);
System.out.println(size);
System.out.println("===========");
size=0;
getSize1(root1);
System.out.println(size);
size=0;
getSize1(root2);
System.out.println(size);
}
我们会发现,结果出错?因为我们定义的size经过每个结点都会+1,但是不能清0,所以我们调用这个方法时,一定要将size=0;
汇集思想求结点的个数
我们发现每个都是左子树+右子树+头结点,我们可以递归求解
// 汇集思想求结点的个数
public static int getSize2(TreeNode root) {
if (root == null) {
return 0;
}
int left = getSize2(root.left);
int right = getSize2(root.right);
return left + right + 1;
}
测试
public static void main(String[] args) {
TreeNode root1 = buildTree.buildTree1();
TreeNode root2 = buildTree.buildTree2();
System.out.println(getSize2(root1));
System.out.println(getSize2(root2));
}
遍历求叶子结点的个数
我们可以采用遍历的思想求出结点个数,需要定义一个leftSize,当结点左右子树都为null时,记录节点个数
当然我们调用的时候也需要将leafSize=0;
// 遍历求叶子结点的个数
static int leafSize = 0;
public static void getLeafSize1(TreeNode root) {
if (root == null) {
return;
}
if (root.left == null && root.right == null) {
leafSize++;
}
getLeafSize1(root.left);
getLeafSize1(root.right);
}
测试
//求解叶子结点个数
public static void main(String[] args) {
TreeNode root1 = buildTree.buildTree1();
TreeNode root2 = buildTree.buildTree2();
getLeafSize1(root1);
System.out.println(leafSize);
leafSize = 0;
getLeafSize1(root2);
System.out.println(leafSize);
}
汇集思想求叶子结点的个数
我们发现叶子结点是左子树 为 null 和 右子树 为 null ,我们可以递归求解
// 汇集思想求叶子结点的个数
public static int getLeafSize2(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) {
return 1;
}
int left = getLeafSize2(root.left);
int right = getLeafSize2(root.right);
return left + right;
}
测试:
//求解叶子结点个数
public static void main(String[] args) {
TreeNode root1 = buildTree.buildTree1();
TreeNode root2 = buildTree.buildTree2();
System.out.println(getLeafSize2(root1));
System.out.println(getLeafSize2(root2));
}
求第k层结点个数
递归求解:
// 求第k层结点个数
public static int getLeavelSize(TreeNode root, int k) {
if (root == null) {
return 0;
}
if (k == 1) {
return 1;
}
int left = getLeavelSize(root.left, k - 1);
int right = getLeavelSize(root.right, k - 1);
return left + right;
}
测试:
//求解二叉树第k层有几个结点
public static void main(String[] args) {
TreeNode root1 = buildTree.buildTree1();
TreeNode root2 = buildTree.buildTree2();
System.out.println(getLeavelSize(root1,2));
System.out.println(getLeavelSize(root1,4));
System.out.println(getLeavelSize(root2,1));
System.out.println(getLeavelSize(root2,3));
System.out.println(getLeavelSize(root2,4));
}
求二叉树的高度
左子树和右子树中较大的为二叉树高度:
// 求二叉树的高度
public static int getHeight(TreeNode root) {
if (root == null) {
return 0;
}
int left = getHeight(root.left);
int right = getHeight(root.right);
return Integer.max(left, right) + 1;
}
测试:
//二叉树高度
public static void main(String[] args) {
TreeNode root1 = buildTree.buildTree1();
TreeNode root2 = buildTree.buildTree2();
System.out.println(getHeight(root1));
System.out.println(getHeight(root2));
}
是否存在结点为e的结点
//是否存在结点为e的结点
public static boolean contains(TreeNode root, int e) {
if (root == null) {
return false;
}
if (root.val == e) {
return true;
}
if (contains(root.left, e)) {
return true;
}
return contains(root.right, e);
}
//是否存在结点为e的结点
public static void main(String[] args) {
TreeNode root1 = buildTree.buildTree1();
TreeNode root2 = buildTree.buildTree2();
System.out.println(contains(root1,'1'));
System.out.println(contains(root1,'c'));
System.out.println(contains(root1,'z'));
}
是否存在结点为e的结点,返回其结点位置
//是否存在结点为e的结点,返回其结点位置
public static TreeNode nodeOf(TreeNode root, int e) {
if (root == null) {
return null;
}
if (root.val == e) {
return root;
}
TreeNode r = nodeOf(root.left, e);
if (r != null) {
return r;
}
return nodeOf(root.right, e);
}
//是否存在结点为e的结点,返回其结点位置
public static void main(String[] args) {
TreeNode root1 = buildTree.buildTree1();
System.out.println(nodeOf(root1,'1'));
System.out.println(nodeOf(root1,'c'));
System.out.println(nodeOf(root1,'e'));
}
判断 node 在不在以 root 为根的树中,node 一定不是 null
public static boolean containsNode(TreeNode root, TreeNode node) {
if (root == null) {
return false;
}
if (root == node) {
return true;
}
boolean r = containsNode(root.left, node);
if (r) {
return true;
}
return containsNode(root.right, node);
}
// 判断 node 在不在以 root 为根的树中,node 一定不是 null
public static void main(String[] args) {
TreeNode root1 = buildTree.buildTree1();
TreeNode root2 = buildTree.buildTree2();
TreeNode node1 = new TreeNode('a');
System.out.println(containsNode(root1, root1));
System.out.println(containsNode(root1, root2));
System.out.println(containsNode(root1, node1));
System.out.println(containsNode(root2, node1));
System.out.println(containsNode(node1, node1));
}