摘要
二叉树是一种广泛应用于数据结构和算法中的树形数据结构。本文将带你深入了解二叉树的结构、遍历方法及其在实际应用中的优势,帮助你更好地掌握这一重要概念。
二叉树的建立
我们是通过输入一个先序序列来构建二叉树的。
// 根据先序序列构建二叉树
public static TreeNode buildTree(String str){ //str是输入的先序序列,例如AB**C** *是代表空子树
TreeNode root=null;
if(str.charAt(i)!='*'){
root=new TreeNode(str.charAt(i));
i++; //i是一个初始化为0的全局变量
root.left=buildTree(str);
root.right=buildTree(str);
}else {
i++;
}
return root;
}
二叉树的遍历
二叉数的遍历可以分为递归遍历和非递归遍历。而我们主要介绍一下非递归遍历。(可能递归对于大家来说都是小case吧)
在非递归方法中我们要利用栈这个数据结构。先通过先序遍历遍历说明一下。在先序遍历中我们是按照根节点,左节点,最后右节点访问的。具体操作就是假如我们有一个根节点,然后我们创建一个栈,将根节点压入栈,之后只要栈不为空,就一直循环,循环中每次pop出一个节点,只要这个节点的右节点不为空就压入栈,接着左节点不为空就压入栈,就可以了。(先右后左是因为栈是先入后出的)代码展示先序和后序遍历
//非递归先序遍历
public static List<Character> preorderStack(TreeNode root){
List<Character> list=new ArrayList<>();
Stack<TreeNode> stack=new Stack<>();
stack.push(root); //先将根节点压入栈
while(!stack.isEmpty()) {
TreeNode node = stack.pop(); //每次处理栈顶元素
list.add(node.val); //将当前节点加入集合中
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
return list;
}
//非递归后续遍历
public static List<Character> postorderStack(TreeNode root){
List<Character> list=new ArrayList<>();
Stack<TreeNode> stack=new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode pop = stack.pop();
list.add(pop.val);
if(pop.left!=null){
stack.push(pop.left);
}
if(pop.right!=null){
stack.push(pop.right);
}
}
Collections.reverse(list); //上面我们是按照根右左的顺序访问,所以我们将集合反转即可
return list;
}
中序遍历的迭代法思路具体的,我们可以使用一个 cur指针 先指向根节点,然后进行循环,循环什么呢?当 cur指针 不为空时,就让 cur指针 一值向左走,边走边用栈记录下结点值,当 cur指针为空时,我们就可以从栈中弹出元素给 cur指针 ,接着让 cur 指针向右结点走,接着循环以上步骤,直到 cur == null 并且 栈为空为止。
//非递归中序遍历
public static List<Character> inorderStack(TreeNode root){
List<Character> list=new ArrayList<>();
Stack<TreeNode> stack=new Stack<>();
TreeNode cur =root;
while (cur!=null||!stack.isEmpty()){
if(cur!=null){
stack.push(cur);
cur=cur.left;
}else{
cur=stack.pop();
list.add(cur.val);
cur=cur.right;
}
}
return list;
}
以上的遍历在本质上都属于深度优先遍历(DFS),而还有一种层序遍历就属于广度优先遍历(BFS)它体现了一种“一圈一圈向外扩展”的逐层遍历方式。广度优先遍历通常借助“队列”来实现。队列遵循“先进先出”的规则,而广度优先遍历则遵循“逐层推进”的规则,两者背后的思想是一致的。
//层序遍历
public void levelOrder(TreeNode root){
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
TreeNode poll = queue.poll();
list.add(poll.val);
if(poll.left!=null){
queue.offer(poll.left);
}
if(poll.right!=null){
queue.offer(poll.right);
}
}
}
遍历就简单介绍到这里了,其实想要更深刻的理解就自己画一个二叉树,然后照着代码一步一步的执行(在纸上画一个栈,一个队列模拟一下),边执行边思考效果会挺好的,加油!
二叉树的应用
排序:二叉搜索树(BST)可以用于排序,它的根节点存储最大值,左子树存储小于根节点的值,右子树存储大于根节点的值。
查找:二叉搜索树可以用于查找元素,时间复杂度为O(log n)。
平衡二叉树:在平衡二叉树中,每个节点的左右子树的高度差不超过1,这可以确保查找和插入操作的时间复杂度为O(log n)。
堆:堆是一种特殊的完全二叉树,用于实现优先队列,时间复杂度为O(log n)。