【数据结构】五分钟自测主干知识(十)

2024-03-25 07:36

本文主要是介绍【数据结构】五分钟自测主干知识(十),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一节,我们讲述了二叉树的概念,二叉树又有什么基本操作呢?今天我们来讲述二叉树的应用~

话不多说,书继上回


5.3二叉树的遍历及应用

二叉树由三个基本部分组成:根结点(D),左子树(L),右子树(R)。

因此,对二叉树的遍历可以分别对这三个部分进行。

如果遵循先左后右的原则,可以有三种遍历规则:DLR,LDR,LRD。

分别称为先序遍历中序遍历后序遍历

1.先序遍历

定义:若二叉树为空,则空操作,否则:

(1)访问根结点;

(2)先序遍历左子树;

(3)先序遍历右子树。

按照这个递归定义可以写出先序遍历二叉树的递归算法:

void PreOrder(BiTree T) {if (!T) return;visite(T->data);//访问根结点PreOrder(T->lchild);PreOrder(T->rchild);
}
2.中序遍历

定义:若二叉树为空,则空操作,否则:

(1)中序遍历左子树;

(2)访问根结点;

(3)中序遍历右子树。

按照这个递归定义可以写出中序遍历二叉树的递归算法:

void InOrder(BiTree T) {if (!T) return;InOrder(T->lchild);visite(T->data);//访问根结点InOrder(T->rchild);
}
3.后序遍历

定义:若二叉树为空,则空操作,否则:

(1)后序遍历左子树;

(2)后序遍历右子树。

(3)访问根结点;

按照这个递归定义可以写出后序遍历二叉树的递归算法:

void PostOrder(BiTree T) {if (!T) return;PostOrder(T->lchild);PostOrder(T->rchild);visite(T->data);//访问根结点
}

可见这三种遍历的搜索路线是一样的,只是访问根的时机不同。 

将二叉树上每个空子树用一个虚结点表示,将这样处理后的二叉树称为原二叉树的扩展二叉树

原二叉树上的结点称为内部结点,表示空指针的虚结点称为外部结点

递归算法优点是简洁,但一般而言,其执行效率不高,因为系统需要维护一个运行栈以保证递归过程是正确执行。其实以上遍历还可以使用非遍历方法。

设一存放结点指针的栈S,每访问完一个结点X后,就将结点X的指针入栈,以便后来能通过这个指针找到结点X的右子树。

void PreOrder(BiTree T) {InitStack(S);    //初始化一个空栈while (T || !StackEmpty(S)) {//遍历结束的条件是栈为空且T为空while (T) {visite(T->data);Push(S, T);    //T进栈T = T->lchild;}if (!StackEmpty(S)) {Pop(S, T);    //弹出栈顶指针TT = T->rchild;}}
}

其中有关栈的处理(其中一些函数)详见前面的文章

附链接:【数据结构】五分钟自测主干知识(四)http://t.csdnimg.cn/DffSWicon-default.png?t=N7T8http://t.csdnimg.cn/DffSW


 4.层序遍历

对二叉树除了可以按上述的先序、中序和后序规则进行遍历外,还可以自上而下,自左向右逐层地进行遍历。

在层序遍历时,当第 i 层结点被访问完后,接下来要逐个访问位于第i + 1 层上的第 i 层结点的左孩子和右孩子。这时,在 i层先被访问的结点其左、右孩子将先被访问,因此需要利用一个队列来存放已访问过的结点的孩子,以控制对这些孩子的访问先后次序。层序遍历的算法思路是:


(1)初始化一个空队列,用来保存已访问过结点的孩子;


(2)非空根指针入队;


(3)若队列为空,则遍历结束;否则重复执行:
①队头元素出队,访问之;
②若被访结点有左孩子,则左孩子入队;
③若被访结点有右孩子,则右孩子入队。

void LayerTraversal(BiTree T) {InitQueue(Q);if (T) EnQueue(Q, T);while (!QueueEmpty(Q)) {DeQueue(Q, p);visite(p->data);if (p->lchild) EnQueue(Q, p->lchild);if (p->lchild) EnQueue(Q, p->rchild);}
}

其中有关队列的处理(其中一些函数)详见前面的文章

附链接:【数据结构】五分钟自测主干知识(五)
http://t.csdnimg.cn/TX4HAicon-default.png?t=N7T8http://t.csdnimg.cn/TX4HA

不论按哪种次序遍历含有n个结点的二叉树,其时间复杂度至少为O(n)


5.二叉树运算举例

1.求二叉树的结点个数

方案1:

int CountNodes1(BiTree T) {if (!T) return 0;int nl = CountNodes1(T->lchild);int nr = CountNodes1(T->rchild);return(1 + nl + nr);
}

方案2:

void CountNodes2(BiTree T, int& n) {if (!T)return;n++;CountNodes2(T->lchild, n);CountNodes2(T->rchild, n);
}

2.输出二叉树每个结点的层次数

void Level(BiTree T, int lev){if (!T)return;lev++;printf(T->data,lev);Level(T->lchild, lev);Level(T->rchild, lev);
}

3.求二叉树的深度

好用的递归方法继续:

int Depth(BiTree T) {if (!T)return 0;int hl = Depth(T->lchild);int hr = Depth(T->rchild);return (hl > hr ? hl + 1: hr + 1);
}

4.输出二叉树树根到所有叶子结点的路径

void OutPath(BiTree T, Stack& S) {if (!T)return;Push(S, T);if (!T->lchild && !T->rchild)StackTraverse(S);OutPath(T->lchild, S);OutPath(T->rchild, S);Pop(S, e);
}

5.(重点)表达式求值

算术表达式可以用二叉树的形式来表示。

用二叉树表示算术表达式的递归方法如下:

(1)如果表达式为常数或简单变量,则二叉树中仅有一个根结点,根结点的数据域存放该表达式的值。

(2)如果表达式的形式是:

(左操作数) 二目运算符 (右操作数)

则二叉树中,以左子树表示左操作数,右子树表示右操作数,根结点的数据域存放二目运算符。

(3)操作数本身又是表达式

例如表达式a+b*(c-d)-e/f的二叉树表示如下:

该二叉树的先序序列为-+a*b-cd/ef

恰好是表达式的前缀表示(波兰式

该二叉树的后序序列为abcd-*+-ef/

恰好是表达式的后缀表示(逆波兰式

 下面给出表达式二叉树结点的存储类型定义:

typedef struct BiNode {double val;char op;unsigned char tag;struct BiNode* lchild, * rchild;
}BiTNode,*BiTree;

其中val分量用来存放表达式中的数值,op分量用来存放表达式中的运算符。

tag起标志作用,若tag=0,则表示结点中存放的是数值,取val分量;

若tag=1,则表示结点中存放的是运算符,取op分量。

对表达式求值可用逆波兰式的求值方法,即利用后序遍历完成计算

double Calculate(BiTree T) {if (T->tag == 0)return T->val;double a = Calculate(T->lchild);double b = Calculate(T->rchild);return operate(a, T->op, b);//计算并返回a op b
}

其中operate函数表示计算算式值


今天我们就到这里,可以对照黑体字查看主干知识,下一讲,我们聊聊线索二叉树

附链接:【数据结构】五分钟自测主干知识()

长咕一下

这篇关于【数据结构】五分钟自测主干知识(十)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/844272

相关文章

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

sqlite3 相关知识

WAL 模式 VS 回滚模式 特性WAL 模式回滚模式(Rollback Journal)定义使用写前日志来记录变更。使用回滚日志来记录事务的所有修改。特点更高的并发性和性能;支持多读者和单写者。支持安全的事务回滚,但并发性较低。性能写入性能更好,尤其是读多写少的场景。写操作会造成较大的性能开销,尤其是在事务开始时。写入流程数据首先写入 WAL 文件,然后才从 WAL 刷新到主数据库。数据在开始

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

【408数据结构】散列 (哈希)知识点集合复习考点题目

苏泽  “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家    知识点 1. 散列查找 散列查找是一种高效的查找方法,它通过散列函数将关键字映射到数组的一个位置,从而实现快速查找。这种方法的时间复杂度平均为(

浙大数据结构:树的定义与操作

四种遍历 #include<iostream>#include<queue>using namespace std;typedef struct treenode *BinTree;typedef BinTree position;typedef int ElementType;struct treenode{ElementType data;BinTree left;BinTre

Python 内置的一些数据结构

文章目录 1. 列表 (List)2. 元组 (Tuple)3. 字典 (Dictionary)4. 集合 (Set)5. 字符串 (String) Python 提供了几种内置的数据结构来存储和操作数据,每种都有其独特的特点和用途。下面是一些常用的数据结构及其简要说明: 1. 列表 (List) 列表是一种可变的有序集合,可以存放任意类型的数据。列表中的元素可以通过索

【Python知识宝库】上下文管理器与with语句:资源管理的优雅方式

🎬 鸽芷咕:个人主页  🔥 个人专栏: 《C++干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 文章目录 前言一、什么是上下文管理器?二、上下文管理器的实现三、使用内置上下文管理器四、使用`contextlib`模块五、总结 前言 在Python编程中,资源管理是一个重要的主题,尤其是在处理文件、网络连接和数据库