树形结构:树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
特点:有一个特殊的节点,称为根节点,根节点没有前驱节点
除根节点外,其余节点被分成M(M > 0)个互不相交的集合T1、T2、…、Tm,其中每一个集合 Ti (1 <= i<= m) 又是一棵与树类似的子树。每棵子树的根节点有且只有一个前驱,可以有0个或多个后继,树是递归定义的。
节点的度:一个节点含有的子树的个数称为该节点的度。
树的度:一棵树中,最大的节点的度称为树的度;
叶子节点或终端节点:度为0的节点称为叶节点;
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
根结点:一棵树中,没有双亲结点的结点;
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
树的高度或深度:树中节点的最大层次;
二叉树特点:1. 每个结点最多有两棵子树,即二叉树不存在度大于 2 的结点。
2. 二叉树的子树有左右之分,其子树的次序不能颠倒,因此二叉树是有序树。
特殊的二叉树:. .
1**.满二叉树**: 一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果
一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
3. 完全二叉树: 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。
4. 二叉树的性质:1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有 (i>0)个结点。
2. 若规定只有根节点的二叉树的深度为1,则深度为K的二叉树的最大结点数是 (k>=0)
3. 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1。
4. 具有n个结点的完全二叉树的深度k为 上取整。
5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i
的结点有:
若i>0,双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
若2i+1<n,左孩子序号:2i+1,否则无左孩子
若2i+2<n,右孩子序号:2i+2,否则无右孩子
二叉树的前序中序后序遍历代码:
public class TreeTraversal {
public static void preTraversal(TreeNode root){
if(root!=null){ //前序
System.out.printf("%c",root.v);
preTraversal(root.left);
preTraversal(root.right);
}
}
public static void inTraversal(TreeNode root){
if(root!=null){ //后序
inTraversal(root.left);
System.out.printf("%c",root.v);
inTraversal(root.right);
}
}
public static void postTraversal(TreeNode root){
if(root!=null){ //后序
postTraversal(root.left);
postTraversal(root.right);
System.out.printf("%c",root.v);
}
}
public static void main(String[] args) {
TreeNode a=BuildTree.buildTree();
System.out.printf("前序遍历: ");
preTraversal(a);
System.out.println();
System.out.printf("中序遍历: ");
inTraversal(a);
System.out.println();
System.out.printf("后序遍历: ");
postTraversal(a);
System.out.println();
}
}
// 遍历思路-求结点个数;void getSize1(Node root);
// 子问题思路-求结点个数;int getSize2(Node root);
// 遍历思路-求叶子结点个数;void getLeafSize1(Node root);
// 子问题思路-求叶子结点个数;int getLeafSize2(Node root);
// 子问题思路-求第 k 层结点个数;int getKLevelSize(Node root);
// 获取二叉树的高度;int getHeight(Node root);
// 查找 val 所在结点;Node find(Node root, int val);
public class SomeMethod {
private static int n;
public static int sumTreeNodeSize(TreeNode root){ //求树的节点采用遍历思路
n=0;
preOrder(root);
return n;
}
public static int sumTreeNodeSize2(TreeNode root){ // 求树的节点采用汇集思路
if(root==null){
return 0;
}else{
int nodeRootSize=1;
int leftSubNodeSize=sumTreeNodeSize2(root.left);
int rightSubNodeSize=sumTreeNodeSize2(root.right);
return nodeRootSize+leftSubNodeSize+rightSubNodeSize;//根+左子树+右子树
}
}
private static void preOrder(TreeNode root) {
if(root!=null){
n++; // 遍历这个过程会经过每个节点
preOrder(root.left);
preOrder(root.right);
}
}
private static int leafN;
private static int sumTreeLeafNodeSize(TreeNode root){ //求树中叶子节点个数采用遍历思路
// 注意,每次计算叶子结点个数之前,都必须归零
leafN = 0;
// 2. 使用前序遍历方式,经过每一个结点
preOrder2(root);
return leafN;
}
private static int sumTreeLeafNodeSize2(TreeNode root){//求树中叶子节点个数采用汇集思路
if(root==null){
return 0; // 空树
}else if(root.left==null&&root.right==null){
return 1; //只有一个结点
}else{
// 至少一个以上的结点
// 整棵树的叶子结点个数 = 左子树的叶子节点个数 + 右子树的叶子结点个数
int leftSubTreeLeafSize = sumTreeLeafNodeSize2(root.left);
int rightSubTreeLeafSize = sumTreeLeafNodeSize2(root.right);
return leftSubTreeLeafSize + rightSubTreeLeafSize;
}
}
private static void preOrder2(TreeNode root) {
if(root!=null){
if(root.left==null&&root.right==null){
leafN++;
}
preOrder2(root.left);
preOrder2(root.right);
}
}
public static int sumKLevelNodeSize(TreeNode root, int k){ //求第k层节点个数
if(root==null){
return 0;
}else if(k==1){
return 1;
}else{
int leftSumK_1=sumKLevelNodeSize(root.left,k-1);
int rightSumK_1=sumKLevelNodeSize(root.right,k-1);
return leftSumK_1+rightSumK_1;
}
}
public static int getHeight(TreeNode root){ //获取树的高度
if(root==null){
return 0;
}else if(root.left==null&&root.right==null){
return 1;
}else{
int leftSubTreeHeight = getHeight(root.left);
int rightSubTreeHeight = getHeight(root.right);
return Math.max(leftSubTreeHeight,rightSubTreeHeight)+1;
}
}
public static boolean contains2(TreeNode root, int v){ //树中是否包含v 思路:三个大思路:一空树
// 二 判断根中节点是否为v
if(root==null){ //三 根中节点部位不为v,先判断左树,在判断右树
return false; // 注意 若左树有不用判断右树
}
if(root.v==v){
return true;
}
boolean left = contains2(root.left, v);
if (left) {
return true;
}
return contains2(root.right, v);
}
public static boolean contains1(TreeNode root, int v) {
if (root == null) {
// 空树
return false;
} else {
if (root.v == v) {
// 根里找到了
// 没必要再去左右子树找了
return true;
} else {
// 根里没找到
boolean leftSubTreeContains = contains1(root.left, v);
if (leftSubTreeContains) {
// 左子树里找到了
// 没必要再去右子树里找了
return true;
} else {
// 左子树里也没找到
boolean rightSubTreeContains = contains1(root.right, v);
if (rightSubTreeContains) {
// 右子树里找到了
return true;
} else {
return false;
}
}
}
}
}
public static TreeNode contains4(TreeNode root, int v){
if(root==null){
return null;
}
if(root.v==v){
return root;
}
TreeNode leftTreeNode = contains4(root.left, v);
if(leftTreeNode!=null){
return leftTreeNode;
}
return contains4(root.right,v);
}
public static boolean contains3(TreeNode root, TreeNode node){
if(root==null){
return false;
}
if(root==node){
return true;
}
boolean leftTreeNode = contains3(root.left, node);
if(leftTreeNode){
return true;
}
return contains3(root.right, node);
}
public static void main(String[] args) {
TreeNode root=BuildTree.buildTree();
int sum=sumTreeNodeSize2(root);
System.out.println(sum);
int sumLeaf=sumTreeLeafNodeSize2(root);
System.out.println(sumLeaf);
int sumK=sumKLevelNodeSize(root,4);
System.out.println(sumK);
int heightTree=getHeight(root);
System.out.println(heightTree);
System.out.println(contains2(root,'A'));
TreeNode a=contains4(root,'B');
System.out.println(a);
}
}
二叉树的层序遍历,判断完全二叉树(层序遍历应用) 带层级的层序遍历代码
public class TreeLevelOrder {
public static void levelOrderTraversal(TreeNode root){
if(root==null){
return;
}
//队列元素的元素是树的结点
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()){ //把树的结点拖入队列在删除时候在托入他的左右孩子 以此循环
TreeNode node = queue.remove();
System.out.println(node.val);
if(node.left!=null){
queue.add(node.left);
}
if(node.right!=null){
queue.add(node.right);
}
}
}
public static boolean isCompleteTree(TreeNode root){
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
while (true){
TreeNode node = queue.remove();
if(node==null){
break;
}
queue.add(node.left);
queue.add(node.right);
}
while (!queue.isEmpty()){
TreeNode node = queue.remove();
if(node==null){
}
else{
return false;
}
}
return true;
}
static class Nl{
int level;
TreeNode node;
public Nl(TreeNode node, int level) {
this.level = level;
this.node = node;
}
}
public static void levelOrderWithLevel(TreeNode root){
if(root==null){
return;
}
Queue<Nl> queue=new LinkedList<>();
queue.add(new Nl(root,1));
while (!queue.isEmpty()){
Nl nl = queue.remove();
TreeNode node=nl.node;
int level= nl.level;
System.out.println(level);
System.out.println(node.val);
if (node.left != null) {
queue.add(new Nl(node.left, level + 1));
}
if (node.right != null) {
queue.add(new Nl(node.right, level + 1));
}
}
}
public static void main(String[] args) {
TreeNode root=BuildTree.BuildTree1();
levelOrderTraversal(root);
System.out.println(isCompleteTree(root));
levelOrderWithLevel(root);
}
}
前中后序遍历非递归实现
public class FeiDiGui {
public static void preOrder(TreeNode node){
Deque<TreeNode> stack=new LinkedList<>();
TreeNode current=node;
while (!stack.isEmpty()||current!=null){
while (current!=null){
System.out.println(current.v);
stack.push(current);
current=current.left;
}
TreeNode top = stack.pop();
current=top.right;
}
}
public static void main(String[] args) {
TreeNode root=BuildTree.buildTree();
preOrder(root);
System.out.println("-------------");
inOrder(root);
System.out.println("-------------");
postOrder(root);
}
public static void inOrder(TreeNode node){
Deque<TreeNode> stack=new LinkedList<>();
TreeNode current=node;
while (!stack.isEmpty()||current!=null){
while (current!=null){
stack.push(current);
current=current.left;
}
TreeNode top = stack.pop();
System.out.println(top.v);
current=top.right;
}
}
public static void postOrder(TreeNode node){
Deque<TreeNode> stack=new LinkedList<>();
TreeNode current=node;
TreeNode last=null;
while (!stack.isEmpty()||current!=null){
while (current!=null){
System.out.println(current.v);
stack.push(current);
current=current.left;
}
TreeNode top = stack.peek();
if(top.right==null){
stack.pop();
last=top;
System.out.println(top.v);
}
else if (top.right == last) {
// 第三次经过 top
// 说明从右子树回来
stack.pop();
last = top;
System.out.println(top.v);
} else {
// 第二次经过 top
// 说明从左子树回来的
current = top.right;
}
}
}
}