二叉树遍历和线索二叉树大题复习(王道教材)(上)

文章目录


# 定义二叉树数据结构
typedef struct ThreadNode{
    ElemType data; //存放数据
    struct ThreadNode *lchild,*rchild; //左指针及右指针
    int ltag,rtag; //左右线索 ,=0表示指向孩子,=1表示指向线索
}ThreadNode, * ThreadTree;

一、编写后序遍历二叉树的非递归算法

1.1 思路

后序遍历顺序 :左 右 根。
思路:
利用栈,沿着根的左孩子依次入栈

p = p->lchild;

直到左孩子为空时 。读取栈顶元素

if(p == Null)
{
	GetTop(S,p);
}

看看元素是否有右孩子,如果有右孩子且没有被访问过的话使指针指向P的右孩子

if(p -> rchild && p->rchild != r) // r为标记
{
	p = p ->rchild
}

如果不存在右子树 或者右子树 已经被访问过了 就弹出栈顶元素并对它进行访问

else{
	pop(S,p);
	visit(p->data);
	r = p;
	p = NULL;
}

1.2总程序

void PostOrder(ThreadTree T)
{
    InitStack(S); //栈
    ThreadTree p = T;//指针P
    r = NULL;//指针标志
    while( p || !IsEmpty(S)) //指针非空并且栈不为空
        if(p){
            push(S,p);
            p = p->lchild; // 依次遍历左子树入栈
        }else{
            GetTop(S,p);
            if(p->rchild && p->rchild !=NULL) // 右子树存在未被访问
            {
                p = p ->rchild; //访问右子树
            }else {
                pop(S,p);
                visit(p->data);
                r = p;
                p = Null; //
            }
        }
}

二、试给出二叉树的自下而上,从右到左的层次遍历算法

2.1思路

思路:这里的顺序刚好与层次遍历的顺序相反,可以利用层次遍历所得到的结果依次入栈在出栈即可得到

层次遍历算法:

void levelOrder(ThreadTree T)
{
    InitQueue(Q);
    ThreadNode *p = T;
    EnQueue(Q,T); //将根结点入队
    while(!IsEmpty(Q))
    {
        DeQueue(Q,p); //出队
        visit(p);
        if(p ->lchild != NULL)
        {
            EnQueue(Q,p->lchild); //左孩子存在左孩子入队
        }
        if(p ->rchild != NULL)
        {
            EnQueue(Q,p->rchild);//右孩子存在右孩子入队
        }
    }
}

更改后:

2.2总程序

void levelOrder(ThreadTree T)
{
    InitQueue(Q);
    InitStack(S)
    ThreadNode *p = T;
    EnQueue(Q,T); //将根结点入队
    while(!IsEmpty(Q))
    {
        DeQueue(Q,p); //出队
        Push(S,p);
        visit(p);
        if(p ->lchild != NULL)
        {
            EnQueue(Q,p->lchild); //左孩子存在左孩子入队
        }
        if(p ->rchild != NULL)
        {
            EnQueue(Q,p->rchild);//右孩子存在右孩子入队
        }
    }
    while(IsEmpty(S))
    {
    	pop (S,p);
    	visit(p->data);
    	}
}

三、假设二叉树采用二叉链表存储结构,设计一个非递归算法求二叉树的高度

二叉链表存储结构表示

 typedef struct BiTNode{
 	ElemType data; // 数据域
 	struct BiTNode *lchild,*rchild; //左右孩子指针
 }BiTNode,*BiTree;

3.1 思路

思路:利用层次遍历一层一层记录,需要考虑的是什么时候让层数加一,做法是设置一个变量用来指向每一层的最右结点,另外设置两个变量,一个变量是每当入队时加一,另一个变量是每当出队时加一,当出队的变量与记录每一层右结点的变量相同时则可以说明这一层已经出队完成,于是让树高加一,并且让变量指向下一层的最右。(这里的最右就是靠入队时+1的变量提供,除了根节点时)

3.2总程序


int btdepth(ThreadTree T)
{
    if(!T) {
        return 0; //树空则返回0
    }
    int front , rear = -1; // 出队时 front ++ ,入队时 rear ++
    int last = 0,level = 0; //last 作用是记录 本层有多少个结点 level记录高度
    InitQueue(Q); 
    EnQueue(Q,T) //根结点入队
    rear ++;
    while(!IsEmpty(Q))
    {
        DeQueue(Q,p); //出队
        front++;
        if(p ->lchild != NULL)
        {
            EnQueue(Q,p->lchild); //左孩子存在左孩子入队
            rear ++;
        }
        if(p ->rchild != NULL)
        {
            EnQueue(Q,p->rchild);//右孩子存在右孩子入队
            rear ++;
        }
        if(front == last) //说明一层已经出队完成
        {
            level ++;
            last = rear; // 指向下一层;
        }
    }
    return level;
}




四、设一棵二叉树中各结点的值互不相同,其先序遍历序列和中序遍历序列分别存于两个一维数组A[1…N]和B[1…N]中,试编写算法建立该二叉树的二叉链表

4.1思路

从先序遍历我们可以知道该树的根结点,然后根据这个结点的值在B中寻找到该结点,就可以把B分为左子树及右子树,然后对算法进行递归,就可以得到最后的答案

4.2总程序

ThreadTree PreInCreat(ElemType A[],ElemType B[],int l1,int h1,int l2,int h2)
{
    // l1,h1分别为先序的第一个和最后一个元素的下标 
    // l2,h2分别为中序的第一个和最后一个元素的下标;
    ThreadNode *root = (ThreadNode *) malloc(sizeof(ThreadNode));
    root->data=A[l1];
    for(int i = l2;B[i]!=root->data;i++);
    llen = i - 12; //左子树长度
    rlen = h2 - i; //右子树长度
    if(llen)
        root->lchild = PreInCreat(A,B,l1+1,l1+len,l2,l2+llen-1); 
    //由于左子树的长度为llen,所以左子树的最后一个结点先序应该到 l1 + llen ,右子树的最后一个结点先序应该到 l2 - llen -1
    else
        root->lchild = NULL;
    if(rlen)
        root->rchild = PreInCreat(A,B,h1-rlen+1,h1,h2-rlen+1,h2);
    //同理
    else
        root->rchild = NULL;
}


五、二叉树按二叉链表形式存储,写一个判别给定二叉树是否是完全二叉树的算法

5.1思路

完全二叉树的概念 ,结点不能在没有左兄弟的情况下出现。利用层次遍历将结点加入队列,遇到空结点看后面是否有无结点,有结点则不是完全二叉树

5.2代码

bool IsComplete(ThreadTree T)
{
     InitQueue(Q);
     if(!T) {
         return true; //空树为满二叉树
     }
     EnQueue(Q,T);
     while(!IsEmpty(Q))
     {
         DeQueue(Q,p);
         if(p)
         {
             if(p ->lchild != NULL)
             {
                 EnQueue(Q,p->lchild); //左孩子存在左孩子入队
             }
             if(p ->rchild != NULL)
             {
                 EnQueue(Q,p->rchild);//右孩子存在右孩子入队
             }
         }else
         {
             while(!IsEmpty(Q)) //看是否后面有结点
             {
                 DeQueue(Q,p);
                 if(p)
                     return false;
             }
         }
     }
}

六、假设二叉树采用二叉链表存储结构存储,试设计一个算法,计算一颗给定二叉树的所有双分支结点的个数

6.1思路

利用层次遍历,设置两个标志位当出队时有左右孩子就将两个标志位置为1,在最后判断标志位是否等于1。

6.2代码

int DsonNodes(ThreadTree T)
{
    int ltag = 0,rtag=0;
    int count = 0;
    InitQueue(Q);
    EnQueue(T);//根结点入队
    while(!IsEmpty(Q))
    {
        DeQueue(Q,p);
        if(p ->lchild != NULL)
        {
            EnQueue(Q,p->lchild); //左孩子存在左孩子入队
            ltag = 1; //说明有左结点
        }
        if(p ->rchild != NULL)
        {
            EnQueue(Q,p->rchild);//右孩子存在右孩子入队
            rtag = 1;//说明有右结点
        }
        if(ltag == 1 && ltag == rtag)
        {
            count ++;
        }
        ltag = rtag = 0;
    }
}

七、设树B是一棵采用链式存储结构存储的二叉树,编写一个把B中所有结点的左、右子树进行交换的函数

7.1思路

采用递归算法,交换b结点的左孩子的左右子树,右孩子的左右子树,b结点的左右子树

7.2 总程序


void swap(ThreadTree T)
{
    if(T)
    {
        swap(T->lchild);
        swap(T->rchild);
        temp = b->lchild;
        b->lchild = b->rchild;
        b->rchild = temp;
    }
}


8、假设二叉树采用二叉链存储结构存储,设计一个算法,要求先序遍历序列中第k个结点的值

8.1 思路

递归找值

8.2总程序

ElemType PreNode(ThreadTree T,int K)
{
    if(T == NULL)
    {
        return '#'; // 空树返回
    }
    if(i == K)
    {
        return  T->data; //递归出口
    }
    i ++;
    ch = PreNode(T->lchild,K);
    if(ch!= '#')
    {
        return  ch;
    }
    ch = PreNode(T->rchild,K);
    return ch;
}

9.已知二叉树以二叉链表存储,编写算法完成,对于树中每个元素为x的结点,删除以它为根的子树,并释放相应的空间

9.1思路

删除结点使用递归算法,唯一要考虑的是删除结点的父结点的指向NULL
利用层次遍历记录父指针

9.2代码

void Search(ThreadTree T,ElemType x)
{
    ThreadNode Q[]; //建立存放二叉树,容量足够大
    if(T){
        if(T->data == x)
        {
            DeleteXTree(T);
            return;
        }
    }
    InitQueque(Q);
    EnQueue(Q,T);
    while(!IsEmpty(Q))
    {
        DeQueue(Q,p);
        if(p->lchild) //p左结点存在
        {
            if(p->lchild->data == x) //删除子树,置位空
            {
                DeleteXTree(p->lchild);
                p->lchild = NULL;
            }else{
                EnQueue(Q,p->lchild);
            }
        }
        if(p->rchild)
        {
            if(p->rchild->data == x)//同理 
            {
                DeleteXTree(p->rchild);
                p->rchild = NULL;
            }else{
                EnQueue(Q,p->rchild);
            }
        }
    }
}

十、在二叉树中查找值为x的结点,试编写算法(用C语言)打印为x的结点的所有祖先,假设值为X的结点不多于一个

10.1 思路

思路:利用后序遍历非递归算法,先沿着左子树访问,当访问完之后发现并未找到值,开始访问右子树,当也没有找到值时,退栈。当找到值,输出栈里元素

10.2 总程序

	typedef struct {
    ThreadTree t;
    int tag; //tag 表 O表示对左子树访问,1表示对右子树访问
};stack;
void Search(ThreadTree T,ElemType x)
{
    stack s[];
    top = 0;
    while(T != NULL || top > 0)
    {
        while(T != NULL && T->data !=x)
        {
            s[++top] = T;
            s[top].tag = 0;
            T = T->lchild;
        }
        if(T->data == x)
        {
            for(i =1;i < top;i++)
            {
                printf("%d",s[i].t->data)
                return 0;
            }
        }
        while(top!= 0 && s[top].tag == 1)
            top--;
        if(top!=0)
        {
            s[top].tag = 1;
            T = s[top].t->rchild;
        }
    }
}




  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值