二叉树常见方法整理(1 遍历)
程序员文章站
2022-06-05 19:01:29
...
序
最近在看jdk的时候,发现一些底层还是使用了二叉树的相关知识,由此可以扩展开红黑树,或者MySQL的索引B+树。
补充一些知识点。
二叉树:
1、深度优先:递归,非递归实现方式
1)先序遍历:先访问根节点,再依次访问左子树和右子树
2)中序遍历:先访问左子树,再访问根节点吗,最后访问右子树
3)后序遍历:先访问左子树,再访问右子树,最后访问根节点
其中后序遍历是最复杂的。:举例两种不同的实现方式:
a) 对于任意节点current,若该节点不为空则访问该节点后再将节点压栈,并将左子树节点置为current,重复此操作,直到current为空。 若左子树为空,取栈顶节点的右子树,如果右子树为空或右子树刚访问过,则访问该节点,并将preNode置为该节点
b)要保证根结点在左孩子和右孩子访问之后才干访问,因此对于任一结点P。先将其入栈。假设P不存在左孩子和右孩子。则能够直接访问它;或者P存在左孩子或者右孩子。可是其左孩子和右孩子都已被访问过了。
对我来说,其中b更容易理解一些,还有双栈的实现方式更难理解就没贴。
2、广度优先按照树的深度,一层一层的访问树的节点。
节点类
package com.daojia.collect;
/**
*
* @author daojia
*
*/
public class Node {
int value;
Node leftChild;
Node rightChild;
Node(int value) {
this.value = value;
}
public void display() {
System.out.print(this.value + ",");
}
@Override
public String toString() {
return String.valueOf(value);
}
}
package com.daojia.collect;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
public class Btree {
private Node root = null;
Btree(int value) {
root = new Node(value);
root.leftChild = null;
root.rightChild = null;
}
//查找
public Node findKey(int value) {
Node current = root ;
while(true){
if(current.value== value)
{
return current;
}
else if(current.value>value){
current = current.leftChild;
}else if(current.value < value){
current = current.rightChild;
}
if(current == null){
return null;
}
}
}
//插入
public Node insert(int value) {
String error = null;
Node node = new Node(value);
if (root == null) {
root = node;
root.leftChild = null;
root.rightChild = null;
} else {
Node current = root;
Node parent = null;
while (true) {
if (value < current.value) {
parent = current;
current = current.leftChild;
if (current == null) {
parent.leftChild = node;
break;
}
} else if (value > current.value) {
parent = current;
current = current.rightChild;
if (current == null) {
parent.rightChild = node;
break;
}
} else {
System.out.println("exists");
break;
}
} // end of while
}
return node;
}
//中序遍历递归操作
public void inOrderTraverse() {
System.out.print("中序递归:");
inOrderTraverse(root);
System.out.println();
}
/**
* (递归)先遍历左子树,在跟节点,再遍历右子树
* @param node
*/
private void inOrderTraverse(Node node) {
if (node == null)
return ;
inOrderTraverse(node.leftChild);
node.display();
inOrderTraverse(node.rightChild);
}
/**
* 非递归遍历
* 1)对于任意节点current,若该节点不为空则将该节点压栈,并将左子树节点置为current,重复此操作,直到current为空。
* 2)若左子树为空,栈顶节点出栈,访问节点后将该节点的右子树置为current
* 3) 重复1、2步操作,直到current为空且栈内节点为空。
*/
public ArrayList<Integer> inOrderByStack() {
System.out.print("中序非递归:");
ArrayList<Integer> list = new ArrayList<Integer>();
Stack<Node> stack = new Stack<Node>();
Node current = root;
while(current != null ||!stack.isEmpty())
{
while(current != null){
stack.push(current);
current = current.leftChild;
}
if(!stack.isEmpty())
{
current =stack.pop();
list.add(current.value);
current = current.rightChild;
}
}
return list;
}
//前序遍历
public void preOrderTraverse() {
System.out.print("前序遍历:");
preOrderTraverse(root);
System.out.println("");
}
private void preOrderTraverse(Node node) {
if (node == null)
return ;
node.display();
preOrderTraverse(node.leftChild);
preOrderTraverse(node.rightChild);
}
//前序遍历非递归操作
public ArrayList<Integer> preOrderByStack() {
System.out.print("前序遍历 非递归:");
ArrayList<Integer> list = new ArrayList<Integer>();
Stack<Node> stack = new Stack<Node>();
Node current = root;
while(current != null || !stack.isEmpty())
{
while(current != null){
stack.push(current);
list.add(current.value);
current = current.leftChild;
}
if( !stack.isEmpty()){
current = stack.pop();
current = current.rightChild;
}
}
return list;
}
//后序遍历
public void postOrderTraverse() {
System.out.print("后序遍历:");
postOrderTraverse(root);
System.out.println("");
}
private void postOrderTraverse(Node node){
if(node == null){
return;
}
postOrderTraverse(node.leftChild);
postOrderTraverse(node.rightChild);
node.display();
}
/**
* 1)对于任意节点current,若该节点不为空则访问该节点后再将节点压栈,并将左子树节点置为current,重复此操作,直到current为空。
* 2)若左子树为空,取栈顶节点的右子树,如果右子树为空或右子树刚访问过,则访问该节点,并将preNode置为该节点
*/
public ArrayList<Integer> postOrderByStack() {
System.out.print("后序遍历 非递归:");
ArrayList<Integer> list = new ArrayList<Integer>();
Stack<Node> stack = new Stack<Node>();
Node current = root;
Node preNode = null;
while(current != null || !stack.isEmpty())
{
while(current != null){
stack.push(current);
current = current.leftChild;
}
if( !stack.isEmpty()){
current = stack.peek().rightChild;
if (current == null || current == preNode) {
current = stack.pop();
list.add(current.value);
preNode = current;
current = null;
}
}
}
return list;
}
//后序遍历非递归操作
public ArrayList<Integer> postOrderByStack2() {
System.out.print("后序遍历 非递归:");
ArrayList<Integer> list = new ArrayList<Integer>();
Stack<Node> stack = new Stack<Node>();
Node current = null;
Node preNode = null;
stack.push(root);
while(!stack.isEmpty())
{
current = stack.peek();
//当前节点没有孩子节点或者左右孩子节点都被访问过
if( (current.leftChild == null&¤t.rightChild== null) ||
(current!= null&&(current.leftChild == preNode|| current.rightChild== preNode)) ) {
stack.pop();
list.add(current.value);
preNode = current;
}else{
if(current.rightChild != null ){
stack.push(current.rightChild);
}
if(current.leftChild != null ){
stack.push(current.leftChild);
}
}
}
return list;
}
/**
* 广度优先遍历
* @return
*/
public ArrayList<Integer> levelTraverse(){
LinkedList<Node> queue = new LinkedList<Node>();
ArrayList<Integer> list = new ArrayList<Integer>();
System.out.print("广度优先遍历 :");
queue.add(root);
while(!queue.isEmpty()){
Node current = queue.poll();
list.add(current.value);
if(current.leftChild != null){
queue.add(current.leftChild);
}
if(current.rightChild != null){
queue.add(current.rightChild);
}
}
return list;
}
/**
* 得到最小值
* @return
*/
public int getMinValue() {
System.out.print("最小值:");
Node current = root;
while(true){
if(current.leftChild == null)
{
return current.value;
}
current = current.leftChild;
}
}
//得到最大值
public int getMaxValue(){
System.out.print("最大值:");
Node current = root;
while(true){
if(current.rightChild == null)
{
return current.value;
}
current = current.rightChild;
}
}
public static void main(String[] args){
Btree tree = new Btree(10);
tree.insert(7);
tree.insert(8);
tree.insert(9);
tree.insert(12);
tree.insert(11);
tree.insert(13);
System.out.println(tree.insert(1));
tree.inOrderTraverse();
System.out.println(tree.inOrderByStack().toString());
tree.preOrderTraverse();
System.out.println(tree.preOrderByStack().toString());
tree.postOrderTraverse();
System.out.println(tree.postOrderByStack().toString());
System.out.println(tree.postOrderByStack2().toString());
System.out.println(tree.levelTraverse().toString());
System.out.println(tree.getMinValue());
System.out.println(tree.getMaxValue());
}
}
补充下栈的含义:pop 与peek,都返回栈顶的值。
不同点:peek 不改变栈的值(不删除栈顶的值),pop会把栈顶的值删除。
返回getMin栈的最小值。
运行结果:
1
中序递归:1,7,8,9,10,11,12,13,
中序非递归:[1, 7, 8, 9, 10, 11, 12, 13]
前序遍历:10,7,1,8,9,12,11,13,
前序遍历 非递归:[10, 7, 1, 8, 9, 12, 11, 13]
后序遍历:1,9,8,7,11,13,12,10,
后序遍历 非递归:[1, 9, 8, 7, 11, 13, 12, 10]
后序遍历 非递归:[1, 9, 8, 7, 11, 13, 12, 10]
广度优先遍历 :[10, 7, 12, 1, 8, 11, 13, 9]
最小值:1
最大值:13
待续:。。。
参考:
https://blog.csdn.net/fengrunche/article/details/52305748
上一篇: 【数据结构】二叉树的遍历及应用