【数据结构】树(下)

遍历二叉树

原理

二叉树的遍历是从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。

遍历方法

  • 前序遍历:先访问根结点,然后前序遍历左子树,再前序遍历右子树。
  • 中序遍历:先访问左子树,然后是根节点,最后是右子树。
  • 后序遍历:先访问左子树,然后是右子树,最后是根结点。
  • 层序遍历:从树的第一层即根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。

前序遍历算法

//二叉树前序遍历算法
void PreOrderTraverse (BiTree T){
  if(T == NULL) return;
  printf("%c",T->data);//显示结点数据,可以更改为其他对结点操作
  PreOrderTraverse(T->lchild);//先遍历左子树
  PreOrderTraverse(T->rchild);//再遍历右子树
}

中序遍历算法

//二叉树中序遍历算法
void InOrderTraverse(BiTree T){
  if(T == NULL) return;
  InOrderTraverse(T->lchild);//中序遍历左子树
  printf("%c",T->data);//显示结点数据,可更改为其他操作
  InOrderTraverse(T->rchild);//最后中序遍历右子树
}

后序遍历算法

//二叉树后序遍历算法
void PostOrderTraverse(BiTree T){
  if(T == NULL) return;
  PostOrderTraverse(T->lchild);//先后序遍历左子树
  PostOrderTraverse(T->rchild);//再后序遍历右子树
  printf("%c",T->data);//显示结点数据
}

二叉树的建立

//按前序输入二叉树中结点的值
//#表示空树,构造二叉链表表示二叉树T
void CreateBiTree(BiTree *T){
  TElemType ch;
  scanf("%c",&ch);
  if(ch=='#') *T=NULL;
  else{
    *T=(BiTree)malloc(sizeof(BiTNode));
    if(!*T) exit(OVERFLOW);
    (*T)->data=ch;//生成根结点
    CreateBiTree(&(*T)->lchild);//构造左子树
    CreateBiTree(&(*T)->rchild);//构造右子树
  }
}

线索二叉树

原理

指向前驱和后继的指针成为线索,加上线索的二叉链表成为线索链表,相应的二叉树就称为线索二叉树。
对二叉树以某种次序遍历使其变成线索二叉树的过程是线索化。

结构实现

二叉树线索存储结构定义代码:

//二叉树线索存储结构定义
typedef enum {Link,Thread} PointerTag;//Link==0表示指向左右孩子指针,Thread==1表示指向前序或后继的线索
typedef struct BiThrNode{//二叉线索存储结点结构
   TElemType data;//结点数据
   struct BiThrNode *lchild,*rchild;//左右孩子指针
   PointerTag LTag;//左右标志
   PointerTag RTag;
}BiThrNode,*BiThrTree;

线索化的过程就是在遍历的过程中修改空指针的过程。
中序遍历线索化的递归函数代码:

BiThrTree pre;//全局变量,始终指向刚刚访问过的结点
//中序遍历进行中序线索化
void InThreading(BiThrTree p){
  if(p){
    InThreading(p->lchild);//递归左子树线索化
    if(!p->lchild){
      p->LTag=Thread;//前驱线索
      p->lchild=pre;//左孩子指针指向前序
    }
    if(!pre->rchild){//前序没有右孩子
      pre->RTag=Thread;//后继线索
      pre->rchild=p;//前序右孩子指针指向后继(当前结点p)
    }
    pre=p;//保持pre指向p的前驱
    InThreading(p->rchild);//递归右子树线索化
  }
}

添加一个头结点后遍历的代码:

//T指向头结点,头结点左链lchild指向根结点,头结点右链rchild指向中序遍历的最后一个结点。中序遍历二叉线索链表表示的二叉树T
Status InOrderTraverse_Thr(BiThrTree T){
  BiThrTree p;
  p=T->lchild;//p指向根结点
  while(p != T){//空树或者遍历结束时,p==T
    while(p->LTag==Link)//当LTag==0时循环到中序序列第一个结点
      p=p->lchild;
      printf("%c",p->data);
      while(p->RTag==Thread && p->rchild!=T){
        p=p->rchild;
        printf("%c",p->data);
      }
      p=p->rchild;//p进至右子树根
  }
  return OK;
}

树、森林与二叉树的转换

树转换为二叉树

  • 加线。在所有兄弟结点之间加一条线
  • 去线。对树中每个结点,只保留它与第一个孩子结点的连线,删除它与其他孩子结点之间的连线。
  • 层次调整。注意第一个孩子是二叉树结点的左孩子,兄弟转换过来的孩子是结点的右孩子。

森林转换为二叉树

  • 把每个树转换为二叉树。
  • 第一棵树不动,从第二棵二叉树开始,依次把后一棵二叉树的根节点作为前一棵二叉树的根结点的右孩子,用线连接起来。

二叉树转换为树

  • 加线。若某结点的左孩子结点存在,就将左孩子的n个右孩子结点都作为此结点的孩子。将该结点与这些右孩子结点用线连接起来。
  • 去线。删除原二叉树中所有结点与其右孩子结点的连线。
  • 层次调整。

二叉树转换为森林

判断一棵二叉树能够转换成一棵树还是森林,就要看这可棵叉树的根结点有没有右孩子,有就是森林,没有就是一棵树。

  • 从根节点开始,若右孩子存在,则把与右孩子结点的连线删除,直到所有右孩子连线都删除为止,得到分离的二叉树。
  • 再将每棵分离的二叉树转换为树即可。

赫夫曼树及其应用

定义与原理

带权路径长度WPL最小的二叉树为赫夫曼树。

算法描述

  • 根据给定的n个权值构成n棵二叉树的集合F,其中每棵二叉树Ti中只有一个带权为wi根结点,左右子树均为空。
  • 在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左右子树上根结点的权值之和。
  • 在F中删除这两颗树,同时将新得到的二叉树加入F中。
  • 重复2和3步骤,直到F只含一棵树为止。
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值