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个栈中去,那么打印顺序就发生了逆序:左孩子–>右孩子–>根节点,正好是后序遍历的顺序。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: C/C++ 是应用广泛的编程语言,其在数据结构应用方面也十分重要。面试中相关的 C/C++ 数据结构问题主要围绕数组、链表、二叉树和图等方面。以下是一些常见问题及其解答: 1. 如何反转一个单向链表? 答:可以使用三个指针来实现:cur 代表当前节点,pre 代表上一个节点,next 代表下一个节点。每次遍历时,将 cur 的 next 指向 pre,然后将三个指针分别向后移动即可。 2. 如何判断两个链表是否相交,并找出相交的点? 答:可以分别遍历两个链表,得到各自的长度。然后让长的链表先走 n 步,使得两个链表剩余的长度相等。接下来同时遍历两个链表,比较节点是否相同即可找出相交的点。 3. 如何判断一个二叉树是否为平衡二叉树? 答:可以计算每个节点的左右子树深度差,如果任何一个节点的深度差大于1,则此树不是平衡二叉树。可以使用递归实现,每次计算当前节点的深度,然后递归判断其左右子树是否平衡。 4. 如何实现图的深度优先搜索(DFS)和广度优先搜索(BFS)算法? 答:DFS 可以使用递归实现。从某个节点开始,逐个访问其未被访问的邻接节点,并将其标记为已访问。然后对每个未被访问的邻接节点递归调用 DFS 函数。BFS 可以使用队列实现。从某个节点开始,将其加入队列,并标记为已访问。然后从队列中弹出节点,并访问其所有未被访问的邻接节点,并将其加入队列中。重复此过程直到队列为空。 以上是一些常见的 C/C++ 数据结构面试问题及其解答。在面试中,除了掌握相关算法和数据结构知识外,还需多做练习和积累经验,才能更好地应对各种面试问题。 ### 回答2: C语言是一种用于编写系统级程序的高级编程语言,具有简单、高效、灵活等特点,是许多操作系统、编译器等软件的首选语言,也是许多企业在进行面试时重点考察的技能。在C/C++数据结构面试题中,经常会涉及到各种数据结构相关的算法和应用,测试面试者的算法思维能力和实现能力。 其中,常见的数据结构包括链表、栈和队列、二叉树、搜索树、哈希表等。在面试时,会常常涉及代码设计和实现,比如实现链表的插入、删除、查找操作,实现二叉树的遍历、查找操作等。 此外,在数据结构面试中,还经常涉及排序和查找算法,如冒泡排序、快速排序、归并排序、二分查找、哈希查找等。同时,面试者还需要解决一些较为复杂的算法问题,如图的最短路径问题,最小生成树问题等。 总之,C/C++数据结构面试题涵盖了运用数据结构的各种算法和实现方法,需要面试者具备扎实的编程基础和算法思维能力。在备战面试时,可以多做练习,熟悉常用的数据结构和算法,提高理解和实现能力,从而更好地应对面试挑战。 ### 回答3: 面试过程中常见的C/C++数据结构面试题有很多。以下就介绍几个常见的题目并给出解答。 1. 求两个有序数组的中位数 题目描述:给定两个升序排列的整形数组,长度分别为m和n。实现一个函数,找出它们合并后的中位数。时间复杂度为log(m+n)。 解答:这个问题可以使用二分法求解。首先,我们可以在两个数组中分别选出所谓的中间位置,即(i+j)/2和(k+l+1)/2,其中i和j分别是数组A的起始和结束位置,k和l分别是数组B的起始和结束位置。判断A[i+(j-i)/2]和B[k+(l-k)/2]的大小,如果A的中间元素小于B的中间元素,则中位数必定出现在A的右半部分以及B的左半部分;反之,则必定出现在A的左半部分以及B的右半部分。以此类推,每一次都可以删去A或B的一半,从而达到对数级别的时间复杂度。 2. 堆排序 题目描述:对一个长度为n的数组进行排序,时间复杂度为O(nlogn)。 解答:堆排序是一种常用的排序算法,在面试中也经常被考察。堆排序的具体过程是首先将数组构建成一个最大堆或最小堆,然后不断将堆顶元素与最后一个元素交换,并将最后一个元素从堆中剔除。这样,每次剔除后,堆都会重新调整,使得剩下的元素仍然保持堆的性质,直到堆中只剩下一个元素为止。 3. 链表反转 题目描述:反转一个单向链表,例如给定一个链表: 1->2->3->4->5, 反转后的链表为: 5->4->3->2->1。 解答:链表反转题目也是非常常见,其思路也比较简单。遍历链表,将当前节点的next指针指向前一个节点,同时记录当前节点和前一个节点,直至遍历到链表末尾。 以上这三个问题分别从二分法、堆排序和链表三个方面介绍了常见的C/C++数据结构面试题,希望能帮助面试者更好地准备面试。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

君无戏言。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值