浙大数据结构——3.3二叉树的遍历

二叉树的递归遍历

(1)先序遍历(父、左、右)

void PreOrderTraversal(BinTree BT){
	if(BT){
		printf("%d",BT->Data);
		PreOrderTraversal(BT->Left);
		PreOrderTraversal(BT->Right);
	}
} 

(2)中序遍历(左、父、右)

void PreOrderTraversal(BinTree BT){
	if(BT){
		PreOrderTraversal(BT->Left);
		printf("%d",BT->Data);
		PreOrderTraversal(BT->Right);
	}
} 

(3)后序遍历(左、右、父)

void PreOrderTraversal(BinTree BT){
	if(BT){
		PreOrderTraversal(BT->Left);
		PreOrderTraversal(BT->Right);
		printf("%d",BT->Data);
	}
} 

总结:上述三种遍历方法的遍历路径是一样的,只是打印的时机不一样。先序是第一次遇到结点时打印,中序是在第二次遇到结点时打印,后序是第三次遇到结点时打印。

二叉树的非递归遍历(堆栈)

(1)中序遍历算法

遇到一个结点,把它压栈,并遍历其左子树;

当左子树遍历完,弹出栈顶元素,并访问这个元素;

然后按其右指针再按如上程序操作。

void InOrderTraversal(BinTree BT){
	BinTree T=BT;
	Stack S=CreatStack(MaxSize);
	while(T || !IsEmpty){
		while(T){
			Push(S,T);
			T=T->Left;
		}
		if(!IsEmpty(S)){
			T=Pop(S);
			printf("%5d",T->Data);
			T=T->Right;
		}
	}
}

(2)先序遍历算法

遇到一个结点,访问这个元素,并把它压栈,遍历其左子树;

当左子树遍历完,弹出栈顶元素;

然后按其右指针再按如上程序操作。

void InOrderTraversal(BinTree BT){
	BinTree T=BT;
	Stack S=CreatStack(MaxSize);
	while(T || !IsEmpty){
		while(T){
			Push(S,T);
			printf("%5d",T->Data);
			T=T->Left;
		}
		if(!IsEmpty(S)){
			T=Pop(S);
			T=T->Right;
		}
	}
}

(3)后序遍历

与中序和先序不一样,算法需要修改。前两者都是pop左子树再pop父结点再pop右子树。下面的算法中,pop出左子树后,会pop父结点,但是要判断两种情况:这个根是否有右子树、它的右子树是否刚pop出来。满足这两种情况则打印这个父结点,不满足则放回堆栈,指针指向它的右子树继续遍历。

void PostOrderTraversal(BinTree BT) {
    BinTree T = BT, PrePop = NULL; //PrePop记录上一个Pop出来的结点
    Stack S = CreatStack(MaxSize);
    while (T || !IsEmpty(S)) {
        while (T) {        //一直向左将结点压入堆栈
            Push(S, T);
            T = T->Left;
        }
        //将Pop的过程改为循环
        while (!IsEmpty(S)) { //后序遍历有两种情况可以Pop该结点
            T = Pop(S);
            if (T->Right == PrePop || T->Right == NULL) {  //该结点的右结点为空或者上一次Pop的是该结点的右结点
                printf("%05d", T->Data);
                PrePop = T;
            }
            else {  //若不满足以上两种情况 说明该节点右侧节点还未被Pop
                Push(S, T);  //则将该结点重新压回堆栈
                T = T->Right;  //然后指向该结点的右节点
                break; //退出Pop循环
            }
        }
    }
}

层序遍历

用队列实现:根节点入队,从队列中取出一个元素,访问该元素的左右儿子,若左右儿子非空,则顺序入队。

void LevelOrderTraversal(BinTree BT){
	Queue Q;
	BinTree T;
	if(!BT){
		return;
	}
	Q=CreateQueue(MaxSize);
	Add(Q,BT);
	while(!IsEmptyQ(Q)){
		T=DeleteQ(Q);
		printf("%d\n",T->Data);
		if(T->Left){
			AddQ(Q,T->Left);
		}
		if(T-Right){
			AddQ(Q,T->Right);
		}
	}
}

遍历二叉树的应用

eg1:输出二叉树中的叶子结点。(利用先序递归遍历)

void PreOrderTraversal(BinTree BT){
	if(BT){
		if(!BT->Left && !BT->Right){
			printf("%d",BT->Data);
		}
		PreOrderTraversal(BT->Left);
		PreOrderTraversal(BT->Right);
	}
} 

eg2:求二叉树的高度(改编后序递归遍历)

int PostOrderGetHeight(BinTree BT){
	int HL,HR,MaxH;
	if(BT){
		HL=PostOrderGetHeight(BT->Left);
		HR=PostOrderGetHeight(BT->Right);
		MaxH=(HL>HR)?HL:HR;
		return(MaxH+1);
	}
	else return 0;
}

eg3:二元运算表达式树及其遍历

为了防止优先级混乱,遍历完一个左子树、父结点、右子树后要加括号。

eg4:由两种遍历序列确定二叉树(必须包含中序遍历)如:

根据先序序列,a是根节点,则中序序列中,a前面的是左子树包含的元素,a后面是右子树包含的元素。

在先序序列,b是左子树的根节点,则中序序列中,c是左子树,ed是右子树。按照这种方法一直分析下去可知结构。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值