二叉树基础知识

一、二叉树的种类

1.满二叉树

(1)满二叉树的底层是满的。
(2)满二叉树的节点数量:2^k-1,其中k是层数(从根节点往下数,根节点为第一层)。

2.完全二叉树

(1)完全二叉树的底层不是满的,但是从左到右一定是连续的。

3.二叉搜索树

(1)左子树的所有节点都小于根节点,右子树的所有节点都大于根节点,同时对于每一棵左右子树来说都满足这个规律。
(2)查找某个节点的时间复杂度是log(n)级别的。
(3)二叉搜索树对于节点的布局是没有任何要求的。

4.平衡二叉搜索树

(1)左子树和右子树的高度的差的绝对值不能超过1。

二、二叉树的存储方式

1.链式存储

通过指针来指向下一个节点。

2.线性存储

通过数组来存储节点,从左到右,从上到下,编号为0开始。
某一个节点的左孩子的计算方式:2*i+1
某一个节点的有孩子的计算方式:2*i+2
注意:如果这棵树不是完全二叉树,那么剩余的节点我们可以用null来填充。

三、二叉树的遍历

1.深度优先搜索

(1)前序遍历:根 左 右
(2)中序遍历:左 根 右
(3)后序遍历:左 右 根

通常用递归的方法来进行树的遍历,也可以通过迭代的方法进行遍历。

2.广度优先搜索

层序遍历,一层一层地去遍历。利用队列,通过迭代的方式一层一层的去遍历。

3.递归三部曲

(1)确定递归函数的参数和返回值
(2)确定终止条件
(3)单层递归的逻辑

以前序遍历为例,代码如下:

void qianxu(TreeNode root,List<Integer> list){
	if(root==null)
		return;
	list.add(root.val);   //对根节点进行操作
	qianxu(root.left,list);
	qianxu(root.right,list);
}
4.非递归遍历二叉树

(1)非递归前序遍历:
借助栈来完成操作。前序遍历是:根 左 右。我们先将根节点入栈,在栈不为空的时候,弹出栈顶元素,然后将根节点的右孩子入栈,将根节点的左孩子入栈(顺序不能乱),因为只有这样出栈的时候才能达到“根 左 右”的目的。伪代码如下:

void function(TreeNode root,List list){
	Stack st;
	st.push(root);
	while(!st.isEmpty()){
		node = st.peek();
		st.pop();
		if(node!=null){
			list.add(node);   //处理根节点   
		}else{
			continue;
		}
		st.push(node.right);    //将右孩子入栈
		st.push(node.left);    //将左孩子入栈
	}	
}

(2)非递归后序遍历:
非递归的后序遍历实际上是在前序遍历的基础上实现的。前序遍历是按照“根 左 右”放入数组中的,那么如果我们按照“根 右 左”的顺序放入数组中,最后再将数组进行反转,反转后的数组就为“左 右 根”。这就达到了后序遍历的要求。
那么如何按照“根 右 左”的顺序放入数组中呢?参考前序遍历是将根节点首先入栈,然后弹出根节点,放入数组中,再将右孩子和左孩子入栈,循环直到栈为空。所以我们可以先将根节点入栈,然后弹出,放入数组中,再将左孩子和有孩子入栈,循环直到栈为空。最后再将数组进行翻转。代码如下:

void function(TreeNode root,List list){
	Stack st;
	st.push(root);
	while(!st.isEmpty()){
		node = st.peek();
		st.pop();
		if(node!=null){
			list.add(node);   //处理根节点   
		}else{
			continue;
		}
		st.push(node.left);    //将左孩子入栈
		st.push(node.right);    //将右孩子入栈
	}	
	reverse(list);   //将数组翻转

(3)非递归中序遍历:
中序遍历:左 根 右。
中序遍历处理的第一个节点是整棵二叉树的最左边的节点,因此我们可以维护一个指针,用来记录现在访问的节点。在访问过程中,如果当前节点不为空,我们将访问到的节点入栈,并继续访问下一个节点(当前节点的左孩子)。如果当前节点为空,那么弹出栈顶元素,同时使指针指向刚弹出的栈顶元素(变为当前元素),并且接下来要访问当前节点的右孩子,然后继续循环。伪代码如下:

void function(TreeNode root,List list){
	Stack st;
	TreeNode cur = root;   //当前根节点为要访问的元素
	while(!st.isEmpty()||cur!=null){
		if(cur!=null){
			st.push(cur);
			cur = cur.left;
		}else{
			cur = st.peek();
			st.pop();
			list.add(cur);   //处理根节点
			cur = cur.right;
		}
	}	
}

5.二叉树的层序遍历

二叉树的层序遍历意思是一层一层地从上往下,从左往右遍历每个节点。层序遍历需要借助队列。具体思路如下:首先将根节点入队,当队列不为空时,进行循环:对首元素出队,处理对首元素,同时把对首元素的左右孩子按顺序入队。伪代码如下:

void levelOrder(TreeNode root){
	Queue qu;
	List list;
	TreeNode temp;
	qu.offer(root);
	while(!qu.isEmpty()){
		temp = qu.peek();   //对首元素
		list.add(temp);    //处理对首元素
		qu.poll();
		if(temp.left!=null){
			qu.offer(temp.left);
		}
		if(temp.right!=null){
			qu.offer(temp.right);
		}
	}
}

如果我们要收集每一层的节点,我们可以将代码改成如下:

void levelOrder(TreeNode root){
	Queue qu;
	List list1;
	TreeNode temp;
	qu.offer(root);
	while(!qu.isEmpty()){
		int size = qu.size();
		List list2;
		for(int i = 0;i<size;i++){
			temp = qu.peek();   //对首元素
			list2.add(temp);    //处理对首元素
			qu.poll();
			if(temp.left!=null){
				qu.offer(temp.left);
			}
			if(temp.right!=null){
				qu.offer(temp.right);
			}
		}
		list1.add(list2);		
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值