二叉树

二叉树是一种树型结构,二叉树的特点是每个节点最多可以有两棵子树。并且,二叉树的两棵子树有左右之分,其次序不能颠倒。二叉树有下面三条性质:

性质1:在二叉树的第i层上最多可以有2^(i-1)个节点。

性质2:深度为k的二叉树最多可以有2^k-1个节点。

性质3:对于一棵二叉树,如果叶子节点数为m,度为2的节点数为n,那么m = n + 1。

下面这个图描述了一棵简单的二叉树。


由于二叉树中每个节点可以有两个子节点,因此二叉树不是一种线性结构。为了方便起见,通常用链式结构表示二叉树中的节点。二叉树中的节点可以用下面的数据结构定义:

typedef struct bitnode {
        int data;
        struct bitnode *lchild; 
        struct bitnode *rchild;
}bitnode, *bitree;

二叉树遍历是二叉树中的基本操作,按照节点访问顺序不同,可以分为四种方式:

先序遍历:  (1)访问根节点;(2)先序遍历左子树;(3)先序遍历又子树。

中序遍历:  (1)中序遍历左子树;(2)访问根节点;(3)中序遍历又子树。

后续遍历:  (1)后续遍历左子树;(2)后续遍历又子树;(3)访问根节点。

层次遍历:  按照节点在二叉树中的层次从上到下从左到右访问各个节点。

上面这个例子中,各种遍历方式的结果如下:

先序遍历:  5, 8, 12, 1, 6, 9, 20, 11, 17

中序遍历:  12, 8, 6, 1, 9, 5, 11, 17, 20

后续遍历:  12, 6, 9, 1, 8, 17, 11, 20, 5

层次遍历:  5, 8, 20, 12, 1, 11, 6, 9, 17


在对二叉树进行遍历前,我们首先需要先构造一棵二叉树,二叉树可以采用递归方法进行构造,方法如下:

void createbitree(bitnode **t)
{
        int ch;
        scanf("%d", &ch);
        if (ch == 0)
                *t = NULL;
        else {
                *t = (bitree)malloc(sizeof(bitnode));
                if (*t == NULL)
                        return;
                (*t)->data = ch;
                createbitree(&((*t)->lchild));
                createbitree(&((*t)->rchild));
        }
        return;
}

按照程序设计方法不同,二叉树遍历又可以分为递归算法和非递归算法两种。递归算法比较简单,逻辑非常清晰,代码如下:

// 先序遍历递归算法
void preorder(bitree t, void (*visit)(bitree node))
{
        if (t) {
                visit(t);
                preorder(t->lchild, visit);
                preorder(t->rchild, visit);
        }
}

// 中序遍历递归算法
void inorder(bitree t, void (*visit)(bitree node))
{
        if (t) {
                inorder(t->lchild, visit);
                visit(t);
                inorder(t->rchild, visit);
        }
}

// 后续遍历递归算法
void postorder(bitree t, void (*visit)(bitree node))
{
        if (t) {
                postorder(t->lchild, visit);
                postorder(t->rchild, visit);
                visit(t);
        }
}

与递归算法 相比,非递归算法的逻辑有些复杂,非递归算法借助堆栈实现了二叉树的遍历过程。理解非递归算法的关键是理解各个节点入栈、出栈的顺序。

先序遍历非递归算法

void preordernorec(bitree t, void (*visit)(bitree node))
{
        bitree queue[100];
        bitree p;
        int index = 0;

        if (t != NULL) {
                queue[index++] = t;
                while (index != 0) {
                        p = queue[--index];
                        visit(p);
                        if (p->rchild != NULL) {
                                queue[index++] = p->rchild;
                        }
                        if (p->lchild != NULL) {
                                queue[index++] = p->lchild;
                        }
                }
        }
}

中序遍历非递归算法
void inordernorec(bitree t, void (*visit)(bitree node))
{
        bitree queue[100];
        bitree p;
        int index = 0;

        while ((t!= NULL) ||(index != 0)) {
                if (t != NULL) {
                        queue[index++] = t;
                        t = t->lchild;
                } else {
                        p = queue[--index];
                        visit(p);
                        t = p->rchild;
                }
        }

}

后续遍历非递归算法

void postordernorec(bitree t, void (*visit)(bitree node))
{
        bitree queue1[100];
        bitree queue2[100];
        bitree p;
        int index1 = 0;
        int index2 = 0;

        if (t != NULL) {
                queue1[index1++] = t;
                while (index1 != 0) {
                        p = queue1[--index1];
                        queue2[index2++] = p;
                        if (p->lchild != NULL)
                                queue1[index1++] = p->lchild;
                        if (p->rchild != NULL)
                                queue1[index1++] = p->rchild;
                }

                for (index1 = index2 - 1; index1 >=0; index1--)
                        visit(queue2[index1]);
        }
}

层次遍历二叉树

void levelorder(bitree t, void (*visit)(bitree node))
{
        bitree queue[100];
        bitree p;
        int front = 0;
        int rear = 0;

        if (t != NULL) {
                queue[rear++] = t;
                while (front != rear) {
                        p = queue[front++];
                        visit(p);
                        if (p->lchild != NULL)
                                queue[rear++] = p->lchild;
                        if (p->rchild != NULL)
                                queue[rear++] = p->rchild;
                }
        }
}

测试程序

void visit(bitree node)
{
        printf("%d ", node->data);
}

int main(int argc, char *argv[])
{
        bitree t;

        createbitree(&t);
        printf("pre order: ");
        preorder(t, visit);
        printf("\npre order no rec: ");
        preordernorec(t, visit);

        printf("\n\nin order: ");
        inorder(t, visit);
        printf("\nin order no rec: ");
        inordernorec(t, visit);

        printf("\n\npost order: ");
        postorder(t, visit);
        printf("\npost order no rec: ");
        postordernorec(t, visit);

        printf("\n\nlevel order: ");
        levelorder(t, visit);
        printf("\n");

        return 0;
}
输出结果如下:

pre order: 5 8 12 1 6 9 20 11 17 
pre order no rec: 5 8 12 1 6 9 20 11 17 

in order: 12 8 6 1 9 5 11 17 20 
in order no rec: 12 8 6 1 9 5 11 17 20 

post order: 12 6 9 1 8 17 11 20 5 
post order no rec: 12 6 9 1 8 17 11 20 5 

level order: 5 8 20 12 1 11 6 9 17


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值