【考研408真题】2022年408数据结构41题---判断当前顺序存储结构树是否是二叉搜索树

news2024/11/16 18:03:14

文章目录

  • 思路
  • 408考研各数据结构C/C++代码(Continually updating)

思路

在这里插入图片描述
在这里插入图片描述
很明显,这是一个顺序存储结构的树的构成方法。其中树的根节点位置从索引0开始,对于该结构,存在有:如果当前根节点的下标为n,那么其左子树下标为2n+1,右子树下标为2n+2。
而对于BST,我们知道,其一个非常显著的特点就是:对于根节点root,其左子树小于其根节点的值,其右子树大于其根节点的值。同时,如果当前节点为null,不影响其是否为BST。
基于这个理论,我们大概的实现思路是:递归的判断当前根节点的左子树和右子树,并且限定其左右子树的值的大小区间范围。
那么这里应该如何去限制这个范围呢?
从上面的理论中我们可以得到如下的伪代码:

//如下代码基于链式存储结构 不过不影响理论实践
bool isBST(SqBiTree* root,int low,int high)
{
	if(root==null){
		return true;
	}
	//这里逻辑严谨应该增加一个左右指针的非空判断 我就不写了
	if(root.left.val>=root.val || root.right.val <= root.val){
		return false;
	}
	return isBST(root.left,low,root.val) && 
	isBST(root.right,root.val,maxValue);
}

为什么要这么写呢?
首先我们基于上面的定义,如果当前节点为空,不影响当前树是否是BST,因此直接返回tree。
之后,我们开始条件判断,当前节点的左右子节点,是否小于和大于当前节点。
如果不是,也就是违法了BST的特性,那么我们直接返回false。
并且,我们一开始也说了,这应该是一个递归的判断过程,因此我们还需要对当前root节点的左子树和右子树继续去执行当前的递归过程。
那么递归的条件是什么?
对于当前节点的左子树,其最小值应该是不限定的,但是其最大值必须小于当前节点的值,
而对于其右子树,其最小值应该大于当前节点的值,其最大值不限。
所以就可以得到最后两行代码的条件了。
那么换到我们题目中,我们只需要将指针操作,修改为对数组下标的数据判断即可。
最终就可以得到如下代码:

// 递归函数,判断以n为根的二叉树是否是BST
bool isBSTUtil(BinaryTree *T, int n, TreeNodeType minVal, TreeNodeType maxVal)
{
    if (T->data[n] == '\0')
        return true;

    TreeNodeType nodeValue = T->data[n];

    // 检查当前节点的值是否在[minVal, maxVal]的范围内
    if ((nodeValue <= minVal) || ( maxVal <= nodeValue))
        return false;

    // 递归检查左子树和右子树,更新范围
    return isBSTUtil(T, 2 * n, minVal, nodeValue) && isBSTUtil(T, 2 * n + 1, nodeValue, maxVal);
}

ok,经过上面的解释,我们就已经得到了完整的当前题目的实现思路了。
完整代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>

#define MaxSize 100

typedef int TreeNodeType;

// 二叉树结构
typedef struct
{
    TreeNodeType data[MaxSize];
    int BiTreeNum;
} BinaryTree;

// 声明队列数据结构
typedef struct
{
    int front, rear;
    int size;
    int capacity;
    int *array;
} Queue;

void initTree(BinaryTree *T);
void createTree(BinaryTree *T, int n);
TreeNodeType rootTree(BinaryTree *T);
int countTree(BinaryTree *T);
int maxDepthOfTree(BinaryTree *T, int n);
void preOrderTraverse(BinaryTree *T, int n);
void inOrderTraverse(BinaryTree *T, int n);
void postOrderTraverse(BinaryTree *T, int n);
void levelOrderTraverse(BinaryTree *T); // 层序遍历
bool destoryTree(BinaryTree *T);
void traverseArray(BinaryTree *T); // 遍历数组
bool isBSTUtil(BinaryTree *T, int n, TreeNodeType minVal, TreeNodeType maxVal);

// 队列相关函数
Queue *createQueue(int capacity);
bool isQueueEmpty(Queue *queue);
bool isQueueFull(Queue *queue);
void enqueue(Queue *queue, int item);
int dequeue(Queue *queue);

int main()
{
    BinaryTree T;
    // 开始构造二叉树 其中使用1作为根节点下标
    // 而不是使用0,使用0的问题在于不好表示数据在数组中的位置
    // 我们知道二叉树满足 当前节点n的左子树和右子树的序列号应该为 2n和2n+1
    initTree(&T);
    printf("请输入根结点(输入#表示该结点为空):");
    createTree(&T, 1);

    traverseArray(&T);

    printf("当前二叉树的最大深度为:%d\n", maxDepthOfTree(&T, 1));

    printf("先序遍历:");
    preOrderTraverse(&T, 1);
    printf("\n");

    printf("中序遍历:");
    inOrderTraverse(&T, 1);
    printf("\n");

    printf("后序遍历:");
    postOrderTraverse(&T, 1);
    printf("\n");

    printf("层序遍历:");
    levelOrderTraverse(&T);
    printf("\n");

    if (isBSTUtil(&T, 1, -10000, 10000))
    {
        printf("this is a BST");
    }
    else
    {
        printf("this is not a BST");
    }

    return 0;
}

void initTree(BinaryTree *T)
{
    int i;
    for (i = 0; i < MaxSize; ++i)
    {
        T->data[i] = '\0';
    }

    T->BiTreeNum = 0;
    return;
}

void createTree(BinaryTree *T, int n)
{
    char ch;
    // 刷新(清空)标准输入流(stdin)
    // 主打一个求稳
    fflush(stdin);
    // 输入当前节点信息 # 代表当前节点为空
    // 先构造过字数
    scanf(" %c", &ch);
    if (ch == '#')
    { // 空直接返回
        return;
    }
    else
    {
        T->data[n] = ch;
        T->BiTreeNum++;
        printf("输入 %c 的左子树数据(输入#表示当前左子树为空: ", ch);
        // 这里有一个技巧
        createTree(T, 2 * n);
        printf("输入 %c 的右子树数据(输入#表示当前右边子树为空): ", ch);
        createTree(T, (2 * n + 1));
    }
}

// 计算二叉树的最大深度
// 从根节点到叶子节点的最长路径的长度
// 由于是顺序结构 因此这里从第一层也就是n=1开始向下遍历
// 然后不断的判断左子树和右子树的高度
// 最后取最大值
int maxDepthOfTree(BinaryTree *T, int n)
{
    if (n <= T->BiTreeNum && T->data[n] != '\0')
    {
        int leftDepth = maxDepthOfTree(T, 2 * n);
        int rightDepth = maxDepthOfTree(T, 2 * n + 1);

        return 1 + fmax(leftDepth, rightDepth);
    }
    else
    {
        return 0;
    }
}

// 先序遍历 根左右
void preOrderTraverse(BinaryTree *T, int n)
{
    if (T->data[n] == '\0')
        return;
    else
    {
        printf("%c ", T->data[n]);
        preOrderTraverse(T, 2 * n);
        preOrderTraverse(T, (2 * n + 1));
    }
}
// 中序遍历 左根由7
void inOrderTraverse(BinaryTree *T, int n)
{
    if (T->data[n] == '\0')
        return;
    else
    {
        inOrderTraverse(T, 2 * n);
        printf("%c ", T->data[n]);
        inOrderTraverse(T, (2 * n + 1));
    }
}
// 后序遍历  左右根
void postOrderTraverse(BinaryTree *T, int n)
{
    if (T->data[n] == '\0')
        return;
    else
    {
        postOrderTraverse(T, 2 * n);
        postOrderTraverse(T, (2 * n + 1));
        printf("%c ", T->data[n]);
    }
}
void traverseArray(BinaryTree *T)
{
    for (int i = 1; i <= T->BiTreeNum; i++)
    {
        printf("%c  ", T->data[i]);
    }
    printf("\n");
}

// 层序遍历二叉树
void levelOrderTraverse(BinaryTree *T)
{
    if (T->BiTreeNum == 0)
    {
        printf("二叉树为空\n");
        return;
    }

    Queue *queue = createQueue(T->BiTreeNum);
    int current = 1; // 从根节点开始

    while (current <= T->BiTreeNum)
    {
        printf("%c ", T->data[current]);

        if (2 * current <= T->BiTreeNum && T->data[2 * current] != '\0')
        {
            enqueue(queue, 2 * current);
        }

        if (2 * current + 1 <= T->BiTreeNum && T->data[2 * current + 1] != '\0')
        {
            enqueue(queue, 2 * current + 1);
        }

        if (!isQueueEmpty(queue))
        {
            current = dequeue(queue);
        }
        else
        {
            break;
        }
    }

    free(queue->array);
    free(queue);
}

// 创建队列
Queue *createQueue(int capacity)
{
    Queue *queue = (Queue *)malloc(sizeof(Queue));
    if (!queue)
    {
        perror("内存分配失败");
        exit(EXIT_FAILURE);
    }

    queue->front = 0;
    queue->rear = -1;
    queue->size = 0;
    queue->capacity = capacity;
    queue->array = (int *)malloc(capacity * sizeof(int));
    if (!queue->array)
    {
        perror("内存分配失败");
        exit(EXIT_FAILURE);
    }

    return queue;
}

// 检查队列是否为空
bool isQueueEmpty(Queue *queue)
{
    return (queue->size == 0);
}

// 检查队列是否已满
bool isQueueFull(Queue *queue)
{
    return (queue->size == queue->capacity);
}

// 入队列
void enqueue(Queue *queue, int item)
{
    if (isQueueFull(queue))
    {
        printf("队列已满\n");
        return;
    }

    queue->rear = (queue->rear + 1) % queue->capacity;
    queue->array[queue->rear] = item;
    queue->size++;
}

// 出队列
int dequeue(Queue *queue)
{
    if (isQueueEmpty(queue))
    {
        printf("队列为空\n");
        return -1;
    }

    int item = queue->array[queue->front];
    queue->front = (queue->front + 1) % queue->capacity;
    queue->size--;

    return item;
}

// 递归函数,判断以n为根的二叉树是否是BST
bool isBSTUtil(BinaryTree *T, int n, TreeNodeType minVal, TreeNodeType maxVal)
{
    if (T->data[n] == '\0')
        return true;

    TreeNodeType nodeValue = T->data[n];

    // 检查当前节点的值是否在[minVal, maxVal]的范围内
    if ((nodeValue <= minVal) || ( maxVal <= nodeValue))
        return false;

    // 递归检查左子树和右子树,更新范围
    return isBSTUtil(T, 2 * n, minVal, nodeValue) && isBSTUtil(T, 2 * n + 1, nodeValue, maxVal);
}

408考研各数据结构C/C++代码(Continually updating)

408考研各数据结构C/C++代码(Continually updating)
这个模块是我应一些朋友的需求,希望我能开一个专栏,专门提供考研408中各种常用的数据结构的代码,并且希望我附上比较完整的注释以及提供用户输入功能,ok,fine,这个专栏会一直更新,直到我认为没有新的数据结构可以讲解了。
目前我比较熟悉的数据结构如下:
数组、链表、队列、栈、树、B/B+树、红黑树、Hash、图。
所以我会先有空更新出如下几个数据结构的代码,欢迎关注。 当然,在我前两年的博客中,对于链表、哈夫曼树等常用数据结构,我都提供了比较完整的详细的实现以及思路讲解,有兴趣可以去考古。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1078198.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

波奇学C++:哈希

哈希本质是的值和位置建立关联起来&#xff0c;这种关联关系就是哈希函数 示例:除留余数&#xff1a;对输入的数字取模。 哈希冲突&#xff1a;多个不同的值指向同一个位置 解决方法&#xff1a; 闭散列&#xff1a;开发地址法。 把24放在下一个位置 哈希桶 闭散列法 闭散列…

NNDL:作业3

在Softmax回归的风险函数(公式(3.39))中如果加上正则化项会有什么影响? (1) 在 Softmax 回归的风险函数中加入正则化项会对模型的训练产生影响。正则化项的作用是对模型的复杂度进行惩罚&#xff0c;防止过拟合的发生。 (2) 原书公式为&#xff1a; 在加入正则化后损失函数…

STM32单片机入门学习(六)-光敏传感器控制LED

光敏传感器模块和LED接线 LED负极接B12,正极接VCC 光敏传感模块一DO端接B13,GND接GND&#xff0c;VCC接VCC,AO不接。 如图&#xff1a; 主程序代码&#xff1a;main.c #include "stm32f10x.h" #include "Delay.h" //delay函数所在头文件 #include …

Python中套接字实现服务端和客户端3-3

3 创建客户端的步骤 创建客户端的步骤如图5所示。 图5 创建客户端的步骤 从图5可以看出&#xff0c;对于客户端来说&#xff0c;首先创建套接字&#xff0c;之后通过创建的套接字去连接服务端&#xff0c;如果连接成功&#xff0c;则继续通过该套接字向服务端发送数据&#x…

扩展windows 10 文件夹文件路径位数

Enable Long Paths in Windows 10, Version 1607, and Later PowerShell Copy New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force 管理员权限运行 PowerShell…

【开源电商网站】(2),使用docker-compose和dockerfile进行配置,设置自定义的镜像,安装插件,增加汉化包,支持中文界面汉化。

项目相关代代码地址 相关内容&#xff1a; https://blog.csdn.net/freewebsys/category_12461196.html 原文地址&#xff1a; https://blog.csdn.net/freewebsys/article/details/133666433 包括以下运行的详细代码&#xff1a; https://gitee.com/study-demo-all/oscommerc…

将cpu版本的pytorch换成gpu版本

1.首先激活虚拟环境 winRcmd 打开dos命令窗口 查看虚拟环境列表 conda env list 激活虚拟环境 2.将原来的pytorch_cpu版本换成gpu版本 注意&#xff1a;安装gpu版本的pytorch时并不需要先卸载原来的cpu版本pytorch,安装时会自己替换的 打开pytorch官网查看以前版本 Previo…

vant组件安装之后导入所有组件报错

问题&#xff1a;引入vant报错(Module build failed (from ./node_modules/postcss-loader/src/index.js): 解决办法&#xff1a;在node_modules里面找到 vant目录下面的lib里面的 index.css&#xff1b; 在url前面加上空格即可

MongoDB 笔记

1 insert 、create、save区别 insert: 主键不存在则正常插入&#xff1b;主键已存在&#xff0c;抛出DuplicateKeyException 异常 save: 主键不存在则正常插入&#xff1b;主键已存在则更新 insertMany&#xff1a;批量插入&#xff0c;等同于批量执行 insert create&#x…

地下城堡3最强英雄搭配,地下城堡3公认最强阵容

在地下城堡3中&#xff0c;组建一支最强的阵容是玩家们追求的目标之一。通过合理的角色搭配和战术配合&#xff0c;你可以打造一个无敌的团队&#xff0c;在战斗中几乎无往而不胜。下面是地下城堡3公认最强阵容搭配攻略&#xff0c;让你在游戏中轻松征战各个副本和挑战。 关注【…

基于 LSTM 进行多类文本分类(附源码)

NLP 的许多创新是如何将上下文添加到词向量中。一种常见的方法是使用循环神经网络。以下是循环神经网络的概念&#xff1a; 他们利用顺序信息。 他们可以捕捉到到目前为止已经计算过的内容&#xff0c;即&#xff1a;我最后说的内容会影响我接下来要说的内容。 RNNs 是文本和…

一次性读懂Mendix的库间“数据同步”功能

Data sync&#xff0c;对于那些深谙其道的技术高手而言&#xff0c;意义不言自明。然鹅对整天在村工厂里打螺丝的我来说&#xff0c;却经历了一段难捱的时期。时至今日&#xff0c;我仍然时不时地选择性地遗忘某些概念和技术点。因此&#xff0c;本文章记录我之前一点实操的心得…

【测试】robotframework安装

目录 python安装 pip一系列安装 运行效果 参考文档 python安装 注意管理员权限安装&#xff0c;不然2503的错误 。 pip一系列安装 pip install robotframework pip install wxPython pip install robotframework-ride 运行python ride.py pip install setuptools 解决…

125KHz低频接收唤醒芯片:Si3933(TSSOP16)

Si3933 具有内部时钟产生器&#xff0c;可使用晶体振荡器或者RC振荡器&#xff0c;也可以使用外部时钟。 Si3933 是一款三通道的D功耗ASK接 收机&#xff0c;可用于检测15KHz-150KHz低频载波频率的数字信号&#xff0c;并产生唤醒信号。内部集成的校验器用于检测 16 位或 32 位…

双态IT乌镇大会 | 首批《数据中心业务连续性等级评价准则》试点单位将诞生

2023年10月13日-15日&#xff0c;由ITSS分会、证券基金行业信息技术应用创新联盟指导&#xff0c;ITSS数据中心运营管理组&#xff08;DCMG&#xff09;、双态IT论坛、智能运维国标工作组主办&#xff0c;ITSS媒体组、AI范儿协办的“2023第六届双态IT乌镇用户大会”将于浙江乌镇…

SpringBoot采用Dynamic-Datasource方式实现多JDBC数据源

目录 1. Dynamic-Datasource实现多JDBC数据源配置1.1 特性1.2 Mysql数据准备2.2 通过Dynamic-Datasource实现多JDBC数据源2.2.1 pom.xml依赖 2.2.2 application.properties配置2.2.3 使用DS注解选择DataSource2.2.4 使用Transactional DSTransactional实现事务 2.3 动态数据源…

下一代架构设计:云原生、容器和微前端的综合应用

文章目录 云原生&#xff1a;构建可弹性扩展的应用1. 微服务架构2. 容器化3. 自动化和自动扩展 容器化和云原生的结合1. 一致性和可移植性2. 弹性和可伸缩性3. 快速部署和更新4. 资源利用率 微前端&#xff1a;前端架构的演进1. 微前端应用2. 统一的外壳应用3. 独立部署 云原生…

TikTok在跨境电商中的作用:挖掘潜在客户的最佳途径

​随着全球数字化浪潮的不断发展&#xff0c;跨境电商行业也经历了巨大的变革。传统的市场营销渠道已经不再足够&#xff0c;企业们需要不断探寻新的方法来吸引潜在客户。在这个过程中&#xff0c;社交媒体平台TikTok逐渐崭露头角&#xff0c;成为了吸引潜在客户的一个选择。本…

[PwnThyBytes 2019]Baby_SQL - 代码审计+布尔盲注+SESSION_UPLOAD_PROGRESS利用

[PwnThyBytes 2019]Baby_SQL 1 解题流程1.1 分析1.2 解题 2 思考总结 1 解题流程 1.1 分析 此题参考文章&#xff1a;浅谈 SESSION_UPLOAD_PROGRESS 的利用 访问正常来讲用ctf-wscan是能扫出source.zip文件的&#xff0c;且F12后提示了有source.zip&#xff0c;那我们就下载…

Apache POI使用

1.导入坐标 <!-- poi --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>${poi}</version></dependency><dependency><groupId>org.apache.poi</groupId><a…