数据结构——第三章树和二叉树:02二叉树

1.二叉树的存储结构:

(1)二叉树的顺序存储表示:

#define MAX_TREE_SIZE 100 //二叉树的最大结点数

typedef TElemType SqBiTree[MAX_TREE_SIZE]; 

SqBiTree bt;

(2)二叉树的链式存储表示:

①二叉链表:

typedef struct BiTNode //结点结构

{

  TElemType data;

  struct BiTNode *lchild, *rchild; //左右孩子指针

} BiTNode, *BiTree;

②三叉链表:如要找某个结点的父结点,在三叉链表中很容易实现,在二叉链表中则需从根指针出发一一查找。

typedef struct TriTNode //结点结构

{

  TElemType data;

  struct TriTNode *lchild, *rchild; //左右孩子指针

  struct TriTNode *parent; //双亲指针

} TriTNode, *TriTree;

2.若一个二叉树中含有n个结点,则它的二叉链表中必含有2n个指针域,其中必有n + 1个空的链域。

证明:分支数目B = n - 1,即非空的链域有n - 1个,空链域有2n - (n - 1) = n + 1个。

3.二叉树的遍历:顺着某一条搜索路径巡防二叉树中的结点,使得每个结点均被访问一次,而且仅被访问一次。对于二叉树可以有三条搜索路径:先上后下的按层次遍历;先左(子树)后右(子树)的遍历;先右子树后左子树的遍历。

(1)先左后右的遍历算法:递归操作

①先根遍历:若二叉树为空树,则空操作;否则,访问根结点->先序遍历左子树->先序遍历右子树。

先根遍历的递归算法描述:

void Preorder(BiTree T)

{

  if (T)

  {

    visit(T->data); //访问根结点

    Preorder(T->lchild); //遍历左子树

    Preorder(T->rchild); //遍历右子树

  }

}

先根遍历的非递归算法描述:

 

②中根遍历:若二叉树为空树,则空操作;否则,中序遍历左子树->访问根结点->中序遍历右子树。

中根遍历的递归算法描述:

void Inorder(BiTree T)

{

  if (T)

  {

    Inorder(T->lchild); //遍历左子树

    visit(T->data); //访问根结点    

    Inorder(T->rchild); //遍历右子树

  }

}

中根遍历的非递归算法描述:

void Inorder(BiTree T)

{

  InitStack(&S);

  p = T;

  while (p != NULL || !StackEmpty(S))

  {

    if (p != NULL) //p指针不空则进栈,p指向p的左子树

    {

      push(&S, p);

      p = p->lchild;

    } else //p指针为空则出栈,p指向p的右子树

    {

      pop(&S, p);

      visit(p->data);

      p = p->rchild; 

    }

  }

}

③后根遍历:若二叉树为空树,则空操作;否则,后序遍历左子树->后序遍历右子树->访问根结点。

后根遍历的递归算法描述:

void Postorder(BiTree T)

{

  if (T)

  {

    Postorder(T->lchild); //遍历左子树

    Postorder(T->rchild); //遍历右子树

    visit(T->data); //访问根结点    

  }

}

后根遍历的非递归算法描述:

 

4.根据先序遍历和中序遍历、中序遍历和后序遍历可以确定一棵二叉树,而根据先序遍历和后序遍历不能唯一确定一棵二叉树(原因是通过中序遍历可以划分出左右子树,先序遍历的根在左边,后序遍历的根在右边,无法划分出左右子树)。

5.统计二叉树中叶子结点个数(函数之间进行数据传递的三种方式):

(1)方法一:通过函数参数传递

void CountLeaf(BiTree T, int* count)

{

  if (T)

  {

    if ((!T->lchild) && (!T->rchild))

    {

      (*count)++; //叶子结点计数加1

    }

    CountLeaf(T->lchild, count);

    CountLeaf(T->rchild, count);

  }

}

(2)方法二:通过全局变量传递

int count = 0;

void CountLeaf(BiTree T)

{

  if (T)

  {

    CountLeaf(T->lchild);

    CountLeaf(T->rchild);

    if ((!T->lchild) && (!T->rchild))

    {

      count++;

    }

  }

}

(3)方法三:通过返回值传递

int CountLeaf(BiTree T)

{

  if (!T)

  {

    return 0;

  }

  if (!T->lchild && !T->rchild)

  {

    return 1;

  } else

  {

    leftCount = CountLeaf(T->lchild);

    rightCount = CountLeaf(T->rchild);

    return m + n;

  }

}

6.求二叉树的深度(后序遍历):从二叉树深度的定义可知,二叉树的深度应为其左、右子树深度的最大值加1。由此,需先分别求得左、右子树的深度,算法中访问结点的操作为:求得左、右子树深度的最大值,然后加1。

int Depth(BiTree T) //返回二叉树的深度

{

  if (!T)

  {

    return 0;

  } else

  {

    leftDepth = Depth(T->lchild);

    rightDepth = Depth(T->rchild);

    depth = 1 + (leftDepth > rightDepth) ? leftDepth : rightDepth; 

  }

  return depth;

}

7.按层次遍历二叉树: 

void levelOrder(BiTree T)

{

  InitQueue(Q); //建立工作队列

  EnQueue(Q, T); //将根结点入队

  while (!QueueEmpty(Q)) //队列不空则继续循环

  {

    DeQueue(Q, p); //将队列首元素出队

    visit(p); //访问出队元素

    if (p->lchild) //如果出队元素左子树不空,则将左子树入队

    {

      EnQueue(Q, p->lchild); 

    }

    if (p->rchild) //如果出队元素右子树不空,则将右子树入队

    {

      EnQueue(Q, p->rchild);

    }

  }

}

posted @ 2018-11-04 12:16  H36Phaeton  阅读(206)  评论(0编辑  收藏  举报