二叉树表示法
P127页
/*
typedef struct BiTNode
{
    int        data;
     struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
*/

struct BiTNode
{
    int        data;
    struct BiTNode *lchild, *rchild;
};

typedef struct BiTNode BiTNode;
typedef struct BiTNode * BiTree;

树的三叉链表表示

 

//三叉链表
typedef struct TriTNode 
{
    int data;
    //左右孩子指针
    struct TriTNode *lchild, *rchild;
    struct TriTNode *parent;
}TriTNode, *TriTree;

双亲链表法
//双亲链表
#define MAX_TREE_SIZE 100
typedef struct BPTNode
{
    int data;
    int parentPosition; //指向双亲的指针 //数组下标
    char LRTag; //左右孩子标志域
}BPTNode;

typedef struct BPTree
{
    BPTNode nodes[100]; //因为节点之间是分散的,需要把节点存储到数组中
    int num_node;  //节点数目
    int root; //根结点的位置 //注意此域存储的是父亲节点在数组的下标
}BPTree;
//用这个数据结构能表达出一颗树,为什么?
4.4.3二叉树的遍历

 

二叉树编程实践
基本操作
typedef struct node{
   int  data; 
   struct node *lchild,*rchild;
} NODE;
NODE *root; 

DLR(NODE *root )
{  
    if (root) //非空二叉树
    {
printf(“%d”,root->data); //访问D
DLR(root->lchild); //递归遍历左子树
DLR(root->rchild); //递归遍历右子树
    }
}

中序遍历算法
LDR(NODE *root)
{ if(root !=NULL)
  {  LDR(root->lchild);
      printf(“%d”,root->data);
      LDR(root->rchild); 
  } }

后序遍历算法
LRD (NODE *root)
{if(root !=NULL) 
   {LRD(root->lchild);
     LRD(root->rchild);
     printf(“%d”,root->data); 
   } }

 

计算二叉树中叶子结点的数目
int sum = 0; //全局变量
DLR_CountLeafNum(NODE *root)//采用中序遍历的递归算法
{ 
   if ( root)  //非空二叉树条件,还可写成if(root !=NULL )
  {   if(!root->lchild&&!root->rchild)  //是叶子结点则统计并打印
      {   sum++;     printf("%d\n",root->data);  }
      DLR_CountLeafNum(root->lchild); //递归遍历左子树,直到叶子处;
      DLR_CountLeafNum(root->rchild);}//递归遍历右子树,直到叶子处;
  } return(0);  
}   
思想:    1)求根结点左子树的叶子结点个数,累计到sum中,求根结点右子树的叶子结点个数累计到sum中。
        2)若左子树还是树,重复步骤1;若右子树还是树,重复步骤1。
        3)全局变量转成函数参数
        4)按照先序、中序、后序方式计算叶子结点,
===》三种遍历的本质思想强化:访问结点的路径都是一样的,计算结点的时机不同。
求二叉树的深度
    思想:    1)求根结点左子树高度,根结点右子树高度,比较的子树最大高度,再+12)若左子树还是树,重复步骤1;若右子树还是树,重复步骤1。
完全Copy二叉树 
    思想:    1)malloc新结点,
2)拷贝左子树,拷贝右子树,让新结点连接左子树,右子树
3)若左子树还是树,重复步骤1、2;若右子树还是树,重复步骤1、2
树的非递归遍历(中序遍历)
中序 遍历的几种情况
分析1:什么时候访问根、什么时候访问左子树、什么访问右子树
       当左子树为空或者左子树已经访问完毕以后,再访问根
       访问完毕根以后,再访问右子树。
分析2:非递归遍历树,访问结点时,为什么是栈,而不是其他模型(比如说是队列)。
        先走到的后访问、后走到的先访问,显然是栈结构
分析3:结点所有路径情况
步骤1:
如果结点有左子树,该结点入栈;
如果结点没有左子树,访问该结点;
步骤2:
如果结点有右子树,重复步骤1;
如果结点没有右子树(结点访问完毕),根据栈顶指示回退,访问栈顶元素,并访问右子树,重复步骤1
如果栈为空,表示遍历结束。 
注意:入栈的结点表示,本身没有被访问过,同时右子树也没有被访问过。
分析4:有一个一直往左走入栈的操作,中序遍历的起点

 

3、#号法编程实践
利用前序遍历来建树(结点值陆续从键盘输入,用DLR为宜)
Bintree createBTpre( )
{      
Bintree T; 
char ch;
        scanf(“%c”,&ch);
        if(ch==’#’) 
T=NULL; 
        else
        {   T=( Bintree )malloc(sizeof(BinTNode));
            T->data=ch;
            T->lchild=createBTpre(); 
            T->rchild=createBTpre();
        }        
        return T;
}

//后序遍历销毁一个树
void  BiTree_Free(BiTNode* T)
{
    BiTNode *tmp = NULL;
    if (T!= NULL)
    {
        if (T->rchild != NULL) BiTree_Free(T->rchild);
        if (T->lchild != NULL) BiTree_Free(T->lchild);
        if (T != NULL)
        {
            free(T); 
            T = NULL;
        }
    }
}