MOOC浙大数据结构-二叉树的遍历

本文是MOOC浙大数据结构课程的笔记
课程详细地址

二叉树的遍历

前序遍历

遍历过程:

  1. 访问根节点
  2. 中序遍历其左子树
  3. 中序遍历其右子树
void InOrderTraversal(BinTree BT)
{
	if (BT) {
		printf("%d", BT->Data);
		InOrderTraversal(BT->Left);
		InOrderTraversal(BT->Right);
	}
}

非递归遍历算法
使用堆栈

void InOrderTraversal(BinTree BT)
{
	BinTree T = BT;
	Stack S = CreatStack(MaxSize); //创建初始化堆栈s
	while (T || !IsEmpty(s)) {
		while (T) {// 一直向左并且将沿途的结点压入堆栈
			Push(S, T);
			printf("%5d", T->Data);// 打印结点
			T = T->Left;
		}
		if (!IsEmpty(s)) {
			T = Pop(s); // 结点弹出堆栈
			T = T->Right;// 转向右子树
		}
	}
}

中序遍历

遍历过程:

  1. 中序遍历其左子树
  2. 访问根节点
  3. 中序遍历其右子树
    递归
void InOrderTraversal(BinTree BT)
{
	if (BT) {
		InOrderTraversal(BT->Left);
		printf("%d", BT->Data);
		InOrderTraversal(BT->Right);
	}
}

非递归遍历算法
使用堆栈

void InOrderTraversal(BinTree BT)
{
	BinTree T = BT;
	Stack S = CreatStack(MaxSize); //创建初始化堆栈s
	while (T || !IsEmpty(s)) {
		while (T) {// 一直向左并且将沿途的结点压入堆栈
			Push(S, T);
			T = T->Left;
		}
		if (!IsEmpty(s)) {
			T = Pop(s); // 结点弹出堆栈
			printf("%5d", T->Data);// 打印结点
			T = T->Right;// 转向右子树
		}
	}
}

给出下面这棵树的中序遍历结果:
MOOC浙大数据结构-二叉树的遍历_第1张图片
答:bdaec

后序遍历

遍历过程:

  1. 中序遍历其左子树
  2. 中序遍历其右子树
  3. 访问根节点
void InOrderTraversal(BinTree BT)
{
	if (BT) {
		InOrderTraversal(BT->Left);
		InOrderTraversal(BT->Right);
		printf("%d", BT->Data);
	}
}

非递归遍历算法
使用堆栈
后序遍历也可以使用非递归遍历算法来实现,但不能像前序和中序一样简单的调一下输出语句就可以实现,因为后序遍历需要先访问完左右结点才输出根节点。
需要在结构中定义个标识

void InOrderTraversal(BinTree BT)
{
	BinTree T = BT;
	Stack S = CreatStack(MaxSize); //创建初始化堆栈s
	while (T || !IsEmpty(s)) {
		while (T) {// 一直向左并且将沿途的结点压入堆栈
			Push(S, T);
			T->Tag=1;// 标记为1
			T = T->Left;
		}
		if (!IsEmpty(s)) {
			T = Pop(s); // 结点弹出堆栈
			if(T->Tag=1){
				(T->Tag)++;
				printf("%5d", T->Data);// 打印结点
				T = T->Right;// 转向右子树
			}else{
				printf("%5d", T->Data);// 打印结点
			}
		}
	}
}

层序遍历

二叉树遍历的核心问题:二维结构的线性化

  • 从结点访问其左、右儿子结点
  • 访问左儿子后、右儿子怎么办?

所以需要一个存储结构来保存暂时不访问的结点,可以用堆栈、队列来存储
队列实现:
遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队、访问该结点、其左右儿子入队

遍历过程:

先根节点入队,然后:

  1. 从队列中取出一个元素;
  2. 访问该结点所指结点,
  3. 若该元素所指结点的左、右孩子结点非空,则将其左、右孩子的指针顺序入队
void LevelOrderTraversal(BinTree BT)
{
    Queue Q;BinTree T;
    if(!BT)return; // 空树直接返回
    Q=CreatQueue(MaxSize); // 创建队列
    AddQ(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);
    }
}

如果将层序遍历中的队列改为堆栈,是否也是一种树的遍历?可以应用这种方法改造出一种前序、中序、后序的非递归遍历吗?

上文已有解答。

遍历二叉树应用

输出二叉树中的叶子结点

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

求二叉树的高度

只要知道了左右子树的高度就可以知道二叉树的高度

void 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;
}

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

MOOC浙大数据结构-二叉树的遍历_第2张图片

两种遍历确定二叉树?

一定要有中序,没有中序会产生左右判断的问题

先序和中序遍历序列来确定一颗二叉树

  • 根据先序遍历序列第一个结点确定根结点
  • 根据根结点在中序遍历序列中分割出左右两个子序列
  • 左子树和右子树分别递归使用相同方法继续分解。

MOOC浙大数据结构-二叉树的遍历_第3张图片

你可能感兴趣的:(MOOC浙大数据结构,数据结构)