二叉树的先序遍历、中序遍历、后序遍历、层序遍历

声明与定义

typedef char ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode
{
    ElementType Data;
    BinTree Left;
    BinTree Right;
};

中、先、后序遍历

void InorderTraversal(BinTree BT)
{
    if (BT)
    {
        InorderTraversal(BT->Left);
        printf(" %c", BT->Data);
        InorderTraversal(BT->Right);
    }
}
void PreorderTraversal(BinTree BT)
{
    if (BT)
    {
        printf(" %c", BT->Data);
        PreorderTraversal(BT->Left);
        PreorderTraversal(BT->Right);
    }
}
void PostorderTraversal(BinTree BT)
{
    if (BT)
    {
        PostorderTraversal(BT->Left);
        PostorderTraversal(BT->Right);
        printf(" %c", BT->Data);
    }
}

回顾

为啥说树结构简单,其实不是容易理解,而是容易写代码,哪怕我真的一点也不懂。 

层序遍历

C++版

void LevelorderTraversal(BinTree BT)
{
    queue<BinTree> q;
    q.push(BT);
    while (!q.empty())
    {
        printf(" %c", q.front()->Data);
        if (q.front()->Left)
            q.push(q.front()->Left);
        if (q.front()->Right)
            q.push(q.front()->Right);
        q.pop();
    }
}

回顾

因为c++中的stl有现成的队列可以直接使用,所以毫不犹豫的使用了queue。

需要注意的是,队列里面存放的元素类型是二叉树指针(可以理解成放的是一整个结点,而不是结点所对应的数据值)。

一开始先把根节点放入队列中,然后进入while循环,循环退出条件是队列为空(队列里面放的是需要输出的元素,输出顺序即为队头到队尾的顺序)。

每一个循环分为三个操作,第一个操作是,假若队头元素的左、右儿子非空,那么入队;第二个操作是,输出队头元素的数据值;第三个操作是,让队头元素出队。

C语言版

顺序队列

void LevelorderTraversal(BinTree BT)
{
    BinTree array[50];
    for (int i = 0; i < 50; i++)
        array[i] = NULL;
    int in = 0, out = 0;
    array[in++] = BT;
    while (in > out)
    {
        if (array[out])
        {
            printf(" %c", array[out]->Data);
            if (array[out]->Left)
                array[in++] = array[out]->Left;
            if (array[out]->Right)
                array[in++] = array[out]->Right;
        }
        out++;
    }
}

回顾

变量in可以理解为rear,变量out可以理解为front。( 动作 <-> 队列 ) 

数组元素千万不能是ElementType,一定要是指向结点的指针。

特殊情况 -> 树为空树的情况:仍然会进while,但是进去并不做什么,而且只进了一次。

每次入队的结点都是出队结点的儿子结点。

 循环队列

void LevelorderTraversal(BinTree BT)
{
    BinTree array[10];
    for (int i = 0; i < 10; i++)
        array[i] = NULL;
    int rear = 0, front = 0;
    array[rear++] = BT;
    while (rear != front)
    {
        if (array[front])
        {
            printf(" %c", array[front]->Data);
            if (array[front]->Left)
            {
                array[rear] = array[front]->Left;
                rear = (rear + 1) % 10;
            }
            if (array[front]->Right)
            {
                array[rear] = array[front]->Right;
                rear = (rear + 1) % 10;
            }
        }
        front = (front + 1) % 10;
    }
}
void LevelorderTraversal(BinTree BT)
{
    BinTree array[10];
    for (int i = 0; i < 10; i++)
        array[i] = NULL;
    int rear = 0, front = 0, len = 0;
    array[rear++] = BT;
    if (BT)
        len++;
    while (len)
    {
        if (array[front])
        {
            printf(" %c", array[front]->Data);
            len--;
            if (array[front]->Left)
            {
                array[rear] = array[front]->Left;
                rear = (rear + 1) % 10;
                len++;
            }
            if (array[front]->Right)
            {
                array[rear] = array[front]->Right;
                rear = (rear + 1) % 10;
                len++;
            }
        }
        front = (front + 1) % 10;
    }
}
void LevelorderTraversal(BinTree BT)
{
    BinTree array[10];
    for (int i = 0; i < 10; i++)
        array[i] = NULL;
    int rear = 0, front = 0, tag = 0;
    array[rear++] = BT;
    if (BT)
        tag = 1;
    while (rear != front || tag != 0)
    {
        if (array[front])
        {
            printf(" %c", array[front]->Data);
            tag = 0;
            if (array[front]->Left)
            {
                array[rear] = array[front]->Left;
                rear = (rear + 1) % 10;
                tag = 1;
            }
            if (array[front]->Right)
            {
                array[rear] = array[front]->Right;
                rear = (rear + 1) % 10;
                tag = 1;
            }
        }
        front = (front + 1) % 10;
    }
}

回顾:

循环队列解决假溢出现象的三种方法:(分别对应上面三段代码)

1)预留一个空间不存数值。空:rear==front ;满:(rear+1)% MAXQSIEZ == front。

(注:这里的一个空间不是指固定的某一个空间,确切地说是front指针所指位置的前一个空间始终不存元素,即始终为空)

2)设置len变量记录队列长度。空:len==0;满:len==MAXQSIZE。

(注:每次入队操作完成的时候,len++;每次出队操作完成的时候,len++)

3)设置tag变量。空:rear==front && tag==0;满:rear==front && tag==1。

(注:每次入队操作完成的时候,tag值改为1;每次出队操作完成的时候,tag值改为0)

二叉树的层序遍历用不上判满,因为如果队列满的话,那就遍历失败了。

方法二和方法三需要特别关注树为空树的情况,如果没有考虑到,则会进入死循环。

对比

循环队列好在哪?节省空间,解决了假溢出问题。

顺序队列不好在哪?浪费资源,出现假溢出现象。

同样的一棵树,我们如果事先评估,那么在设置数组容量时,循环队列这种数据结构可以为我们剩下很大的空间。

 指针数组

指针一般初始化成NULL;指针数组也一样初始化成NULL。

这样可以判断指针如果NULL,则该指针可以分配;如果不等于NULL,则说明指针已经指向某一变量。

一般在用完了指针,收回了分配的内存,比如delete/free以后,也要及时将指针赋值为NULL,便于再次使用。

为了安全合法的使用指针数组,避免访问到其他预期不到的内存,我们必须对指针数组进行初始化。

二叉树的非递归遍历 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

罗马尼亚硬拉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值