文章目录
1.树的结构及基本概念
1.1结构
树是一种非线性的数据结构,树的子树之间不能交叉
1.2基本概念
结点的度:一个结点含有子树的个数,如:A的度为6
树的度:所有结点的度的最大值,例如:该树的度为6
叶子结点(终端节点):度为0的结点,例如:B,C,H,I,P
双亲结点(父节点):若一个结点含有子节点,则这个结点称这个子节点的父亲结点,例如:A是B的父亲结点
孩子结点(子结点):父亲结点的子结点,例如:B是A的孩子结点
根节点:没有双亲结点的结点,例如:A是该树的根结点
树的高度(深度):树中结点的最大层次,例如:该树的深度为4
森林:有n棵互不相交的树组成的集合
1.3树的表示形式
树的表示形式有:双亲表示法,孩子表示法,孩子双亲表示法,孩子兄弟表示法,下图展示的是孩子兄弟表示法
2.二叉树
2.1概念
二叉树是空树或者有一个根结点加上两棵称为左子树、右子树的二叉树的有限集合
2.2三种特殊的二叉树
(1)完全二叉树:一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同
(2)满二叉树:每层结点数都达到最大值的二叉树,就是一棵二叉树的层数为K,且结点总数为2^K-1就为满二叉树,满二叉树是一种特殊的完全二叉树
(3)二叉搜索树:也成为二叉排序树,其左子树均小于根结点的值,右子树均大于根结点的值
2.3二叉树的性质
(1)二叉树中不存在度大于2的结点
(2)二叉树的子树有左右之分,次序不能颠倒,是有序树
(3)若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个节点
(4)若规定只有根结点的二叉树的深度为1,则深度为k的二叉树的结点总数为2^k-1
(5)对任何一棵二叉树,如果叶子结点的个数为n0,度为2的非叶子结点的个数为n2,度为1的结点个数为n1,则n0=n2+1,结点总数 = n0+n1+n2
(6)具有n个结点的完全二叉树的深度为log(n+1)向上取整
(7)对于完全二叉树:已知孩子结点下标为i,则其父亲结点下标为(i-1)/2 ;已知父亲结点下标为j,则其左孩子结点下标为2j+1,右孩子结点下标为2j+2
2.4二叉树的存储
(1)顺序存储
(2)链式存储:通过一个一个的结点引用起来的,常见的表示方法有孩子表示法和孩子双亲表示法
// 孩子表示法(最常用)
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}
// 孩子双亲表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
Node parent; // 当前节点的根节点
}
2.5二叉树的手动创建
public class TestBinaryTree {
public class TreeNode{
public char val;
public TreeNode left;
public TreeNode right;
//构造方法
public TreeNode(char val){
this.val = val;
}
}
public TreeNode crateTree(){
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;
E.right = H;
C.left = F;
C.right = G;
return A;//返回根节点
}
2.6二叉树的遍历
(1)前序遍历
遍历顺序:根结点->左子树->右子树
遍历结果:ABDCEF
//遍历思路
public List<Integer> preorderTraversal1(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null){
return list;
}
return preorderTraversal1Child(root,list);
}
private List<Integer> preorderTraversal1Child(TreeNode root,List<Integer> list){
if(root == null){
return null;
}
list.add(root.val);
preorderTraversal1Child(root.left,list);
preorderTraversal1Child(root.right,list);
return list;
}
//子问题思路
public List<Integer> preorderTraversal2(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null){
return list;
}
list.add(root.val);
List<Integer> leftList = preorderTraversal2(root.left);
list.addAll(leftList);
List<Integer> rightList = preorderTraversal2(root.right);
list.addAll(rightList);
return list;
}
//非递归实现
public List<Integer> preorderTraversal3(TreeNode root){
List<Integer> ret = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur!=null || !stack.empty()){
while(cur != null){
stack.push(cur);
ret.add(cur.val);
cur = cur.left;
}
TreeNode top = stack.pop();
cur = top.right;
}
return ret;
}
(2)中序遍历
遍历顺序:左子树->根结点->右子树
遍历结果:DBAECF
//中序遍历
public void inOrder(TreeNode root){
if (root == null){
return;
}
inOrder(root.left);
System.out.print(root.val+" ");
inOrder(root.right);
}
//非递归实现
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ret = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur!=null||!stack.empty()){
while(cur!=null){
stack.push(cur);
cur = cur.left;
}
TreeNode top = stack.pop();
ret.add(top.val);
cur = top.right;
}
return ret;
}
(3)后序遍历
遍历顺序:左子树->右子树->根结点
遍历结果:DBEFCA
//后序遍历
public void postOrder(TreeNode root){
if (root == null){
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val+" ");
}
//非递归实现
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ret = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
TreeNode tmp = null;
while(cur != null || !stack.empty()){
while(cur != null){
stack.push(cur);
cur = cur.left;
}
TreeNode top = stack.peek();
if(top.right == null || top.right == tmp){
ret.add(top.val);
stack.pop();
tmp = top;
}else{
cur = top.right;
}
}
return ret;
}
(4)层序遍历
遍历结果:ABCDEF
public void leaveOrder(TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();
if (root != null){
queue.offer(root);
}
while (!queue.isEmpty()){
TreeNode cur = queue.poll();
System.out.print(cur.val+" ");
if (cur.left != null){
queue.offer(cur.left);
}
if (cur.right != null){
queue.offer(cur.right);
}
}
}
2.7二叉树的基本操作
import java.util.*;
public class TestBinaryTree {
//求二叉树节点的个数 遍历思路
public static int countSize = 0;
public void size1(TreeNode root){
if (root == null){
return;
}
countSize++;
size1(root.left);
size1(root.right);
}
//求二叉树节点的个数 子问题思路
public int size2(TreeNode root){
if (root == null){
return 0;
}
return size2(root.left)+size2(root.right)+1;
}
//求二叉树的叶子节点的个数 遍历思路
public static int countLeaf = 0;
public void getLeafNodeCount1(TreeNode root){
if (root == null){
return;
}
if (root.left == null && root.right == null){
countLeaf++;
}
getLeafNodeCount1(root.left);
getLeafNodeCount1(root.right);
}
//求二叉树的叶子节点的个数 子问题思路
public int getLeafNodeCount2(TreeNode root){
if (root == null){
return 0;
}
if (root.left == null && root.right == null){
return 1;
}
return getLeafNodeCount2(root.left)+getLeafNodeCount2(root.right);
}
//求第K层节点的个数
public int getKLevelNodeCount(TreeNode root,int k){
if (root == null){
return 0;
}
if (k == 1) {
return 1;
}
return getKLevelNodeCount(root.left,k-1)+getKLevelNodeCount(root.right,k-1);
}
//求树的高度
public int getHeight(TreeNode root){
if (root == null){
return 0;
}
int leftHigh = getHeight(root.left);
int rightHigh = getHeight(root.right);
return leftHigh > rightHigh ? leftHigh+1 : rightHigh+1;
}
// 检测值为value的元素是否存在
public TreeNode find(TreeNode root, int val){
if (root == null){
return null;
}
if (root.val == val){
return root;
}
TreeNode leftFind = find(root.left,val);
if (leftFind != null){
return leftFind;
}
TreeNode rightFind = find(root.right,val);
if (rightFind != null){
return rightFind;
}
return null;
}
//判断这棵树是不是完全二叉树
public boolean isCompleteTree(TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();
//根不为空,放到队列里
if(root != null){
queue.offer(root);
}
//队列不为空,出队,如果出队不为空,将节点的左右孩子入队,否则退出循环
while (!queue.isEmpty()){
TreeNode cur = queue.poll();
if (cur != null){
queue.offer(cur.left);
queue.offer(cur.right);
}else {
break;
}
}
while (!queue.isEmpty()){
TreeNode cur = queue.peek();
if (cur != null){
return false;
}else {
queue.poll();
}
}
return true;
}
}