牛客 5 —— 二叉树

牛客 5 —— 二叉树

二叉树的遍历

二叉树的前序、中序、后序遍历 — 递归

//前序——递归
	public static void previsit(Node node) {
		System.out.println(node);
		previsit(node.left);
		previsit(node.right);
	}
	
	//中序——递归
	public static void invisit(Node node) {
		invisit(node.left);
		System.out.println(node);
		invisit(node.right);
	}
	
	//后序——递归
	public static void postvisit(Node node) {
		postvisit(node.left);
		postvisit(node.right);
		System.out.println(node);
	}

二叉树的前序、中序、后序遍历 — 非递归

中序:当前节点为空,从栈拿一个,打印,向右移动。当前节点不为空,压栈,往左移动。

后序:两个栈,从前序改良。有一种很棒的技巧,就是后序遍历,可以从前序遍历多加一个栈实现。

//前序——非递归
	public static void Fprevisit(Node node) {
		if(node != null) {
			Stack<Node> stack = new Stack<Node>();
			stack.add(node);
			while(!stack.empty()) {
				node = stack.pop();
				visit(node);
				if(node.right != null) {
					stack.push(node.right);
				}
				if(node.left != null) {
					stack.push(node.left);
				}
			}
		}	
	}
	

	//中序——非递归
	public static void Finvisit(Node node) {
		if(node != null) {
			Stack<Node> stack = new Stack<Node>();
			while(!stack.empty() || node != null) {
				//这里有两个继续循环的条件
				//1、栈不为空——还有元素没有访问到
				//2、当前节点node不为空——说明没有找到最左边。
				
				if(node != null) {
					stack.push(node);
					node = node.left;
				}else {
					node = stack.pop();
					visit(node);
					node = node.right;
				}
			}
		}
	}
	
	//后续第一种实现——非递归——双栈
	public static void Fpostvist1(Node node) {
		if (node != null) {
			Stack<Node> s1 = new Stack<Node>();
			Stack<Node> s2 = new Stack<Node>();
			s1.push(node);
			
			while(!s1.empty()) {
				node = s1.pop();
				s2.push(node);
				if(node.left != null) {
					s1.push(node.left);
				}
				if(node.right != null) {
					s1.push(node.right);
				}
			}
			while(!s2.empty()) {
				visit(s2.pop());
			}
		}
	}
	
	//后续第二种实现——非递归
	public static void Fpostvist2(Node node) {
		
		if(node != null) {
			Stack<Node> stack = new Stack<Node>();
			stack.push(node);
			Node c = null;
			while(!stack.empty()) {
				c = stack.peek();
				if (c.left != null && node != c.left && node != c.right) {
					stack.push(c.left);
				} else if (c.right != null && node != c.right) {
					stack.push(c.right);
				} else {
					System.out.print(stack.pop().value + " ");
					node = c;
				}
			}
		}
	}

直观打印树

这个是左神提供给我们作为测试使用的,很直观的打印出树的形状。

public class Code_02_PrintBinaryTree {

	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
			this.value = data;
		}
	}

	public static void printTree(Node head) {
		System.out.println("Binary Tree:");
		printInOrder(head, 0, "H", 17);
		System.out.println();
	}

	public static void printInOrder(Node head, int height, String to, int len) {
		if (head == null) {
			return;
		}
		printInOrder(head.right, height + 1, "v", len);
		String val = to + head.value + to;
		int lenM = val.length();
		int lenL = (len - lenM) / 2;
		int lenR = len - lenM - lenL;
		val = getSpace(lenL) + val + getSpace(lenR);
		System.out.println(getSpace(height * len) + val);
		printInOrder(head.left, height + 1, "^", len);
	}

	public static String getSpace(int num) {
		String space = " ";
		StringBuffer buf = new StringBuffer("");
		for (int i = 0; i < num; i++) {
			buf.append(space);
		}
		return buf.toString();
	}

	public static void main(String[] args) {
		Node head = new Node(1);
		head.left = new Node(-222222222);
		head.right = new Node(3);
		head.left.left = new Node(Integer.MIN_VALUE);
		head.right.left = new Node(55555555);
		head.right.right = new Node(66);
		head.left.left.right = new Node(777);
		printTree(head);

		head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.right.left = new Node(5);
		head.right.right = new Node(6);
		head.left.left.right = new Node(7);
		printTree(head);

		head = new Node(1);
		head.left = new Node(1);
		head.right = new Node(1);
		head.left.left = new Node(1);
		head.right.left = new Node(1);
		head.right.right = new Node(1);
		head.left.left.right = new Node(1);
		printTree(head);
	}
}

后继节点

在这里插入图片描述

如果节点有右子树,那么:他的后继节点就是右子树上最左边的节点。

如果节点没有右子树,那么:通过该节点的父指针,找到该节点的父亲,一直往上,直到某一个节点是他父节点的左孩子停止。
在这里插入图片描述

//树的节点类
	public static class Node {
		public int value;
		public Node left;
		public Node right;
		public Node parent;

		public Node(int data) {
			this.value = data;
		}
	}
	
	public static Node getNext(Node node) {
		if(node == null) {
			return null;
		}
		//如果树的右子树不为空,则后继节点为右子树最左边的节点
		if(node.right != null) {
			Node c = node;
			while(c.left != null) {
				c = c.left;
			}
			return c;
		}else {
			//如果节点的右子树为空,则找父节点,直到该节点的父亲的左孩子是该节点。
			Node parent = node.parent;
			while(parent != null && parent.left != node) {
				node = parent;
				parent = node.parent;
			}
			return parent;
		}
	}

二叉树的序列化与反序列化

可以用递归实现。

平衡树

在这里插入图片描述

1、左树是不是平衡树,如果左树不是平衡树,接下来都不用判断了,肯定不是平衡树。

2、同理,判断右树是否平衡

3、在左树平衡的情况下,拿到左树的高度

4、在右树平衡的情况下拿到右树的高度

5、比较左右子树的高度差

package niuke5;

public class pingheng {

	// 节点类
	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
			this.value = data;
		}
	}

	// 返回类
	public static class ReturnData {
		public boolean isB;
		public int hight;

		public ReturnData(boolean isB, int hight) {
			this.hight = hight;
			this.isB = isB;
		}
	}

	public static ReturnData judge(Node head) {
		// 如果头指针为空,说明平衡
		if (head == null) {
			return new ReturnData(true, 0);
		}
		// 左
		ReturnData leftData = judge(head.left);
		if (!leftData.isB) {
			return new ReturnData(false, 0);
		}
		// 右
		ReturnData rightData = judge(head.right);
		if (!rightData.isB) {
			return new ReturnData(false, 0);
		}
		// 高度差异
		if (Math.abs(rightData.hight - leftData.hight) > 1) {
			return new ReturnData(false, 0);
		}
		// 如果是平衡树
		return new ReturnData(true, Math.max(rightData.hight, leftData.hight) + 1);
	}
}

搜索二叉树、完全二叉树

在这里插入图片描述

搜索二叉树:中序遍历的情况下,是升序的!!!! 所以,我们只要会写中序遍历,在打印数的时改成比较数字大小即可。

完全二叉树:二叉树按层遍历。1、如果一个节点有右孩子没有左孩子,一定不是二叉树;2、如果一个节点,不是左右两个孩子都全,也即是有左没右,或者左右都没有,其后面的所有节点都必须是叶子节点。

public class judge {

	// 判断是否是搜索二叉树、完全二叉树
	
	// 搜索二叉树:中序遍历下,是升序的
	
	//完全二叉树:二叉树按层遍历。
	//1、如果一个节点有右孩子没有左孩子,一定不是二叉树;
	//2、如果一个节点,不是左右两个孩子都全,
	//也即是有左没右,或者左右都没有,其后面的所有节点都必须是叶子节点。  
	
	// 节点类
	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
			this.value = data;
		}
	}

	//判断是否是搜索二叉树
	public static boolean judgeTree1(Node node) {

		if (node != null) {
			Stack<Node> stack = new Stack<Node>();
			while (!stack.empty() || node != null) {
				// 这里有两个继续循环的条件
				// 1、栈不为空——还有元素没有访问到
				// 2、当前节点node不为空——说明没有找到最左边。

				if (node != null) {
					stack.push(node);
					node = node.left;
				} else {
					node = stack.pop();

					// visit(node) —— 原来是visit的时候这里改成比较大小
					if (node.value > stack.peek().value) {
						return false;
					}

					node = node.right;
				}
			}
		}
		return true;
	}
	
	
	public static boolean judgeTree2(Node head) {
		
		if(head == null) {
			return true;
		}
		Queue<Node> queue = new LinkedList<Node>();
		boolean leaf = false;
		Node l = null;
		Node r = null;
		
		queue.offer(head);
		while(!queue.isEmpty()) {
			head = queue.poll();
			l = head.left;
			r = head.right;
			
			//1、该节点是叶子节点,且左右子节点都不为空,
			//或者左不为空,并且作为空
			if((leaf && (l != null || r != null)) || (l == null && r != null)) {
				return false;
			}
			//2、该节点有左节点
			if(l != null) {
				queue.offer(l);
			}
			//3、该节点有右节点
			if(r != null) {
				queue.offer(r);
			}
			//4、该节点有有节点,没有左节点
			if(r != null && l == null) {
				leaf = true;
			}
		}
		return true;
	}
}

完全二叉树节点个数

在这里插入图片描述

递归递归!!!

终点看图!!!

在这里插入图片描述

完全二叉树:最后的叶子节点必须先摆满左边的,再接右边的。

所以,这里要看节点k,也就是头节点的右子树最左边的节点,看看他的高度是否跟左子树的最左边的节点的高度相同。如果高度相同,就说明左子树一定是全部都满的,然后再递归判断右子树即可。

package niuke5;

public class number_of_node {
	
	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
			this.value = data;
		}
	}

	public static int nodeNum(Node head) {
		if (head == null) {
			return 0;
		}
		return bs(head, 1, mostLeftLevel(head, 1));
	}

	public static int bs(Node node, int l, int h) {
		if (l == h) {
			return 1;
		}
		if (mostLeftLevel(node.right, l + 1) == h) {
			return (1 << (h - l)) + bs(node.right, l + 1, h);
		} else {
			return (1 << (h - l - 1)) + bs(node.left, l + 1, h);
		}
	}
	
	public static int mostLeftLevel(Node node, int level) {
		while (node != null) {
			level++;
			node = node.left;
		}
		return level - 1;
	}
}
发布了62 篇原创文章 · 获赞 34 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_41960890/article/details/86291676