欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

树(2)

程序员文章站 2022-04-23 18:43:37
...

一:二叉树的遍历. 由于递归算法很简单,在这里就不例举了,主要看一下非递归算法(其实也就是用栈实现,因为递归本身就是一种栈) 1.先序遍历: 思想:(1)从根节点依次遍历当前节点的左子树,边遍历访问,并且压入栈 (2).再访问当前栈顶结点的右子树,然后再返回

一:二叉树的遍历.

由于递归算法很简单,在这里就不例举了,主要看一下非递归算法(其实也就是用栈实现,因为递归本身就是一种栈)

1.先序遍历:

思想:(1)从根节点依次遍历当前节点的左子树,边遍历访问,并且压入栈

(2).再访问当前栈顶结点的右子树,然后再返回到(1)执行,直至栈空

#define maxsize 100
typedef struct
{
    Bitree Elem[maxsize];
    int base,top;
}SqStack;

void PreOrderUnrec(Bitree t)
{
    SqStack s;
    StackInit(s);
    p=t;
    
    while (p!=null || !StackEmpty(s))
    {
        while (p!=null)             //遍历左子树
        {
            visite(p->data);
            push(s,p);
            p=p->lchild;       
        }//endwhile
        
        if (!StackEmpty(s))         //通过下一次循环中的内嵌while实现右子树遍历
        {
            p=pop(s);
            p=p->rchild;        
        }//endif                
    }//endwhile 
    
}//PreOrderUnrec
2.中序遍历:

思想:(1)从根节点遍历左子树,边遍历边入栈

(2)弹出栈顶元素,并访问,然后访问当前栈顶的右子树,回到(1)

#define maxsize 100
typedef struct
{
    Bitree Elem[maxsize];
    int base,top;
}SqStack;

void InOrderUnrec(Bitree t)
{
    SqStack s;
    StackInit(s);
    p=t;
    while (p!=null || !StackEmpty(s))
    {
        while (p!=null)             //遍历左子树
        {
            push(s,p);
            p=p->lchild;
        }//endwhile
        
        if (!StackEmpty(s))
        {
            p=pop(s);
            visite(p->data);        //访问根结点
            p=p->rchild;            //通过下一次循环实现右子树遍历
        }//endif   
    
    }//endwhile
}//InOrderUnrec

3.后序遍历(其实还不是特清楚,代码来自百度):(需要设置一个标志量表示当前节点的右子树是否被访问)

#define maxsize 100
typedef enum{L,R} tagtype;//标记的类型,为R时表示当前结点的
typedef struct 
{
    Bitree ptr;
    tagtype tag;
}stacknode;

typedef struct
{
    stacknode Elem[maxsize];
    int base,top;
}SqStack;

void PostOrderUnrec(Bitree t)
{ 
    SqStack s;
    stacknode x;
    StackInit(s);
    p=t;
    
    do 
    {
        while (p!=null)        //遍历左子树
        {
            x.ptr = p; 
            x.tag = L;         //标记为左子树
            push(s,x);
            p=p->lchild;
        }
    
        while (!StackEmpty(s) && s.Elem[s.top].tag==R)//如果
        {
            x = pop(s);
            p = x.ptr;
            visite(p->data);   //tag为R,表示右子树访问完毕,故访问根结点       
        }
        
        if (!StackEmpty(s))
        {
            s.Elem[s.top].tag =R;     //遍历右子树
            p=s.Elem[s.top].ptr->rchild;        
        }    
  }while (!StackEmpty(s));
}//PostOrderUnrec


二.线索二叉树:

含有n个结点的二叉树,一共有2n个指针域,有n+1个处于Null状态,为了使空间不浪费,可以让这些空的指针域指向二叉树各种遍历的前驱或后继结点,这样又可以方便查找每一个元素,而不必采用遍历,节省了时间

1.存储结构:

typedef enum { Link, Thread } PointerThr; 
    // Link==0:指针,Thread==1:线索
typedef struct BiThrNode{
    TElemType data;
    Struct BiThrNode *lchild, *rchild;    // 左右孩子指针
    PointerThr LTag, RTag;   // 左右标志,当LTag=Thread时,表示线索,为Link时表示指向下一结点
} BiThrNode, *BiThrTree;
树(2)

1)若结点有左子树,则lchild指向其左孩子;
否则, lchild指向其直接前驱(即线索);

2).若结点有右子树,则rchild指向其右孩子;

否则,rchild指向其后继(即线索);

例:

树(2)


2.线索二叉树的中序遍历算法:

Status IOTraver_T( BiThrTree T,Status (*Visit)(TElemType e) )
{ //T指向头结点,头结点的左链lchild指向根结点,中序遍历 //二叉线索树T的非递归算法,对每个数据元素调用函数Visit。
 p = T->lchild;  //p指向根结点     
 while (p != T) {     //空树或遍历结束时,p = = T
    while (p->LTag==Link) p = p->lchild;  
    if (!Visit(p->data)) return ERROR;  //访问其左子树为空的结点
    while (p->RTag==Thread && p->rchild!=T) 
       { p = p->rchild; Visit(p->data);  } //访问后继结点
    p = p->rchild; 
    }
 return OK;  
} // IOTraver_T

3.线索二叉树的生成算法:

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; }  //后继线索
        pre = p;                         // 保持pre指向p的前驱
      InThreading(p->rchild);      //右子树线索化
     }
  } // InThreading
Status InorderThreading(BiThrTree  & Thrt, BiThrTree  T)
{ //中序遍历二叉树T,并将其中序线索化, Thrt 指向头结点.
   if ( ! (Thrt = (BiThrTree) malloc ( sizeof (BiThrnode) ) )  exit  ( OVERFLOW ) ;
   Thrt ->LTag = Link;   Thrt ->RTag = Thead;   // 建头结点
   Thrt ->rchild = Thrt ;                                       //右指针回指
   if ( !T ) Thrt ->lchild = Thrt ;    // 若二叉树空,则左指针回指
   else {
             Thrt ->lchild = T;     pre = Thrt; //将头结点与树相连
             InThreading(T);          // 中序遍历进行中序线索化,调用上面的函数
             pre ->rchild = Thrt;   
             pre ->RTag = Thread;     //最后一个结点线索化
             Thrt ->rchild = pre;
            }
    return OK;
 } // InOrderThreading