二叉树遍历
二叉树的建立
上图是按层遍历的结果:
根节点是b,它的左孩子是c,右孩子是d
c节点的左孩子是e,右孩子是f
d节点的左孩子是a
规律:
-
父节点数组下标从0到 n/2 -1 ,但是遍历时要小于n/2-1,因为最后一个父节点可能没有右孩子,当n/2-1为奇数时才有右孩子,为偶数时只有左孩子。
-
结点左孩子下标为2n+1,右孩子下标为2n+2
`
class BinaryTreeNode{
char value;
BinaryTreeNode leftNode;
BinaryTreeNode rightNode;
public BinaryTreeNode(){
}
public BinaryTreeNode(char value){
this.value=value;
}
// 创建二叉树
//递归
public BinaryTreeNode createBinaryTree(BinaryTreeNode node,char[] data,int i){
//如果data数组里面没有元素或i大于data数组长度
if(data.length==0||i>data.length || data[i] == ' '){
return null;
}
if(i<data.length){
if(node==null){
node=new BinaryTreeNode();
}
node.value=data[i];
node.leftNode=createBinaryTree(node.leftNode,data,2*i+1);
node.rightNode=createBinaryTree(node.rightNode,data,2*i+2);
}
return node;
}
//创建二叉树
//非递归
public BinaryTreeNode createBinaryTree(char[] data){
if(data.length==0){
return null;
}
List<BinaryTreeNode> list=new ArrayList<>();
for(int i=0;i<data.length;i++){
if (data[i] == ' ') {
list.add(null);
} else {
list.add(new BinaryTreeNode(data[i]));
}
}
for(int i=0;i<data.length/2-1;i++){
if (list.get(i) == null) {
continue;
} else {
//左孩子
list.get(i).leftNode = list.get(i * 2 + 1);
//右孩子
list.get(i).rightNode = list.get(i * 2 + 2);
}
}
//最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独拿出来处理
int last=data.length/2-1;
list.get(last).leftNode=list.get(last*2+1);
//长度为奇数说明有右孩子
if(data.length%2==1){
list.get(last).rightNode=list.get(last*2+2);
}
//返回根节点
return list.get(0);
}
}
`
递归遍历
前序
`
//前序遍历
//递归
public static void preOrder(BinaryTreeNode node){
if(node==null){
return;
}
System.out.print(node.value+" ");
preOrder(node.leftNode);
preOrder(node.rightNode);
}
`
中序
`
//中序遍历
//递归
public static void inOrder(BinaryTreeNode node){
if(node==null){
return;
}
preOrder(node.leftNode);
System.out.print(node.value+" ");
preOrder(node.rightNode);
}
`
后序
`
//后序遍历
//递归
public static void postOrder(BinaryTreeNode node){
if(node==null){
return;
}
preOrder(node.leftNode);
preOrder(node.rightNode);
System.out.print(node.value+" ");
}
`
结果:
按层遍历
需要用到队列
`
//按层遍历
public static void topToBottom(BinaryTreeNode node){
Queue<BinaryTreeNode> queue=new LinkedList<>();
if (node==null){
return;
}
queue.add(node);
while(!queue.isEmpty()){
BinaryTreeNode tempNode=queue.poll();
if(tempNode.leftNode!=null)
queue.add(tempNode.leftNode);
if(tempNode.rightNode!=null)
queue.add(tempNode.rightNode);
System.out.print(tempNode.value+" ");
}
}
`
非递归遍历
先序
`
//前序遍历
//非递归
public static void preOrderTraverseTree(BinaryTreeNode node){
BinaryTreeNode temp=node;
Stack<BinaryTreeNode> stack=new Stack<>();
if(temp==null){
System.out.println("空");
}
while(temp!=null || !stack.empty()){
if(temp!=null){
stack.push(temp);
System.out.print(temp.value+" ");
temp=temp.leftNode;
}else{
temp=stack.pop();
temp=temp.rightNode;
}
}
}
`
中序
`
//中序序遍历
//非递归
public static void inOrderTraverseTree(BinaryTreeNode node){
BinaryTreeNode temp=node;
Stack<BinaryTreeNode> stack=new Stack<>();
if(temp==null){
System.out.println("空");
}
while(temp!=null || !stack.empty()){
if(temp!=null){
stack.push(temp);
temp=temp.leftNode;
}else{
temp=stack.pop();
System.out.print(temp.value+" ");
temp=temp.rightNode;
}
}
}
`
后序
要保证根节点要在左孩子和右孩子都访问下才能访问,对于任意节点x,先入栈,若其没有左孩子和右孩子则可以直接访问。若存在左孩子或右孩子需要左右孩子都访问后才能访问。若非上述两种情况,则将x的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
`
//后序遍历
//非递归
public static void postOrderTraverseTree(BinaryTreeNode node){
BinaryTreeNode temp=node;
Stack<BinaryTreeNode> stack=new Stack<>();
if(temp==null){
System.out.println("空");
}
stack.push(node);
BinaryTreeNode pre=null,cur=null;
while(!stack.empty()){
cur=stack.peek();
if((cur.leftNode==null&&cur.rightNode==null)||(pre!=null&&pre==cur.leftNode||pre==cur.rightNode)){
System.out.print(cur.value+" ");
pre=cur;
stack.pop();
}else{
if(cur.rightNode!=null){
stack.push(cur.rightNode);
}
if(cur.leftNode!=null){
stack.push(cur.leftNode);
}
}
}
}
`
才学疏浅,有什么问题请大家指出来。十分感谢!