当前位置: 首页 > news >正文

C-数据结构-树状存储的基本实现

/*
理解和记忆递归的关键在于把握递归的本质和函数调用的过程。递归函数在每次调用时会把当前状态压入调用栈,直到满足终止条件后开始回溯。理解基准条件和递归步骤:每个递归函数都需要有基准条件(如节点为空时返回),并在每一步中递归调用自身处理子问题。

*/
main.c

#include<stdio.h>
#include<stdlib.h>#define NAMESIZE	32struct score_st
{int id;char name[NAMESIZE];int math;int chinese;
};struct node_st
{struct score_st data;struct node_st *l,*r;
};print_s(struct score_st *d)
{printf("%d %s %d %d\n",d->id,d->d.name,d->math,d->chinese);
}int insert(struct node_st **root,struct score_st *data)
{struct node_st *node;if(*root == NULL){node = malloc(sizeof(*node));if(node == NULL)return -1;node->data = *data;node->l = NULL;node->r = NULL;*root = node;return 0;}if(data->id <= (*root)->data.id)return insert(&(*root)->l,data);elsereturn insert(&(*root)->r,data);
}
struct score_st *find(struct node_st *root,int id)
{if(root == NULL)return NULL;if(id == root->data.id)return &root->data;if(id < root->data.id)return find(root->l,id);elsereturn find(root->r,id);
}
void draw_(struct node_st *root,in level)
{int i;if(root == NULL)return ;draw_(root->t,level+1);for(i = 0;i<level;i++)printf("    ");print_s(&root->data);draw_(root->l,level+1);
}
void draw(struct node_st *root)
{draw_(root,0);
}int main()
{int arr[] = {1,2,3,7,6,5,9,8,4};int i;struct score_st tmp,*datap;struct node_st *tree = NULL;for(i = 0;i<sizeof(arr)/sizeof(*arr);i++){tmp.id = arr[i];snprintf(tmp.name,NAMESIZE,"stu%d",arr[i]);tmp.math = rand()%100;tmp.chinese = rand()%100;insert(&tree,&tmp);}draw(tree);#if 0int tmpid = 2;datap = find(tree,tmpid);if(datap == NULL)printf("can not find the id %d\n",tmpid);elseprint_s(datap);
#endifexit(0);
}

补充说明1

为了理解二级指针的一级目标,我们需要明确指针和二级指针的概念。

指针和二级指针

  • 指针:一个指针变量保存了另一个变量的地址。通过指针,我们可以访问或修改这个变量的值。例如,int *p 是一个指向整数的指针变量。
  • 二级指针:一个二级指针变量保存了另一个指针变量的地址。通过二级指针,我们可以访问或修改这个指针变量的值。例如,int **pp 是一个指向指针变量的指针。

二级指针的一级目标

一级目标是指二级指针所指向的那个指针变量。

举个具体的例子,假设我们有以下定义:

int a = 10;       // 普通变量
int *p = &a;      // 指向变量 a 的指针
int **pp = &p;    // 指向指针 p 的指针

在这个例子中:

  • p 是一个指向 a 的指针。
  • pp 是一个指向 p 的指针。

我们可以这样理解:

  • pp 保存了 p 的地址。
  • *pp 解析出 pp 所指向的内容,即 p
  • **pp 解析出 *pp 所指向的内容,即 a 的值。
    当然可以!以下是一个图形示例来说明 *aa = b 的含义:

假设:

  • aa 是一个指向指针的指针。
  • a 是一个指针,它最初指向一个地址。
  • b 是另一个指针,指向另一个地址。

初始状态:

+------+    +------+    +------+
|  aa  | -> |  a   | -> |  x   |  (假设 x 是 a 所指向的值)
+------+    +------+    +------++------+    +------+
|  b   | -> |  y   |  (假设 y 是 b 所指向的值)
+------+    +------+

执行 *aa = b 后的状态:

+------+    +------+
|  aa  | -> |  b   | -> |  y   |  (aa 现在指向 b,而 b 仍然指向 y)
+------+    +------+

这样做后,aa 所指向的指针 a 不再指向原来的地址,而是指向了 b 所指向的地址。

以下是更详细的图示:

  1. 初始状态:
aa -> a -> [地址1: x]
b -> [地址2: y]
  1. 执行 *aa = b 后:
aa -> b -> [地址2: y]

这意味着,aa 原本指向的指针 a,现在指向了 b,即 a 的地址已经被 b 的地址覆盖。

希望这个图形示例能帮助你更好地理解 *aa = b 的含义。如果还有其他问题,请随时告诉我!

补充说明2

你提到的情况是正确的。A 不出栈的原因是递归调用还没有完成。为了更清楚地解释递归调用的过程,让我们重新逐步分析每一个递归调用和返回的过程,并使用栈来跟踪函数调用。

示例二叉树

假设有如下二叉树:

      A/ \B   C/ \D   E

使用栈模拟执行过程

我们以栈的方式逐步模拟 draw 函数调用 draw_ 的过程。

  1. 初始状态

    • 栈为空。
    • 调用 draw(root),进入 draw_(root, 0)
  2. 处理根节点 A

    • 调用 draw_(A, 0)
    • 栈:[ draw_(A, 0) ]
  3. 递归处理右子树 C

    • 调用 draw_(C, 1)
    • 栈:[ draw_(A, 0), draw_(C, 1) ]
  4. 处理 C 节点

    • 右子树为空,返回。
    • 打印 C(缩进 4 空格)。
    • 左子树为空,返回。
    • 返回 draw_(A, 0)
    • 栈:[ draw_(A, 0) ]

    输出:

        C
    
  5. 打印根节点 A

    • 打印 A(无缩进)。
    • 栈:[ draw_(A, 0) ]

    输出:

        C
    A
    
  6. 递归处理左子树 B

    • 调用 draw_(B, 1)
    • 栈:[ draw_(A, 0), draw_(B, 1) ]
  7. 处理 B 节点

    • 调用 draw_(E, 2)(递归处理右子树)。
    • 栈:[ draw_(A, 0), draw_(B, 1), draw_(E, 2) ]
  8. 处理 E 节点

    • 右子树为空,返回。
    • 打印 E(缩进 8 空格)。
    • 左子树为空,返回。
    • 返回 draw_(B, 1)
    • 栈:[ draw_(A, 0), draw_(B, 1) ]

    输出:

        C
    AE
    
  9. 打印 B 节点

    • 打印 B(缩进 4 空格)。
    • 栈:[ draw_(A, 0), draw_(B, 1) ]

    输出:

        C
    AEB
    
  10. 递归处理左子树 D

    • 调用 draw_(D, 2)
    • 栈:[ draw_(A, 0), draw_(B, 1), draw_(D, 2) ]
  11. 处理 D 节点

    • 右子树为空,返回。
    • 打印 D(缩进 8 空格)。
    • 左子树为空,返回。
    • 返回 draw_(B, 1)
    • 栈:[ draw_(A, 0), draw_(B, 1) ]

    输出:

   C
AEBD
  1. 完成 B 节点的处理

    • 返回 draw_(A, 0)
    • 栈:[ draw_(A, 0) ]
  2. 完成 A 节点的处理

    • 返回 draw(root)
    • 栈为空。

最终输出

    C
AEBD

在这个过程中,A 不出栈的原因是因为它的递归调用还没有完成。只有当左子树 B 的所有处理完成后,A 才会出栈,回到 draw(root),表示递归完全结束。这样我们可以准确地跟踪每一步的递归调用和返回,理解栈的作用。

希望这个解释能帮助你更好地理解代码的递归逻辑!如果还有其他问题,请随时告诉我。

相关文章:

C-数据结构-树状存储的基本实现

/* 理解和记忆递归的关键在于把握递归的本质和函数调用的过程。递归函数在每次调用时会把当前状态压入调用栈&#xff0c;直到满足终止条件后开始回溯。理解基准条件和递归步骤&#xff1a;每个递归函数都需要有基准条件&#xff08;如节点为空时返回&#xff09;&#xff0c;并…...

指纹识别经典图书、开源算法库、开源数据库

目录 1. 指纹识别书籍 1.1《精通Visual C指纹模式识别系统算法及实现》 1.2《Handbook of Fingerprint Recognition》 2. 指纹识别开源算法库 2.1 Hands on Fingerprint Recognition with OpenCV and Python 2.2 NIST Biometric Image Software (NBIS) 3. 指纹识别开源数…...

嵌入式之译码器

系列文章目录 译码器嵌入式之译码器 嵌入式之译码器 系列文章目录一、译码器定义二、常见类型的译码器三、工作原理 一、译码器定义 译码器&#xff08;Decoder&#xff09;是一种数字电路&#xff0c;其主要功能是从输入的编码信号中解码出特定的信息或控制信号。 译码器通常…...

分成sum接近的2个集合,返回相对小的sum

题目描述&#xff1a;给定一个正数数组arr&#xff0c;请把arr中所有的数分成两个集合&#xff0c;尽量让两个集合的累加和接近&#xff0c;返回最接近的情况下&#xff0c;较小集合的累加和sum。 way&#xff1a;选还是不选 //arr[index...]可以自由选择,返回累加和尽量接近…...

SpringBoot前置知识01-SPI接口

SpringBoot前置知识-SPI接口 介绍 Java中SPI是一种服务发现机制&#xff0c;或者说是一种思想&#xff0c;亦是一种约定。其实JDK中的JDBC就是使用了这种用思想&#xff0c;JDBC在JDK中只定义了接口&#xff0c;并没有实现类&#xff0c;连接什么数据库就要引入什么数据库的驱…...

数学建模--LaTeX的基本使用

目录 1.回顾 2.设置这个页眉和页脚 3.对于字体的相关设置 4.对于这个分级标题的设置 5.列表的使用 6.插入图片 1.回顾 &#xff08;1&#xff09;昨天我们了解到了这个latex的使用基本常识&#xff0c;以及这个宏包的概念&#xff0c;区域的划分&#xff0c;不同的代码代…...

授权调用: 介绍 Transformers 智能体 2.0

简要概述 我们推出了 Transformers 智能体 2.0&#xff01; ⇒ &#x1f381; 在现有智能体类型的基础上&#xff0c;我们新增了两种能够 根据历史观察解决复杂任务的智能体。 ⇒ &#x1f4a1; 我们致力于让代码 清晰、模块化&#xff0c;并确保最终提示和工具等通用属性透明化…...

流媒体内网穿透/组网/视频协议转换EasyNTS上云网关如何更改密码?

EasyNTS上云网关的主要作用是解决异地视频共享/组网/上云的需求&#xff0c;网页对域名进行添加映射时&#xff0c;添加成功后会生成一个外网访问地址&#xff0c;在浏览器中输入外网访问地址&#xff0c;即可查看内网应用。无需开放端口&#xff0c;EasyNTS上云网关平台会向Ea…...

HTML5的标签(文本链接、图片路径详解)

目录 前言 一、文本链接 超链接表述 二、图片路径详解 绝对路径 相对路径 网络路径 前言 一、文本链接 超链接表述 HTML 使用标签<a>来设置超文本链接 超链接可以是一个字&#xff0c;一个词&#xff0c;或者一组词&#xff0c;也可以是一幅图像&#xff0c;…...

React Native 之 Linking(链接)(十五)

URL Scheme是什么 URL Scheme是一种机制&#xff0c;主要用于在移动应用程序中打开另一个应用程序或执行特定操作。 定义与原理&#xff1a; URL Scheme允许应用程序通过特定的URL格式与其他应用程序进行交互。 它通过在应用程序中注册一个自定义的URL Scheme&#xff0c;并在…...

Java实现图书系统

首先实现一个图书管理系统,我们要知道有哪些元素? 1.用户分成为管理员和普通用户 2.书:书架 书 3.操作的是: 书架 目录 第一步:建包 第二步:搭建框架 首先:完成book中的方法 其次:完成BookList 然后:完成管理员界面和普通用户界面 最后:Main 第三步:细分方法 1.退…...

Git提交和配置命令

一、提交代码到仓库 在软件开发中&#xff0c;版本控制是一个至关重要的环节。而Git作为目前最流行的版本控制系统之一&#xff0c;为我们提供了便捷高效的代码管理和协作工具。在日常开发中&#xff0c;我们经常需要将本地代码提交到远程仓库&#xff0c;以便于团队协作和版本…...

已解决java.lang.ExceptionInInitializerError: 初始化程序中的异常错误的正确解决方法,亲测有效!!!

已解决java.lang.ExceptionInInitializerError: 初始化程序中的异常错误的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 报错原因 解决思路 解决方法 分析错误栈信息 检查静态初始化块和静态变量 验证资源和配置 使用日志记录…...

报表显示中,是否具备条件格式功能设计?

**报表显示中确实具备条件格式功能设计**。条件格式是一种根据特定条件对单元格或单元格区域进行格式设置的功能&#xff0c;它可以帮助用户更直观地理解和分析数据。 通过条件格式&#xff0c;用户可以设置多种条件&#xff0c;如单元格值的大小、是否包含特定文本等&#xf…...

完全二叉树查找

描述 有一棵树&#xff0c;输出某一深度的所有节点&#xff0c;有则输出这些节点&#xff0c;无则输出EMPTY。该树是完全二叉树。 输入描述 输入有多组数据&#xff0c;遇到0时终止输入。 每组输入一个n(1<n<1000)&#xff0c;然后将树中的这n个节点依次输入&#xff…...

Web安全:SQL注入之时间盲注原理+步骤+实战操作

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…...

[JDK工具-10] jvisualvm 多合一故障处理工具

文章目录 1. 介绍2. 查看堆的变化3. 查看堆快照4. 导出堆快照文件5. 查看class对象加载信息6. CPU分析&#xff1a;发现cpu使用率最高的方法7. 查看线程快照&#xff1a;发现死锁问题 1. 介绍 VisualVM 是一款免费的&#xff0c;集成了多个 JDK 命令行工具的可视化工具&#xf…...

【GateWay】自定义RoutePredicateFactory

需求&#xff1a;对于本次请求的cookie中&#xff0c;如果userType不是vip的身份&#xff0c;不予访问 思路&#xff1a;因为要按照cookie参数进行判断&#xff0c;所以根据官方自带的CookieRoutePredicateFactory进行改造 创建自己的断言类&#xff0c;命名必须符合 xxxRout…...

今日总结2024/5/27

今日学习了状态压缩DP,状态压缩DP分为棋盘型(基于连通性)和集合型 Acwing.1064 小国王 在 nn的棋盘上放 k个国王&#xff0c;国王可攻击相邻的 8个格子&#xff0c;求使它们无法互相攻击的方案总数。 输入格式 共一行&#xff0c;包含两个整数 n和 k。 输出格式 共一行&…...

使用 Snort 进行入侵检测

使用 Snort 进行入侵检测 Snort 是一种流行的开源入侵检测系统。您可以在http://www.snort.org/上获取它。Snort 分析流量并尝试检测和记录可疑活动。Snort 还能够根据其所做的分析发送警报。 Snort 安装 在本课中&#xff0c;我们将从源代码安装。此外&#xff0c;我们不会安…...

ARM架构随机数生成机制与安全应用实践

1. ARM架构随机数生成机制深度解析 在计算机安全领域&#xff0c;高质量的随机数生成是加密算法、密钥生成和安全协议的基础支撑。ARMv8/v9架构通过FEAT_RNG&#xff08;Random Number Generation&#xff09;特性提供了硬件级的随机数生成支持&#xff0c;其设计遵循严格的密码…...

Firefox渗透测试插件工作流:15款高价值安全工具实战指南

1. 这不是普通浏览器插件推荐&#xff0c;而是一套可落地的渗透测试辅助工作流 “火狐插件”四个字在安全从业者耳中&#xff0c;常被默认为“轻量级、临时性、辅助性”的代名词——很多人装完Hackbar就以为自己有了渗透入口&#xff0c;点开FoxyProxy调个代理就当完成了环境隔…...

Unity版本降级实战:跨版本兼容性修复指南

1. 为什么Unity版本降级不是“回退按钮”&#xff0c;而是一场精密手术 在Unity项目开发中&#xff0c;很多人把版本降级想象成操作系统里的“系统还原”——点一下&#xff0c;回到上个稳定状态&#xff0c;万事大吉。我去年接手一个AR工业巡检项目时也这么想&#xff0c;客户…...

Perseus补丁:碧蓝航线全皮肤解锁完整指南与快速配置教程

Perseus补丁&#xff1a;碧蓝航线全皮肤解锁完整指南与快速配置教程 【免费下载链接】Perseus Azur Lane scripts patcher. 项目地址: https://gitcode.com/gh_mirrors/pers/Perseus 还在为碧蓝航线中那些精美皮肤需要付费而烦恼吗&#xff1f;想要免费体验所有舰娘的不…...

如何让老款Mac焕发新生:终极硬件限制破解与macOS兼容工具指南

如何让老款Mac焕发新生&#xff1a;终极硬件限制破解与macOS兼容工具指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 还在为苹果官方停止支持的老款Mac无…...

将PHP C++扩展从php5升级到php7

将PHP C扩展从php5升级到php7 在没有怎么看明白php5 php7源码的情况下&#xff0c;接手一份基于php5写c扩展&#xff0c;如何接手快速升级到php7环境下也能使用呢&#xff1b;我仅仅修改了所引用的一个php中对象处理的头文件&#xff0c;就满足了要求&#xff0c;扩展被编译通过…...

2026特级防火卷帘门价格明细、国标参数及选购避坑指南(河北厂家实测)

在商业综合体、地下车库、厂房消防验收场景中&#xff0c;特级防火卷帘门是核心防火分隔设备&#xff0c;因具备3小时极限耐火极限&#xff0c;成为大型建筑消防报审的刚需产品。很多工程采购、消防从业者在选型时&#xff0c;容易混淆普通卷帘与特级卷帘的区别&#xff0c;同时…...

软件许可优化选到头大?八家公司直接给你答案

上周一个做采购的朋友打电话来&#xff0c;声音都哑了。说他们公司被Adobe审计盯上了&#xff0c;对方要他们在两周内提交过去三年的部署报告。他们IT就两个人&#xff0c;连公司有多少台电脑装了Photoshop都说不清。我问她你现在打算怎么办&#xff0c;她说正在看各种软件许可…...

观察Taotoken在多模型聚合调用时的路由与容错表现

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 观察Taotoken在多模型聚合调用时的路由与容错表现 在构建依赖大模型能力的应用时&#xff0c;服务的稳定性是开发者关心的核心问题…...

超厉害!AI写教材,低查重且内容连贯,快速产出专业教材!

整理教材知识点实在是一项“精细工作”&#xff0c;最大的挑战在于如何保持平衡与衔接&#xff01;我们常常担忧会遗漏核心概念&#xff0c;或是难以掌握合适的难度梯度——小学教材常常写得过于复杂&#xff0c;导致学生难以理解&#xff1b;而高中教材则可能显得过于简单&…...