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),表示递归完全结束。这样我们可以准确地跟踪每一步的递归调用和返回,理解栈的作用。

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

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

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

相关文章

一文搞透常见的Python编码陷阱(上)(分析+案例)

一个认为一切根源都是“自己不够强”的INTJ 个人主页:用哲学编程-CSDN博客专栏:每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 一、别忘了冒号 1. if 语句 2. while 语句 3. for 语句 4. 函数定义 5. 类定义 6. try/except 语句 …

STM32 HAL库串口空闲中断 + DMA 收发不定长数据

串口接收缓冲区定义 usart.h #define BUFFER_SIZE 64typedef struct {uint8_t buff[BUFFER_SIZE];uint32_t length;uint32_t rx_flag; }uart_rx_msg;/* 串口接收消息缓冲 */ extern uart_rx_msg rs422_rx_msg; extern uart_rx_msg rs485_rx_msg; extern uart_rx_msg rs232_r…

001 创建单例

文章目录 饿汉模式懒汉模式线程不安全懒汉式(线程安全)“双重检查锁定”&#xff08;Double-Checked Locking, DCL&#xff09;实现单例(线程安全)例子 1&#xff1a;两个线程几乎同时请求单例实例例子 2&#xff1a;多个线程在不同时间点请求单例实例例子 3&#xff1a;线程在…

IntelliJ IDEA工具的常用快捷键使用

1&#xff0e;单行注释&#xff1a; ctrl / 2. 多行注释&#xff1a; ctrl shift / 3&#xff0e;查看源码&#xff1a;按 ctrl 别松手&#xff0c;鼠标移动到对应的类名下方&#xff0c;出现下划线&#xff0c;点击过去&#xff0c;可以查看类源码。 4&#xff0e;多行编辑…

RTDETR结合CVPR2024最新图像增强算法!让你的模型无惧风雨【含端到端推理脚本】

如何有效地探索雨痕的多尺度表示对于图像去雨是很重要的。与现有的基于Transformer的方法相比,这些方法主要依赖于单一尺度的雨痕外观,我们开发了一个端到端的多尺度Transformer,利用各种尺度中潜在有用的特征来促进高质量的图像重建。为了更好地探索空间变化的雨痕的常见退…

el-table自定义表头数据不更新

我的表头是有三层的&#xff0c;中间一层展示对应的数据&#xff0c;所以需要自定义&#xff0c;官方的文档显示的写法如下&#xff1a; <el-table-column><template slot“header”><div>{{dayData.supply}}、{{dayData.use}}</div></template>…

Effective C++(1)

文章目录 1. 让自己习惯C条款1&#xff1a;视C为一个语言联邦条款2&#xff1a;尽量以const、enum、inline替换#define条款03&#xff1a;尽可能使用 const条款4&#xff1a;确保对象在使用之前被初始化 1. 让自己习惯C 条款1&#xff1a;视C为一个语言联邦 今天的C已经是多个…

原生html和js实现瀑布流布局(macyjs插件,不依赖于jquery,纯原生)

官网地址 方式一&#xff1a;在github上找到项目&#xff0c;复制demo/assets/css/macy.css&#xff0c;以及/dist/macy.js 直接引入项目 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv&qu…

如何理解类的符号引用?类的直接引用?

在Java中&#xff0c;符号引用&#xff08;symbolic reference&#xff09;和直接引用&#xff08;direct reference&#xff09;是理解Java类加载和内存管理的重要概念。它们涉及到JVM如何在运行时处理类、方法、字段等的引用。下面是对这两个概念的详细解释&#xff1a; 符号…

junit-platform-engine旧版本无法更新问题

现象&#xff1a; 运行groovy测试类&#xff0c;一直使用的是低版本的junit-platform-engine-1.5.2.jar。即使在最外层强制升级版本也没有用 解决&#xff1a; 在最外层pom.xml引入高版本的父pom即可 <dependencyManagement><dependencies><dependency>&…

满帮集团 Eureka 和 ZooKeeper 的上云实践

作者&#xff1a;胡安祥 满帮集团&#xff0c;作为“互联网物流”的平台型企业&#xff0c;一端承接托运人运货需求&#xff0c;另一端对接货车司机&#xff0c;提升货运物流效率。2021 年美股上市&#xff0c;成为数字货运平台上市第一股。根据公司年报&#xff0c;2021 年&a…

网络协议——FTP(简介、搭建FTP服务端)

一、简介 1、什么是FTP&#xff1f; FTP&#xff08;File Transfer Protocol&#xff0c;文件传输协议&#xff09; TCP/IP 协议组的协议之一。常用20&#xff08;数据&#xff09;、21&#xff08;命令&#xff09;端口作为通讯端口。&#xff08;22为SSH端口&#xff09;F…

C++ 指针占用的大小是多少

作为一个C程序员&#xff0c;我们可以详细探讨指针在C中的大小&#xff0c;以及通过代码示例来演示这一点。 C 指针占用的大小是多少 指针的大小代码示例代码解释运行结果结论 指针的大小 指针的大小主要取决于系统的架构&#xff08;如32位或64位&#xff09;和编译器的实现…

就业班 第三阶段(ELK) 2401--5.22 day3 filebeat+elk云部署

kafka集群 Windterm同步输入&#xff0c;多台机子可以同时输入同步输入 启动kafka需要启动两个 第一个 [rootkafka1 ~]# cd /usr/local/kafka_2.11-2.0.0/ [rootkafka1 ~]# nohup bin/zookeeper-server-start.sh config/zookeeper.properties &第二个 [rootkafka1 ~]#…

apache BeanUtils

一、populate 1、介绍 BeanUtils.populate(Object bean, Map properties) 方法实在org.apache.commons.beanutils.BeanUtils包下的一个一个方法。 该方法的方法头 此方法中&#xff0c;有两个参数&#xff0c;Object bean 为一个实体类&#xff0c;Map properties为一个map集…

20232810 肖峰 2023-2024-2 《网络攻防实践》实验十一

一、实践内容 &#xff08;1&#xff09;web浏览器渗透攻击 任务&#xff1a;使用攻击机和Windows靶机进行浏览器渗透攻击实验&#xff0c;体验网页木马构造及实施浏览器攻击的实际过程。 实验步骤&#xff1a; ①选择使用Metasploit中的MS06-014渗透攻击模块 ②选择PAYLOAD为任…

Linux 36.3@Jetson Orin Nano之系统安装

Linux 36.3Jetson Orin Nano之系统安装 1. 源由2. 命令行烧录Step 1&#xff1a;下载Linux 36.3安装程序Step 2&#xff1a;下载Linux 36.3根文件系统Step 3&#xff1a;解压Linux 36.3安装程序Step 4&#xff1a;解压Linux 36.3根文件系统Step 5&#xff1a;安装应用程序Step …

# Mybatis 高级用法和tk.mybatis使用

Mybatis 高级用法和tk.mybatis使用 文章目录 Mybatis 高级用法和tk.mybatis使用使用SelectProvider、InsertProvider、UpdateProvider、DeleteProviderSelectProvider使用例子 tk.mybatis引入依赖查询实现实体映射类实体类规范 dao层调用dao 使用SelectProvider、InsertProvide…

eBay运营账号防关联成功的关键因素是什么?

一、什么是ebay eBay如今的发展现状呈现出积极且充满活力的态势。作为全球知名的在线拍卖和购物平台&#xff0c;随着全球消费者对线上购物的需求不断增长&#xff0c;这为卖家提供了广阔的市场空间和盈利机会&#xff0c;但多账号的运营若处理不好容易引起账号被关联&#xf…

基于生命周期评价法的农田温室气体排放估算;农田CH4和N2O排放模拟;农田碳库模型和土壤呼吸等

目录 专题一 温室气体排放模拟研究 专题二 农田CH4和N2O排放模拟 专题三 农田碳库模型和土壤呼吸 专题四 基于生命周期评价法的农田温室气体排放估算 专题五-六 基于过程模型的温室气体排放模拟 专题七 案例模拟与疑难解答 更多应用 农业是甲烷&#xff08;CH4&#xff…