数据结构——二叉数的遍历

本文围绕二叉树展开,介绍了其定义,包括普通二叉树及满二叉树、完全二叉树等特殊类型。阐述了二叉树的性质,如叶子结点数与度为2的结点数关系等。还讲解了顺序和链式两种存储结构,以及先序、后序、中序和层次四种遍历方式及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树的定义

二叉树的定义

二叉树是一种特殊的树,最多只能有两棵子树,且子树有左右之分,不能颠倒

特殊的二叉树
  • 满二叉树
    • 一棵高度为h,且含有2h−12^h-12h1个结点的二叉树称为满二叉树,即树中的每层都含有最多的结点
    • 可对满二叉树自上而下,自左向右编号(根结点编号为1)
    • 对于编号为i的结点,若有双亲,则其双亲为⌊i/2⌋\lfloor i/2 \rfloori/2;若有左孩子,则左孩子为2i;若有右孩子,则右孩子为2i+1
  • 完全二叉树
    • 高度为h、有n个结点的二叉树,当且仅当其每个结点都与高度为h的满二叉树中编号1~n的结点一一对应时,称为完全二叉树

二叉树的性质

  • 非空二叉树上的叶子结点数等于度为2的结点数加1
  • 非空二叉树第kkk层上至多有2k−12^{k-1}2k1个结点
  • 高度为hhh的二叉树至多有2h−12^h-12h1个结点
  • 具有n个结点的完全二叉树的高度为⌈log⁡2(n+1)⌉\lceil \log_2(n+1) \rceillog2(n+1)⌉或者⌊log⁡2(n)⌋+1\lfloor \log_2(n) \rfloor+1log2(n)⌋+1

二叉树的存储结构

顺序存储结构
  • 存储在数组中
  • 适合存储完全二叉树或满二叉树
  • 编号与完全二叉树对应,可利用数组下标确定结点在二叉树中的位置
链式存储结构
typedef struct BiTNode{
	ElemType data;
	struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
  • 在含有n个结点的二叉链表中,含有n+1个空链域

二叉树的遍历

先序遍历
操作过程

若二叉树为空,则什么也不做,否则:

  1. 访问根节点
  2. 先序遍历左子树
  3. 先序遍历右子树
代码实现(递归)
void PreOrder(BiTree T){
	if(T != NULL){
		visit(T);
		PreOrder(T->lchild);
		PreOrder(T->rchild);
	}
}
代码实现(非递归)

版本一:调用栈相关函数,易理解

void PreOrder1(BiTree T){
	InitStack(S);
	BiTree p = T;
	while(p || !IsEmpty(S)){
		if(p){
			visit(p);
			Push(S, p);
			p = p->lchild;
		}else{
			Pop(S, p);
			p = p->rchild;
		}
	}
}

版本二:无调用

void PreOrder2(BiTree T){
    BiTree p;
    BiTNode *s_pre[MaxSize];
    int top = -1;
    if(T != NULL){
        p = T;
        while(top > -1 || p != NULL){
            while(p != NULL){
                printf("%d ", p->data);
                s_pre[++top] = p;
                p = p->lchild;
            }
            if(top > -1){
                p = s_pre[top--];
                p = p->rchild;
            }
        }
    }
    printf("\n");
}
后序遍历

若二叉树为空,则什么也不做,否则:

  1. 后序遍历左子树
  2. 后序遍历右子树
  3. 访问根节点
操作过程
代码实现(递归)
void PostOrder(BiTree T){
	if(T != NULL){
		PreOrder(T->lchild);
		PreOrder(T->rchild);
		visit(T);
	}
}
代码实现(非递归)
void PostOrder1(BiTree T){
	InitStack(S);
	p = T;
	r = NULL;	// 记录最近访问过的结点
	while(p || !IsEmpty(S)){
		if(p){
			Push(S, p);
			p = p->lchild;
		}else{
			GetTop(S, p);
			if(p->rchild && p->rchild != r){	// 若右子树存在且未被访问过
				p = p->rchild;
			}else{								// 否则,弹出根结点,并访问
				Pop(S, p);
				visit(p);
				r = p;
				p = NULL;			// 重置p指针
			}
		}
	}
}
中序遍历
操作过程

若二叉树为空,则什么也不做,否则:

  1. 后序遍历左子树
  2. 访问根节点
  3. 后序遍历右子树
代码实现(递归)
void InOrder(BiTree T){
	if(T != NULL){
		PreOrder(T->lchild);
		visit(T);
		PreOrder(T->rchild);
	}
}
代码实现(非递归)

版本一:调用栈相关函数,易理解

void InOrder1(BiTree T){
	InitStack(S);
	BiTree p = T;
	while(p || !IsEmpty(S)){
		if(p){
			Push(S, p);
			p = p->lchild;
		}else{
			Pop(S, p);
			visit(p);
			p = p->rchild;
		}
	}
}

版本二:无调用

void InOrder2(BiTree T){
    BiTree p;
    BiTNode *s_in[MaxSize];
    int top = -1;
    if(T != NULL){
        p = T;
        while(top>-1 || p != NULL){
            while(p != NULL){
                s_in[++top] = p;
                p = p->lchild;
            }
            if(top > -1){
                p = s_in[top--];
                printf("%d ", p->data);
                p = p->rchild;
            }
        }
    }
    printf("\n");
}
层次遍历
操作过程

若二叉树为空,则什么也不做,否则:

  1. 根结点入队
  2. 若队空,则结束遍历,否则重复第3步
  3. 队列中第一个结点出队,并访问,若其有左孩子,则左孩子入队,若其有有孩子,则右孩子入队,返回第2步
代码实现
void LevelOrder(BiTree T){
	InitQueue(Q);
	BiTree p;
	EnQueue(Q, T);
	while(!IsEmpty(Q)){
		DeQueue(Q, p);
		visit(p);
		if(p->lchild != NULL)
			EnQueue(Q, p->lchild);
		if(p->rchild != NULL)
			EnQueue(Q, p->rchild);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值