只做财经的网站,找网页设计公司去哪个平台,网站建设对应的岗位,制作网页首页教程一#xff0c;概念
1#xff0c;结点的度#xff1a;一个结点含有子树的个数称为该结点的度
2#xff0c; 树的度#xff1a;一棵树中#xff0c;所有结点度的最大值称为树的度#xff1b;
3#xff0c;叶子结点或终端结点#xff1a;度为0的结点称为叶结点#x…一概念
1结点的度一个结点含有子树的个数称为该结点的度
2 树的度一棵树中所有结点度的最大值称为树的度
3叶子结点或终端结点度为0的结点称为叶结点
4双亲结点或父结点若一个结点含有子结点则这个结点称为其子结点的父结点,
5孩子结点或子结点一个结点含有的子树的根结点称为该结点的子结点
6根结点一棵树中没有双亲结点的结点
7树的高度或深度树中结点的最大层次
二二叉树的分类
1满二叉树
每层的结点数都达到最大值则这棵二叉树就是满二叉树。满二叉树是一种特殊的完全二叉树
2完全二叉树
从上到下从左到右一次排列
三二叉树的基本性
1若规定根节点的层数为1则一颗非空二叉树的第i层上最多有2^i-1个节点
2 如规定根结点的二叉树的深度为为1则深度为k的二叉树的最大节点数是2^-1
3对任意一颗二叉树如果其叶节点的个数为n0度为2的非叶节点个数为n2则有n0n21
4,具有n个节点的完全二叉树的深度为log2n1上取整
5对于具有n个节点的完全二叉树如果按照从上至下从左至右所有节点从0开始编号如果父节点的下标为i则孩子节点为2i12i2。但是如果2i1n,左无左孩子若2i2n否则没有右孩子
6知道孩子的下标父节点的下标为i-1/2,如果i0则无则无双亲节点
7, 二叉树存储分为顺序存储和链式储存链式储存是通过一个一个节点的引用起来的。
以链式储存为例
例如
public class BinaryTree {public TreeNode root;static class TreeNode{public char val;public TreeNode left;public TreeNode right;public TreeNode(char val) {this.val val;}}
}
四二叉树的遍历
分类
二叉树的遍历分为大体四种前序遍历中序遍历后序遍历层序遍历。前三种遍历的方式又可以写为递归的形式和非递归的形式
前序遍历
二叉树中的每一棵树都要符合先遍历根然后遍历左树最后是右树根左右
递归
如果根为空直接return。先打印根然后打印左树最后是右树
public void preOrder(TreeNode root){if (rootnull){return;}System.out.print(root.val );preOrder(root.left);preOrder(root.right);
}
非递归
法一
借助栈。先将根放到栈中然后弹出记录下来赋值给cur并打印。然后先将cur的右根放到栈中再放cur的左根。在再弹出栈顶元素也就是左根重复上述步骤记录下来并打印将其右左树再放到栈中
注意
1一定是先放右树再放左树
2将左右树放到栈中时要分别判断左右树是否为空如果为空则不进栈
public void preOrder2(TreeNode root){StackTreeNode stacknew Stack();stack.push(root);TreeNode curstack.pop();stack.push(cur.right);stack.push(cur.left);System.out.print(cur.val );while (!stack.isEmpty()){curstack.pop();if (cur.right!null){stack.push(cur.right);}if (cur.left!null) {stack.push(cur.left);}System.out.print(cur.val );}
}
法二
借助栈。将root赋值给cur进入两次循环内循环是找到cur最左边的树并把过程中经过的每一个节点放到栈中直到找到null。因为这里是前序遍历所以每找到一个节点就要打印出来。当找到null时走出循环。这时弹出栈顶元素cur等于栈顶元素的右树通过前面步骤已知栈顶元素的左树为空。然后cur开始外循环。由于内循环的条件是cur!null所以当右树为空时不进入内循环直接再次弹出栈顶元素。如果不为空是则进入内循环寻找它的左树……
public void preOrder3(TreeNode root){StackTreeNode stacknew Stack();TreeNode curroot;while (cur!null||!stack.isEmpty()){while (cur!null){stack.push(cur);System.out.print(cur.val );curcur.left;}TreeNode oldstack.pop();curold.right;}System.out.println();
}
中序遍历
二叉树中的每一棵树都要符合先遍历左树然后遍历根最后是右树左根右
递归
public void midOrder(TreeNode root){if (rootnull){return;}midOrder(root.left);System.out.print(root.val );midOrder(root.right);
非递归
与前序遍历非递归的法二原理相似只是根打印的位置不相同所以在走内循环时不打印节点走完后在打印这样保证先打印的是左树。
public void midOrder2(TreeNode root){StackTreeNodestacknew Stack();TreeNode curroot;while (cur!null||!stack.isEmpty()){while (cur!null){stack.push(cur);curcur.left;}TreeNode oldstack.pop();System.out.print(old.val );curold.right;}System.out.println();
}后序遍历
二叉树中的每一棵树都要符合先遍历左树然后遍历右树最后是根左右根
递归
public void postOrder(TreeNode root){if (rootnull){return;}postOrder(root.left);postOrder(root.right);System.out.print(root.val );
}
非递归
与中序遍历非递归思路相似只是根打印的位置不相同所以在走内循环及走完内循环后均不打印完成内循环后直接判断栈顶元素右树是否为空如果为空就可以弹出栈顶元素并且打印。但是如果不为空就要先走右树因为后序遍历的顺序是左右根已知没有左树所以要先打印右树。
注意要把每次遍历完的节点储存一下。因为每次内循环走完左树为空时到判断栈顶元素A右树时在右树不为空的情况下这时会开始遍历右树当遍历完右树后又会回到这个起点判断该栈顶元素A是否有右树这时就会进入死循环所以这里的判断条件进行丰富即栈顶元素既有右树且之前没有遍历过【注意栈顶元素A,只是举了一个例子方便理解】
public void postOrder2(TreeNode root){StackTreeNodestacknew Stack();TreeNode curroot;TreeNode prevnull;while (cur!null||!stack.isEmpty()){while (cur!null){stack.push(cur);curcur.left;}TreeNode oldstack.peek();if (old.rightnull||prevold.right){stack.pop();System.out.print(old.val );prevold;}else {curold.right;}}System.out.println();
}
层序遍历
一层一层的进行遍历
这里我们用到了队列先把根放进去弹出时记录下来赋值到ret中并打印然后根据ret将ret的左树和右树也放到队列里面重复上述步骤弹出记录下来并打印将其左右树再放到队列中循环上述步骤直到队列为空则遍历完成。需要注意的是将左右树放到队列中时要分别判断左右树是否为空如果为空则不进队列只有不为空时才能放入。
法一
public void levelOrder(TreeNode root){QueueTreeNode queuenew LinkedList();if (rootnull){return;}queue.offer(root);while (!queue.isEmpty()){TreeNode retqueue.peek();if (ret.left!null){queue.offer(ret.left);}if (ret.right!null){queue.offer(ret.right);}System.out.print(queue.poll().val );}System.out.println();
}
法二
这种方法是将每一层的节点放到一个链表中然后将每一层的的链表放到一个“大的链表”中。先将根放到队列中计算这一层的大小size则决定着这一层的的链表的大小。然后循环size次从而将这一层的每个元素均放到该层链表中。然后将这一层的每个元素的左右树再放到队列中重复上述步骤直到链表为空。
public ListListCharacter levelOrder2(TreeNode root){ListListCharacter retnew LinkedList();if (rootnull){return ret;}QueueTreeNode queuenew LinkedList();queue.offer(root);while (!queue.isEmpty()){int size queue.size();ListCharacter listnew LinkedList();while (size0){TreeNode nodequeue.peek();if (node.left!null){queue.offer(node.left);}if (node.right!null) {queue.offer(node.right);}list.add(queue.poll().val);size--;}ret.add(list);}return ret;}
五求二叉树的简单性质
1一棵树的节点个数
法一
我们遍历二叉树时遍历了每个节点所以只需要将遍历中打印的步骤改为count就可以得到节点的个数
public static int sizeNode;
public void size2(TreeNode root) {if (rootnull){return ;}sizeNode;size2(root.left);size2(root.right);
}
法二
一棵树的节点个数这棵树的左子树的节点个数右子树的节点个数1.这个1是根节点
public int size(TreeNode root){if (rootnull){return 0;}return 1size(root.left)size(root.right);
}
2求叶子节点的个数
法一
叶子结点的性质是左子树和右子树均为null所以当遇到这样的节点时返回1。整颗树的叶子结点个数左子树叶子节点的个数右子树叶子结点个数
public int getLeafNodeCount(TreeNode root){if (rootnull){return 0;}if (root.leftnullroot.rightnull){return 1;}return getLeafNodeCount(root.left)getLeafNodeCount(root.right);
}
法二
也可以遍历二叉树找到左子树和右子树均为null的节点count.
public static int sizeLeafNode;
public void getLeafNodeCount2(TreeNode root){if (rootnull){return ;}if (root.leftnullroot.rightnull){sizeLeafNode;}getLeafNodeCount2(root.left);getLeafNodeCount2(root.right);}
3获取k层节点的个数
我们每递归一层时让参数k-1这样当k1时就是k层的节点我们只需要返回1整颗树的k层结点个数左子树的k层节点的个数右子树的k层结点个数
public int getKLevelNodeCount(TreeNode root,int k){if (rootnull ){return 0;}if (k1){return 1;}return getKLevelNodeCount(root.left,k-1)getKLevelNodeCount(root.right,k-1);
}
4树的高度
树的高度左子树高度和右子树高度的最大值1
public int getHeight(TreeNode root){if (rootnull){return 0;}int leftHeightgetHeight(root.left);int rightHeightgetHeight(root.right);return Math.max(leftHeight,rightHeight)1;
}
5找到某个节点
如果找到该节点返回该节点的根。左子树递归完后如果找到了直接返回如果没有找到再右子树递归这样可以提高效率
public TreeNode find(TreeNode root,char val){if (rootnull){return null;}if (root.valval){return root;}TreeNode retfind(root.left,val);if (ret!null){return ret;}retfind(root.right,val);if (ret!null){return ret;}else {return null;}
}
六简单应用
1检查两棵树是否相同
如果两棵树均为空则相同。因为我们需要用递归来实现所以写的时候我们用if语句两棵树一定不相同的条件来快速排除
排除条件
1如果一棵树为空一棵树不为空直接返回false
2如果对应节点的值不一样直接返回false
当两棵树对应的左树与右树均相同则两棵树相同
public boolean isSameTree(TreeNode p,TreeNode q){if (pnullqnull){return true;}if (pnullq!null||p!nullqnull){return false;}if (p.val! q.val){return false;}return isSameTree(p.left,q.left)isSameTree(p.right,q.right);}
2第二棵树是否是第一棵树的子树
我们先找到第一棵树是否有节点与第二棵树的根结点一致如果有相同的节点调用方法一看两棵树是否相同。我们分别从左树和右树中寻找只要有一边找到了就说明第二棵树是第一棵树的子树
public boolean isSubTree(TreeNode root,TreeNode subRoot){if (rootnullsubRoot!null){return false;}if (root.val subRoot.val){return isSameTree(root,subRoot);}return isSubTree(root.left,subRoot)||isSubTree(root.right,subRoot);
}
3翻转二叉树 当根为空或者根的左右树均为空则直接返回根。如果不是交换左右树
private void swap(TreeNode root){TreeNode tmproot.left;root.leftroot.right;root.righttmp;
}
public TreeNode reverseTree(TreeNode root){if (rootnull||root.leftnullroot.rightnull){return root;}swap(root);reverseTree(root.left);reverseTree(root.right);return root;
}
4判断一棵二叉树是否是平衡二叉树
即所有节点的高度差小于等于一
法一
算左右树的高度如果差的绝对值小于1且左树和右树每一棵子树的左右树的高度差的绝对值小于1则是平衡二叉树
public boolean isBalanced(TreeNode root){if (rootnull){return true;}int leftHeightgetHeight(root.left);int rightHeightgetHeight(root.right);return Math.abs(leftHeight-rightHeight)1isBalanced(root.left)isBalanced(root.right);
}
法二优化
重写计算书的高度的方法如果树的左右树的高度差小于1则返回该树的高度如果高度差大于1返回-1最后看树的高度是否大于0如果大于0则说明每一棵树的左右子树的高度差均小于1如果小于0则说明有树的左右子树的高度差均大于1则不是平衡二叉树
public int getHeight2(TreeNode root){if (rootnull){return 0;}int leftgetHeight2(root.left);if (left0){return -1;}int rightgetHeight2(root.right);if (right0){return -1;}if (Math.abs(left-right)1){return Math.max(left,right)1;}else {return -1;}
}
public boolean isBalanced2(TreeNode root){if (rootnull){return true;}return getHeight2(root)0;}5对称二叉树
如果根为空或者根的左树右树均为空则是对称二叉树。
1如果跟的左树右树一个为空一个不为空则不是对称二叉树
2如果根的左树和右树的值不一样则不是对称二叉树
然后判断左右这两棵树是否镜面对称我们再写一个子方法。
1如果这两棵树的左右树均为空则是对称二叉树
2如果一棵树的左树与一棵树的右树一颗为空一颗不为空则不是对称二叉树
3如果一棵树的右树与一棵树的左树一颗为空一颗不为空则不是对称二叉树
4如果一棵树的左树与另一棵树的右树的值不相同或者一棵树的右树与一棵树的左树的值不相同则不是对称二叉树
private boolean isSymmetricChild(TreeNode p,TreeNode q){if (p.leftnullp.rightnullq.leftnullq.rightnull){return true;}if (p.left!nullq.rightnull||p.leftnullq.right!null||p.right!nullq.leftnull||p.rightnullq.left!null){return false;}if (p.left.val!q.right.val||p.right.val!q.left.val){return false;}return isSymmetricChild(p.left,q.right)isSymmetricChild(p.right,q.left);
}public boolean isSymmetric(TreeNode root){if (rootnull||root.leftnullroot.rightnull){return true;}if (root.leftnullroot.right!null||root.left!nullroot.rightnull){return false;}if (root.left.val!root.right.val){return false;}return isSymmetricChild(root.left,root.right);
}