遍历定义:顺着某一条搜索路线巡防二叉树中的结点,使得到每个节点均被访问一次,而且仅被访问一次(又称周游)
访问的含义很广,可以是对结点作各种处理,
如:输出结点的信息、修该结点的数据值等,但要求这种访问不破坏原来的数据结构
遍历目的:得到树中所有结点的一个线性排列。
遍历用途:它是树结构插入、删除、修该、查找和排序运算的前提,是二叉树一切运算的基础和核心。
若二叉树为空,则返回空;否则
访问根节点
先序遍历左子树
先序遍历右子树
代码实现:
// 先序遍历
int PreOrderTraverse(BiTree T){
if(T == NULL){
return 0; // 空二叉树
}
else{
printf("%c\t",T->data); // 访问根结点
PreOrderTraverse(T->Lchild); // 递归遍历左子树
PreOrderTraverse(T->Rchild); // 递归遍历右子树
}
}
若二叉树为空,则返回空;否则
中序遍历左子树
访问根节点
中序遍历右子树
代码实现:
// 中序遍历
int InorderTraverse(BiTree T){
if(T == NULL){ // 空二叉树
return 0;
}
else{
InorderTraverse(T->Lchild); // 递归遍历左
printf("%c\t",T->data); // 访问根结点
InorderTraverse(T->Rchild); // 递归遍历右
}
}
若二叉树为空,则返回空操作;否则:
后续遍历左子树
后序遍历右子树
访问根节点
代码实现:
// 后序遍历
int PostOrderTraverse(BiTree T){
if(T == NULL){ // 空二叉树
return 0;
}
else{
PostOrderTraverse(T->Lchild); // 递归遍历左
PostOrderTraverse(T->Rchild); // 递归遍历右
printf("%c\t",T->data); // 访问根结点
}
}
若二叉树中各节点的值均不相同,则二叉树结点的先序序列、中序序列、后序序列都是唯一的
由二叉树的先序序列和中序序列,或由二叉树的后续序列和中序序列可以确定唯一 一颗二叉树
基本思想:
先建立一个栈
根结点进栈,遍历左子树
根结点出栈,输出根节点,遍历右子树。
typedef struct StackNode{
SElemType data;
struct StackNode *next;
}StackNode,*LinkStack;
// 1、栈的初始化
Status InitLinkStack(LinkStack &S){
S = NULL;
return OK;
}
// 2、链栈是否为空
Status LinkStackEmpty(LinkStack &S){
if(S == NULL){
return TRUE;
}else{
return FALSE;
}
}
// 3、 链栈的入栈
Status Push(LinkStack &S,SElemType e){
StackNode *p;
p = new StackNode;
p->data = e;
p->next = S;
S = p;
return OK;
}
// 4、链栈的出栈
Status Pop(LinkStack &S,SElemType e){
StackNode *p;
if(S == NULL){
return ERROR;
}
e = S->data;
p = S;
S = S->next;
delete p;
return OK;
}
// 构造一个二叉树
typedef struct BiNode{
SElemType data;
struct BiNode *Lchild;
struct BiNode *Rchild;
}BiNode,*BiTree;
// 中序遍历非递归
Status InOrderStraverse(BiTree T){
BiTree p,q;
LinkStack S;
InitLinkStack(S);
p = T;
while(p||!LinkStackEmpty(S)){
if(p){
Push(S,p->data);
p = p->Lchild;
}
else{
Pop(S,q->data);
printf("%c\t",p->data);
p = q->Rchild;
}
}
return OK;
}
基本思想:
使用一个队列
将根结点进队;
队不空时循环:从队列中出列一个结点*p,访问它;
若它有左孩子结点,将左孩子结点进队;
若它有右孩子结点,将右孩子结点进队;
# define OK 1
# define ERROR 0
# define MAXQSIZE 100
typedef char QElemType;
typedef int Status;
typedef struct {
QElemType data[MAXQSIZE];
int front;
int rear;
}SqQueue;
// 1、初始化
Status InitQueue(SqQueue &Q){
Q.front = 0;
Q.rear = 0;
return OK;
}
Status QueueEnpty(SqQueue &Q){
if(Q.front == Q.rear){
return 1;
}
else{
return 0;
}
}
// 2、循环队列入队
Status EnQueue(SqQueue &Q,QElemType e){
if((Q.rear+1)%MAXQSIZE == Q.front){ // 队满
return ERROR;
}
Q.data[Q.rear] = e; // 新元素加入队尾
Q.rear = (Q.rear+1)%MAXQSIZE; // 队尾指针+1
return OK;
}
// 3、出队
Status DeQueue(SqQueue &Q,QElemType e){
if(Q.front == Q.rear){
return ERROR; // 队空
}
e = Q.data[Q.front];
Q.front = (Q.front+1)%MAXQSIZE;
return OK;
}
// 构造一个二叉树
typedef struct BiNode{
QElemType data;
struct BiNode *Lchild;
struct BiNode *Rchild;
}BiNode,*BiTree;
// 二叉树的层次遍历算法
void LevelOrder(BiNode *b){
BiNode *p;
SqQueue qu;
InitQueue(qu); // 初始化队列
EnQueue(qu,b->data); // 根节点指针进入队列
while(!QueueEnpty(qu)){ // 队列不为空
DeQueue(qu,p->data); // 出队结点
printf("%c\t",p->data);
if(p->Lchild != NULL){
EnQueue(qu,p->Lchild->data); // 左孩子进队
}
if(p->Rchild != NULL){
EnQueue(qu,p->Rchild->data); // 右孩子进队
}
}
}
// 二叉树的创建
void CreateBiTree(BiTree &T){
char ch;
scanf("%c",&ch);
if(ch == '#'){
T = NULL;
}
else{
T = (BiTree )malloc(sizeof(BiNode));
if(!T){
exit(-1);
}
T->data = ch;
CreateBiTree(T->Lchild);
CreateBiTree(T->Rchild);
}
}
// 复制二叉树
int Copy(BiTree T,BiTree &newT){
if(T==NULL){ // 如果是空树,返回0
newT = NULL;
return 0;
}
else{
newT = new BiNode;
newT->data = T->data;
Copy(T->Lchild,newT->Lchild);
Copy(T->Rchild,newT->Rchild);
}
}
// 计算二叉树的深度
int Depth(BiTree T){
int m,n;
if(T==NULL){
return 0;
}
else{
m = Depth(T->Lchild);
n = Depth(T->Rchild);
if(m>n){
return (m+1);
}
else{
return (n+1);
}
}
}
// 计算结点总数
int NodeCount(BiTree T){
if(T == NULL){
return 0;
}
else{
return NodeCount(T->Lchild)+NodeCount(T->Rchild
)+1;
}
}
// 计算叶子节点数
int LeadCount(BiTree T){
if(T ==NULL){
return 0;
}
if(T->Lchild == NULL && T->Rchild == NULL){
return 1;
}
else{
return LeadCount(T->Lchild)+LeadCount(T->Rchild);
}
}
利用二叉链表中的空指针域:
如果某个结点的左孩子为空,则将空的左孩子指针域改为指向其前驱;
如果某个结点的右孩子为空,则将空的右孩子指针域改为指向其后继
这种改变指向的指针称为线索
加上了线索的二叉树称为线索二叉树
对二叉树按某种遍历次序使其变为线索二叉树的过程叫做线索化
对二叉链表中每个结点增设两个标志域Ltag 和 Rtag,并约定
Ltag = 0 Lchild 指向该节点的左孩子
Ltag = 1 Lchild 指向该节点的前驱
Rtag = 0 Rchild 指向该节点的右孩子
Rtag = 1 Rchild 指向该节点的后继