数据结构之树:先序遍历二叉树(C & Python)

1   先序遍历

二叉树先序遍历的实现思想是:

  1. 访问根节点
  2. 访问当前节点的左子树
  3. 若当前节点无左子树,则访问当前节点的右子树

以上图 为例,采用先序遍历的思想遍历该二叉树的过程为:

  1. 访问该二叉树的根节点,找到 节点1
  2. 访问节点 1 的左子树,找到节点 2
  3. 访问节点 2 的左子树,找到节点 4
  4. 由于访问节点 4 左子树失败,且也没有右子树,因此以节点 4 为根节点的子树遍历完成,但节点 2 还没有遍历其右子树,因此现在开始遍历,即访问节点 5
  5. 由于节点 5 无左右子树,因此节点 5 遍历完成,并且由此以节点 2 为根节点的子树也遍历完成,现在回到节点 1 ,并开始遍历该节点的右子树,即访问节点 3
  6. 访问节点 3 左子树,找到节点 6
  7. 由于节点 6 无左右子树,因此节点 6 遍历完成,回到节点 3 并遍历其右子树,找到节点 7
  8. 节点 7 无左右子树,因此以节点 3 为根节点的子树遍历完成,同时回归节点 1,由于节点 1 的左右子树全部遍历完成,因此整个二叉树遍历完成

 因此,上图中二叉树采用先序遍历得到的序列为:1 2 4 5 3 6 7

2   算法设计

算法1:

  1. 根结点入栈并访问根结点
  2. 栈顶结点设为当前结点,找到结点的左孩子,左孩子为空则进入操作4,左孩子不为空则访问左孩子并将其入栈,同时将结点左孩子置空,代表已访问结点左孩子
  3. 重复操作2
  4. 栈顶结点设为当前结点,找到结点的右孩子,右孩子不为空则进入操作6,右孩子为空则代表子树遍历结束,弹出栈顶结点,栈空则遍历结束
  5. 重复操作4
  6. 访问右孩子并将其入栈
  7. 重复操作2

算法2:

  1. 根结点入栈
  2. 弹出栈顶结点并将其设为当前结点,栈空则遍历结束
  3. 访问结点并找到结点的右孩子,右孩子不为空则将右孩子入栈,左孩子设为当前结点
  4. 结点不为空进入操作3,结点为空进入操作2

3   C语言实现算法1

代码:

'''C

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>

#define STACK_INITSIZE 100
#define STACK_INCREMENT 10

//******************************************************************
//                         创建树
//******************************************************************

//树结点结构体
typedef struct node
{
    int data;
    struct node *lchild, *rchild;
}BiNode, *BiTree;

//创建一个简单的树,返回树的根结点指针
BiTree createBiTree()
{
    BiTree T=(BiNode *)malloc(sizeof(BiNode));
    T->data=1;
    T->lchild=(BiNode *)malloc(sizeof(BiNode));
    T->rchild=(BiNode *)malloc(sizeof(BiNode)); 
    T->lchild->data=2;
    T->lchild->lchild=(BiNode *)malloc(sizeof(BiNode));
    T->lchild->rchild=(BiNode *)malloc(sizeof(BiNode));
    T->lchild->rchild->data=5;
    T->lchild->rchild->lchild=NULL;
    T->lchild->rchild->rchild=NULL;
    T->rchild->data=3;
    T->rchild->lchild=(BiNode *)malloc(sizeof(BiNode));
    T->rchild->lchild->data=6;
    T->rchild->lchild->lchild=NULL;
    T->rchild->lchild->rchild=NULL;
    T->rchild->rchild=(BiNode *)malloc(sizeof(BiNode));
    T->rchild->rchild->data=7;
    T->rchild->rchild->lchild=NULL;
    T->rchild->rchild->rchild=NULL;
    T->lchild->lchild->data=4;
    T->lchild->lchild->lchild=NULL;
    T->lchild->lchild->rchild=NULL;
    return T;
}


//****************************************************************
//                            创建栈
//****************************************************************

//栈结构体
typedef struct 
{
    BiNode *base;
    BiNode *top;
    int size;
}BiStack;

//栈初始化
BiStack stackInit()
{
    BiStack s;
    s.base = (BiNode *)malloc(sizeof(BiNode)*STACK_INITSIZE);
    s.top = s.base;
    s.size =STACK_INITSIZE;
    return s;
}

//入栈
void push(BiStack *s, BiNode e)
{
    if(s->top - s->base >= s->size)
    {
        s->size += STACK_INCREMENT;
        s->base = (BiNode *)realloc(s->base, sizeof(BiNode)*s->size);
    }
    *s->top = e;
    s->top++;
}

//出栈
BiNode pop(BiStack *s)
{
    BiNode temp;
    s->top--;
    temp = *s->top;
    return temp;
}

//得到栈顶元素,但不出栈
BiNode getTop(BiStack s)
{
    BiNode temp;
    s.top--;
    temp = *s.top;
    return temp;
}



//*********************************************************************
//                     使用栈结构先序遍历二叉树
//*********************************************************************

int time = 0;    //记录访问结点次数
//访问结点
void visitNode(BiNode *root)
{
    time++;
    printf("第%d次访问的结点是:%d\n", time, root->data);
}

int cnt = 0;     //记录栈变化次数
int stack[20][20];     //记录栈每次改变时栈中结点的数据
//遍历栈中结点
void traverseStack(BiStack s)
{ 
    int i = 0;
    while(s.base != s.top)
    {
        stack[cnt][i] = s.base->data;
        i++;
        s.base++;
    }
    stack[cnt][i] = 0XFFFFFFFF;
    cnt++;
}

//先序遍历二叉树
void preTraverse(BiTree T)
{  
    BiStack bs = stackInit();
    traverseStack(bs);
    BiNode root = *T;  
    BiNode *temp = NULL;
    push(&bs, root);      //根结点入栈
    traverseStack(bs);
    visitNode(&root);
    while(bs.top != bs.base)      //栈空表示遍历结束
    {
        root = getTop(bs);
        temp = root.lchild;       //先访问左孩子
        while(temp != NULL)       //左孩子不为空
        {
            //将结点左孩子设为空,代表已访问其左孩子
            root.lchild = NULL;
            pop(&bs);            
            push(&bs, root);

            //左孩子入栈
            root = *temp;
            temp = root.lchild;
            push(&bs, root);
            traverseStack(bs);
            visitNode(&root);
        }
        temp = root.rchild;     //后访问右孩子     
        while(temp == NULL)     //右孩子为空,代表左右孩子均已访问,结点可以出栈 
        {
            //结点出栈
            pop(&bs);
            traverseStack(bs);
            if(bs.top == bs.base) break;    //根结点出栈,遍历结束

            //查看上一级结点是否访问完左右孩子  
            root = getTop(bs);
            temp = root.rchild;           
        }
        if(bs.top != bs.base)
        {
            //将结点右孩子设为空,代表已访问其右孩子
            root.rchild = NULL;       
            pop(&bs);
            push(&bs, root);

            //右孩子入栈
            root = *temp;      
            push(&bs, root);
            traverseStack(bs);
            visitNode(&root);  
        }    
    }
}



//************************************************************************************
//                                     主函数
//************************************************************************************

void main()
{
    BiTree Tree = createBiTree();
    printf("\n二叉树先序遍历结果如下\n");
    preTraverse(Tree);

    printf("\n\n栈中结点变化情况如下\n");
    for(int i = 0; i < cnt; i++)
    {
        printf("栈中的结点有:");
        int j = 0;
        while(stack[i][j] != 0XFFFFFFFF)
        {
            printf("%d ", stack[i][j]);
            j++;
        }
        printf("\n");
    }
    printf("\n\n");
    system("date /T");
    system("TIME /T");
    system("pause");
    exit(0);  
}

运行结果:

4    Python实现算法1

代码:

import datetime
import time

##################################################################################
#                                     二叉树
##################################################################################

#树结点类      
class BiNode():
    #创建结点,左右孩子为空
    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None
    
    #创建左右孩子结点    
    def creat(self, data1=0XFFFFFFFF, data2=0XFFFFFFFF):
        if data1 != 0XFFFFFFFF:
            self.lchild = BiNode(data1)
        if data2 != 0XFFFFFFFF:
            self.rchild = BiNode(data2)
            
        
#创建一棵简单的二叉树
def creatTree():
    T = BiNode(1)
    T.creat(2, 3)
    T.lchild.creat(4, 5)
    T.rchild.creat(6, 7)
    return T
    

#############################################################################################
#                                       栈
#############################################################################################

#栈类
class Stack():
    def __init__(self):
        self.bs = []

    def push(self, e):
        self.bs.append(e)
        
    def pop(self):
        if self.bs:
            return self.bs.pop()
        else:
            raise LookupError("stack is empty!")

    def getTop(self):
        return self.bs[-1]


####################################################################################
#                         使用栈结构先序遍历二叉树
####################################################################################

time = 0              #记录访问结点次数
#访问结点的操作 
def visitNode(node):
    global time       #将time设为全局变量
    time += 1
    print("第{}次访问的结点是:{}".format(time, node.data))

stackList = []        #记录栈中元素,列表的每个元素也为列表
#遍历栈,栈中结点的数据存储在stackList中
def traverseStack(treeStack):
    global stackList
    temp = []
    for i in range(len(treeStack.bs)):
        temp.append(treeStack.bs[i].data)
    stackList.append(temp)

#先序遍历二叉树        
def preTraverse(T):
    treeStack = Stack()
    traverseStack(treeStack)
    treeStack.push(T)
    traverseStack(treeStack)
    visitNode(T)
    while treeStack.bs != []:        #栈空代表遍历结束
        root = treeStack.getTop()
        temp = root.lchild
        while temp != None:
            #左孩子入栈          
            treeStack.push(temp)
            traverseStack(treeStack)
            visitNode(temp)           
            #将结点左孩子设为空,代表已访问其左孩子
            root.lchild = None
            root = temp
            temp = root.lchild
        temp = root.rchild            #后访问右孩子
        while temp == None:           #右孩子为空,代表左右孩子均已访问,结点可以出栈
            treeStack.pop()           #结点出栈
            traverseStack(treeStack)
            if treeStack.bs == []:    #根结点出栈,遍历结束
                break
            #查看上一级结点是否访问完左右孩子
            root = treeStack.getTop()
            temp = root.rchild
        if treeStack.bs != []:
            treeStack.push(temp)       #右孩子入栈
            traverseStack(treeStack)
            visitNode(temp)
            root.rchild = None         #将结点右孩子设为空,代表已访问其右孩子  

        
        
if __name__ == '__main__':
    T = creatTree()
    print("\n二叉树先序遍历结果如下")
    preTraverse(T)
    print("\n栈中结点变化情况如下")
    for i in range(len(stackList)):
        print("栈中的结点有:{}".format(stackList[i]))
    print("\n\n")
    datetime = datetime.datetime.now()
    print(datetime.strftime("%Y-%m-%d\n%H:%M:%S"))

运行结果:

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

观察者555

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值