概述
1.种类
- 满二叉树:二叉树只有度(子节点个数)为0与2的节点,且度为0的节点在同一层
- 完全二叉树:底层以上全被填满,底层节点从左向右连续(集中于左边)
- 二叉搜索树(二叉排序树)
满二叉树与完全二叉树没有数值的概念,而二叉搜索树有
1.若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值
2.若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值
3.它的左、右子树也分别为二叉排序树
- 平衡二叉搜索树(AVL):空树或左右两子树高度差绝对值不超过1,并且是平衡二叉树
- 堆是完全二叉树和排序的结合,而不是平衡二叉搜索树
堆是一棵完全二叉树(一定是平衡二叉树),同时保证父子节点的顺序关系(父节点大于子节点)
而搜索树是父节点大于左孩子,小于右孩子,所以堆不是平衡二叉搜索树
2.存储方式
- 链式存储(链表)
- 顺序存储(数组)
3.遍历方式
1.前序遍历:中左右
2.中序遍历:左中右
3.后序遍历:左右中
层次遍历(迭代,队列)
深度优先遍历
1.递归三步走
确定哪些参数是递归的过程中需要处理的进而确定递归函数的参数
确定每次递归的返回值是什么进而确定递归函数的返回类型
-->相当于确定函数的作用
确定每层递归需要处理的信息,清晰重复调用自己实现递归的过程
class Solution {
public List<Integer> preorderTraversal(TreeNode root){
List<Integer> res = new ArrayList<Integer>();
preorder(root,res);
return res;
}
public void preorder(TreeNode root,List<Integer> res){
if(root==null) return;
res.add(root.val);
preorder(root.left,res);
preorder(root.right,res);
}
}
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> st = new Stack<>();
if(root!=null)st.push(root);
while(!st.isEmpty()){
TreeNode node = st.peek();
if(node!=null){
st.pop();
if(node.right!=null) st.push(node.right);
if(node.left!=null) st.push(node.left);
st.push(node);
st.push(null);
} else {
st.pop();
node = st.peek();
st.pop();
result.add(node.val);
}
}
return result;
}
}
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while(root!=null||!stack.isEmpty()){
while(root!=null){
list.add(root.val);
stack.push(root);
root = root.left;
}
root = stack.pop();
root = root.right;
}
return list;
}
}
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
inorder(root,res);
return res;
}
public void inorder(TreeNode root,List<Integer> res){
if(root==null) return;
inorder(root.left,res);
res.add(root.val);
inorder(root.right,res);
}
}
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> st = new Stack<>();
if(root!=null)st.push(root);
while(!st.empty()){
TreeNode node = st.peek();
if(node!=null){
st.pop();
if(node.right!=null) st.push(node.right);
st.push(node);
st.push(null);
if(node.left!=null) st.push(node.left);
} else {
st.pop();
node = st.peek();
st.pop();
result.add(node.val);
}
}
return result;
}
}
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while(root!=null||!stack.isEmpty()){
while(root!=null){
stack.push(root);
root = root.left;
}
root = stack.pop();
list.add(root.val);
root = root.right;
}
return list;
}
}
class Solution {
public List<Integer> postorderTraversal(TreeNode root){
List<Integer> res = new ArrayList<Integer>();
postorder(root,res);
return res;
}
public void postorder(TreeNode root,List<Integer> res){
if(root==null) return;
postorder(root.left,res);
postorder(root.right,res);
res.add(root.val);
}
}
class Solution {
public List<Integer> postorderTraversal(TreeNode root){
List<Integer> result = new LinkedList<>();
Stack<TreeNode> st = new Stack<>();
if(root!=null)st.push(root);
while(!st.empty()){
TreeNode node = st.peek();
if(node!=null){
st.pop();
st.push(node);
st.push(null);
if(node.right!=null) st.push(node.right);
if(node.left!=null) st.push(node.left);
} else {
st.pop();
node = st.peek();
st.pop();
result.add(node.val);
}
}
return result;
}
}
class Solution {
public List<Integer> preorder(Node root) {
List<Integer> res = new ArrayList();
pre(root,res);
return res;
}
public void pre(Node root,List<Integer> res) {
if(root==null) return;
res.add(root.val);
for(Node node:root.children){
pre(node,res);
}
}
}
class Solution {
public List<Integer> postorder(Node root) {
List<Integer> res = new ArrayList();
post(root,res);
return res;
}
public void post(Node root,List<Integer> res) {
if(root==null) return;
for(Node node:root.children){
post(node,res);
}
res.add(root.val);
}
}
广度优先遍历
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ress = new ArrayList();
List<Integer> res;
if(root==null) return ress;
Queue<TreeNode> queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()){
res = new ArrayList();
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
res.add(node.val);
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
}
ress.add(res);
}
return ress;
}
}
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> ress = new ArrayList();
Stack<List<Integer>> stack = new Stack();
List<Integer> res;
if(root==null) return ress;
Queue<TreeNode> queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()){
res = new ArrayList();
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
res.add(node.val);
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
}
stack.push(res);
}
while(!stack.isEmpty()) ress.add(stack.pop());
return ress;
}
}
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList();
if(root==null) return res;
Queue<TreeNode> queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
TreeNode node = null;
for(int i=0;i<size;i++){
node = queue.poll();
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
}
res.add(node.val);
}
return res;
}
}
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> ress = new ArrayList();
if(root==null) return ress;
double res;
Queue<TreeNode> queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()){
res = 0.0;
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
res += node.val;
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
}
ress.add(res/size);
}
return ress;
}
}
class Solution {
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> ress = new ArrayList();
List<Integer> res;
if(root==null) return ress;
Queue<Node> queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()){
res = new ArrayList();
int size = queue.size();
for(int i=0;i<size;i++){
Node node = queue.poll();
res.add(node.val);
if(node.children!=null){
for(Node no:node.children){
queue.offer(no);
}
}
}
ress.add(res);
}
return ress;
}
}
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList();
if(root==null) return res;
Queue<TreeNode> queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()){
int max=Integer.MIN_VALUE;
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
max = Math.max(max,node.val);
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
}
res.add(max);
}
return res;
}
}
class Solution {
public Node connect(Node root) {
if(root==null) return root;
Queue<Node> queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
for(int i=0;i<size;i++){
Node node = queue.poll();
if(i<size-1) node.next = queue.peek();
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
}
}
return root;
}
}
class Solution {
public int maxDepth(TreeNode root) {
int res = 0;
if(root==null) return res;
Queue<TreeNode> queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
}
res++;
}
return res;
}
}
class Solution {
public int minDepth(TreeNode root) {
int res = 0;
if(root==null) return res;
Queue<TreeNode> queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
res++;
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
if(node.left==null&&node.right==null){
return res;
}
}
}
return res;
}
}
总结
1.递归与迭代的优劣
- 不考虑函数调用开销和函数调用产生的堆栈开销,二者的时间复杂度差不多
- 空间复杂度递归开销更大
- 递归方便程序员,但难为机器,实际开发中避免使用递归!