c语言/c++(数据结构篇) 之 二叉树的操作实例(5/7)

实验目的:

1. 掌握二叉链表存储结构和掌握二叉树中各种基本运算算法设计。

2. 掌握二叉树的各种遍历过程以及遍历算法设计。

实验内容

编程实现:

(1) 由如图1所示的二叉树创建对应的二叉链存储结构b,该二叉树的括号表示串为“A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”;

(2) 输出二叉树b;

(3) 输出‘H’结点的左、右孩子结点值;

(4) 输出二叉树b的高度;

(5) 编写先序、中序、后序遍历程序,输出该二叉树先序、中序、后序遍历结果;

(6) 编写程序统计该二叉树结点个数;

(7) 编写程序统计该二叉树叶子结点个数。

1 一颗二叉树

 程序代码:

#include <iostream>

#include <queue>

using namespace std;

const int N = 10010;

const int INF = -1; // 我们用一个常数来表示当前二叉树节点为空的情况

struct Node {

    int w; // 当前树节点的值

    int p; // 当前树节点的双亲所在数组下标

    int l; // 当前树节点的左子节点所在数组下标

    int r; // 当前树节点的右子节点所在数组下标

};

Node node[N];

// 按照前序遍历二叉树的顺序输入树节点

void input(int n) {

    cin >> node[n].w;

    if(node[n].w == INF) { // 输入 -1 代表当前节点所在子二叉树停止输入

        return ;

    }

    node[n].p = n / 2;

    node[n].l = n * 2;

    node[n].r = n * 2 + 1;

    input(n*2);

    input(n*2+1);

}

// 前序遍历二叉树

void preOrderParse(int n) {

    if(node[n].w == INF) {

        return ;

    }

    cout << node[n].w << " ";

    preOrderParse(node[n].l);

    preOrderParse(node[n].r);

}

// 中序遍历二叉树

void inOrderParse(int n) {

    if(node[n].w == INF) {

        return ;

    }

    inOrderParse(n*2);

    cout << node[n].w << " ";

    inOrderParse(n*2+1);

}

// 后续遍历二叉树

void postOrderParse(int n) {

    if(node[n].w == INF) {

        return ;

    }

    postOrderParse(n*2);

    postOrderParse(n*2+1);

    cout << node[n].w << " ";

}

void sequenceParse() {

    queue<int> que;

    int n = 1;

    que.push(1); // 插入根节点所在数组下标

    while(!que.empty()) {

        n = que.front();

        que.pop(); // 得到队头元素并且将队头元素出队列

        // 如果当前节点不为空,那么输出该节点,并且将该节点的左右子节点插入队尾

        if(node[n].w != INF) {

            cout << node[n].w << " ";

            que.push(node[n].l);

            que.push(node[n].r);

        }

    }

}

int main() {

    cout << "请以前序遍历的顺序输入二叉树,空节点输入 -1 :" << endl;

    input(1); // 从下标为 1 开始前序输入二叉树

    cout << "前序遍历:" << endl;

    preOrderParse(1);

    cout << endl << "中序遍历:" << endl;

    inOrderParse(1);

    cout << endl << "后序遍历:" << endl;

    postOrderParse(1);

    cout << endl << "层序遍历:" << endl;

    sequenceParse();

    return 0;

}

 程序测试及运行结果:

分析与讨论:

1.先序遍历的递归实现:

先序遍历的遍历顺序为根节点–>左孩子–>右孩子,所以往栈中放数时先放右孩子,在放左孩子(左右孩子都不为空的情况下)。根据栈的先进后出的性质,所以先打印左孩子再打印右孩子,但是有的人可能会有疑问,那根节点呢。根节点在往栈中放左右孩子的时候就已经打印完了,所以根节点肯定在左右孩子打印之前就打印完了。

这样打印顺序就为:根节点–>左孩子–>右孩子。

2.中序遍历:

如果当前节点不为空,就往栈中放入该节点,然后让指向该节点的指针指向该节点的左孩子。如果当前节点为空,就弹出栈顶的节点,打印。然后让指向该节点的指针指向该节点的右孩子

3.后序遍历

后序遍历的遍历顺序为左孩子–>右孩子–>根节点,将这个顺序倒过来:根节点–>右孩子–>左孩子。和前序遍历是不是很像呢。对:前序遍历的顺序:根节点–>左孩子–>右孩子。那么,实现后序遍历只需要先往栈中放根节点的左孩子,然后再放右孩子。那么打印的顺序就成了根节点–>右孩子–>左孩子。但是,我们先不着急打印,利用栈结构能够使一段序列逆序的性质,将第一个栈中的节点全部放到第2个栈中去,那么打印顺序就发生了逆序:左孩子–>右孩子–>根节点,正好是后序遍历的顺序。

猜你喜欢

转载自blog.csdn.net/qq_59819866/article/details/131451208