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

数据结构课程设计(三)构建决策树

3 决策树

3.1 需求规格说明

【问题描述】

ID3算法是一种贪心算法,用来构造决策树。ID3算法起源于概念学习系统(CLS),以信息熵的下降速度为选取测试属性的标准,即在每个节点选取还尚未被用来划分的具有最高信息增益的属性作为划分标准,然后继续这个过程,直到生成的决策树能完美分类训练样例。

具体方法是:从根结点开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子结点;再对子结点递归的调用以上方法,构建决策树;知道所以特征的信息增益均很小或没有特征可以选择为止。

参考论文:Quinlan J R. Induction of Decision Trees[J]. Machine Learning, 1986, 1(1): 81-106.

参考资料:决策树—ID3、C4.5、CART_决策树流程图-CSDN博客

【数据说明】

DT_data.csv为样本数据,共14条记录。每一条记录共4维特征,分别为Weather(天气), Temperature(温度),Humidity(湿度),Wind(风力);其中Date(约会)为标签列。

【基本要求】(60%)

(1)根据样本数据,建立决策树。

(2)输入测试数据,得到预测是否约会(yes/no)。

【提高要求】(40%)

(1)对决策树(ID3)中特征节点分类选择指标(信息增益)进行优化,选择信息增益率作为决策树(C4.5)中特征节点分类指标,。

决策树(C4.5)及信息增益率参考资料:数据挖掘--决策树C4.5算法(例题)_c4.5算法例题-CSDN博客

3.2 总体分析与设计

(1)设计思想

①存储结构

在决策树的实现中,我采用了以下存储结构:

样本数据结构(Sample):定义了一个结构体Sample来存储每个样本的特征和标签。特征包括天气(Weather)、温度(Temperature)、湿度(Humidity)和风力(Wind),标签为约会结果(Date),表示为yes或no。

决策树节点结构(TreeNode):定义了结构体TreeNode来表示决策树的节点。每个节点包含一个属性(attribute),用于分裂的属性名;一个分支映射(branches),存储该属性不同取值对应的子节点;以及一个标签(label),表示叶子节点的分类结果。

决策树类(DecisionTree):定义了一个类DecisionTree,包含根节点(root)和算法类型(algorithmType)。该类提供构建决策树(buildTree)、预测(predict)和可视化(visualizeTree)等方法。

②主要算法思想

决策树的构建主要基于ID3和C4.5算法。这两种算法都是利用信息增益或信息增益率作为属性选择的标准,递归地构建决策树,直到所有样本都能被正确分类或者没有更多的属性可以用来进一步分裂。

ID3算法:以信息熵的下降速度为选取测试属性的标准,选择信息增益最大的属性进行分裂。

C4.5算法:在ID3的基础上进行了优化,使用信息增益率来选择属性,以减少属性值中某个类别占比过大时的影响。

(2)设计表示

决策树构建的UML类图如图3.2-1所示。

3.2-1 程序UML类图

这里Question_3类主要是为了读取数据并预生成标签列,而Decision类则主要进行的是决策树的构建以及其可视化的工作。

(3)详细设计表示

决策树构建的程序流程图如图3.2-2所示。

3.2-2 决策时实现流程图

该程序的流程步骤如下所示:

1.初始化:构造函数中初始化根节点和算法类型。

2.属性选择:计算每个属性的信息增益或信息增益率,并选择最佳属性。

3.节点分裂:根据选择的属性值分裂节点,递归构建子树。

4.叶子节点生成:当所有样本属于同一类别或没有更多属性时,生成叶子节点。

5.预测:从根节点开始,根据样本的特征值递归查找对应的分支,直到到达叶子节点,得到预测结果。

6.可视化:递归遍历决策树,使用QT的GraphicsView控件实现绘制节点和分支,展示决策树结构。

由于本题中,采取了两种不同的算法,故这里我还绘制了构建决策树的流程图,如图3.2-3所示。

3.2-3 构建决策树流程图

3.3 编码

问题1】:在生成决策树和剪枝的时候指针容易丢失的问题

【解决方法】:在解决生成决策树中指针容易丢失的问题时,首先需要确保正确管理内存。动态分配内存时,使用new关键字进行分配,而在不再需要时使用delete进行释放。此外,释放内存后,将指针设置为nullptr,以避免野指针问题。另一方面,在实际调试过程中,通过手动绘图,监控指针指向,保证生成决策树和剪枝时要逻辑合理。反复调试保证代码正确。

问题2】:树的结点只记录了属性,无法获取结点的特征属性,可视化效果较差

【解决方法】:使用map存储该结点的特征属性和特征属性取值,每个结点存储上一层分类的值以及下一层分类的最优属性,通过存储上一层分类的值,我们可以了解节点的父节点是什么,从而构建出完整的树形结构。而下一层分类的最优属性则可以帮助我们了解节点的子节点应该具备哪些特征,以便进一步展开子节点。在此基础上,完成树结构的绘制,实现可视化,能清晰明了的告诉用户在哪种情况下最有可能去约会。

3.4 程序及算法分析

①使用说明

打开程序后,即可出现初始化程序样式,如图3.4-1所示。

3.4-1 初始化程序

接下来,可以点击相应的算法,并点击“选择CSV文件”将提供的测试CSV输入并进行训练,此时程序会调用visualizeTree函数会将训练结果同步可视化到界面中显示,如图3.4-2所示。

3.4-2 选择决策树训练集文件

这里我应用了ID3算法为例子,选择不同的选项后,再点击“分析结果”即可得到相应的输出结果,如图3.4-3所示。

3.4-3 输出结果

同样,如果选择“C45”算法则会调用C45算法进行决策树的构建,这里需要说明的是C4.5算法和ID3算法的一个显著差异就是应用了信息熵增益率来取代信息熵增益,这样可以显著消除众数分布的影响,并且C45算法所构建的决策树样式也是和ID3算法有较大差异的,如图3.4-4所示。

3.4-4 决策树构建差别

而应用C4.5算法进行预测时显然会得到更加精确的预测结果,如图3.4-5所示。

3.4-5 C4.5算法预测结果

3.5 小结

决策树是一种常用的监督学习算法,主要用于分类和回归问题。它的每个内部节点代表一个属性或特征,每个分支代表一个决策规则,每个叶节点则代表一个结果或决策。决策树的优点在于它的模型结果易于理解和解释,因为决策过程类似于人类的决策过程。此外,它需要的数据预处理较少,不需要进行归一化或标准化,且可以处理数值和分类数据。

在ID3算法中,我通过计算信息增益来选择最佳属性进行节点分裂。信息增益是衡量属性对于分类结果的信息量的增加程度,它帮助我们确定哪个属性最能减少分类的不确定性。然而,我发现单一地使用信息增益作为分裂标准有时会导致选择偏向于那些值较多的属性。为了改进这一问题,我在C4.5算法中引入了信息增益率。这一改进让我更加全面地考虑了属性的选择。信息增益率不仅考虑了信息增益的大小,还考虑了分裂信息值的大小。这样,算法在选择分裂属性时,能够更准确地衡量分裂后的信息量变化。而在实现ID3和C4.5决策树算法的过程中,我遇到了许多困难。决策树的复杂性不在算法逻辑上,而是涉及到对数据结构的深入理解。指针的正确使用对于决策树的构建至关重要,一旦出错,可能会导致树的结构混乱或内存泄漏。最棘手的是指针丢失问题。在动态构建决策树时,我经常遇到指针指向无效内存地址或未初始化的情况。为了解决这个问题,我仔细检查了内存管理代码,并确保在使用指针之前进行了正确的初始化。同时,我也加强了对new和delete操作符的使用,确保正确地分配和释放内存。

但是本题程序还有待改进,比如绘制时的标记与结点图案重合的情况,我还需要进一步详细的处理。而且未讨论如何处理连续数值型数据以构建更精确的决策树,例如引入CART算法更好地处理连续属性。当然,算法都是有缺陷的,需要针对不同的问题选择最适用的算法才能将问题解决,同时优化算法的工作也需要继续努力完成。

3.6 附录

//决策树构建
// 构造函数
DecisionTree::DecisionTree(AlgorithmType algoType) : root(nullptr), algorithmType(algoType) {}
// 析构函数
DecisionTree::~DecisionTree() {freeTree(root);
}
// 释放内存
void DecisionTree::freeTree(TreeNode* node) {if (!node) return;for (auto& branch : node->branches) {freeTree(branch.second);}delete node;
}
// 计算信息熵
double DecisionTree::calculateEntropy(const std::vector<Sample>& samples) const {std::map<std::string, int> labelCount;for (const auto& sample : samples) {labelCount[sample.date]++;}double entropy = 0.0;int total = samples.size();for (const auto& pair : labelCount) {double p = static_cast<double>(pair.second) / total;entropy -= p * log2(p);}return entropy;
}
// 按属性分组
std::map<std::string, std::vector<Sample>> DecisionTree::splitByAttribute(const std::vector<Sample>& samples, const std::string& attribute) const {std::map<std::string, std::vector<Sample>> groups;for (const auto& sample : samples) {std::string value;if (attribute == "Weather") value = sample.weather;if (attribute == "Temperature") value = sample.temperature;if (attribute == "Humidity") value = sample.humidity;if (attribute == "Wind") value = sample.wind;groups[value].push_back(sample);}return groups;
}
// 计算信息增益
double DecisionTree::calculateGain(const std::vector<Sample>& samples, const std::string& attribute) const {auto groups = splitByAttribute(samples, attribute);double totalEntropy = calculateEntropy(samples);double weightedEntropy = 0.0;int totalSamples = samples.size();for (const auto& pair : groups) {double p = static_cast<double>(pair.second.size()) / totalSamples;weightedEntropy += p * calculateEntropy(pair.second);}return totalEntropy - weightedEntropy;
}
//计算分裂信息
double DecisionTree::calculateSplitInfo(const std::vector<Sample>& samples, const std::string& attribute) const {auto groups = splitByAttribute(samples, attribute);double splitInfo = 0.0;int totalSamples = samples.size();for (const auto& pair : groups) {double p = static_cast<double>(pair.second.size()) / totalSamples;if (p > 0) {splitInfo -= p * log2(p);}}return splitInfo;
}
//计算信息增益率
double DecisionTree::calculateGainRatio(const std::vector<Sample>& samples, const std::string& attribute) const {double gain = calculateGain(samples, attribute);double splitInfo = calculateSplitInfo(samples, attribute);// 避免分母为0if (splitInfo == 0) return 0.0;return gain / splitInfo;
}
// 构建决策树
TreeNode* DecisionTree::buildTree(const std::vector<Sample>& samples, const std::set<std::string>& attributes) {// 如果样本全属于一个类别std::string firstLabel = samples.front().date;bool allSame = std::all_of(samples.begin(), samples.end(), [&firstLabel](const Sample& s) {return s.date == firstLabel;});if (allSame) {TreeNode* leaf = new TreeNode();leaf->label = firstLabel;return leaf;}// 如果没有剩余属性if (attributes.empty()) {TreeNode* leaf = new TreeNode();std::map<std::string, int> labelCount;for (const auto& sample : samples) {labelCount[sample.date]++;}leaf->label = std::max_element(labelCount.begin(), labelCount.end(),[](const auto& a, const auto& b) {return a.second < b.second;})->first;return leaf;}// 选择最佳属性double maxMetric = -1;std::string bestAttribute;for (const auto& attr : attributes) {double metric;if (algorithmType == ID3) {metric = calculateGain(samples, attr); // ID3 使用信息增益}else {metric = calculateGainRatio(samples, attr); // C4.5 使用信息增益率}if (metric > maxMetric) {maxMetric = metric;bestAttribute = attr;}}// 创建当前节点TreeNode* node = new TreeNode();node->attribute = bestAttribute;// 按最佳属性划分auto groups = splitByAttribute(samples, bestAttribute);std::set<std::string> remainingAttributes = attributes;remainingAttributes.erase(bestAttribute);for (const auto& pair : groups) {node->branches[pair.first] = buildTree(pair.second, remainingAttributes);}return node;
}
// 预测
std::string DecisionTree::predict(const Sample& sample, TreeNode* node) const {if (node->label != "") return node->label;std::string value;if (node->attribute == "Weather") value = sample.weather;if (node->attribute == "Temperature") value = sample.temperature;if (node->attribute == "Humidity") value = sample.humidity;if (node->attribute == "Wind") value = sample.wind;auto it = node->branches.find(value);if (it != node->branches.end()) {return predict(sample, it->second);}return "Unknown";
}
// 可视化决策树
void DecisionTree::visualizeTree(QGraphicsScene* scene, TreeNode* node, int x, int y, int dx, int dy) const {if (!node) return;// 节点样式int nodeRadius = 20; // 节点半径QColor nodeColor = node->label.empty() ? Qt::yellow : Qt::green; // 叶子节点用绿色,非叶子用黄色QGraphicsEllipseItem* ellipse = scene->addEllipse(x - nodeRadius, y - nodeRadius, nodeRadius * 2, nodeRadius * 2, QPen(Qt::black), QBrush(nodeColor));// 节点文字QGraphicsTextItem* text = scene->addText(QString::fromStdString(node->label.empty() ? node->attribute : node->label));text->setDefaultTextColor(Qt::black);text->setFont(QFont("Arial", 10, QFont::Bold));text->setPos(x - text->boundingRect().width() / 2, y - text->boundingRect().height() / 2);// 如果是叶子节点,终止递归if (!node->label.empty()) return;// 动态调整分支间距int childCount = static_cast<int>(node->branches.size());if (childCount == 0) return;int totalWidth = (childCount - 1) * dx; // 子节点总宽度int startX = x - totalWidth / 2;       // 子节点起始位置// 遍历子节点,绘制分支线和递归调用int index = 0;for (const auto& branch : node->branches) {int childX = startX + index * dx; // 子节点X坐标int childY = y + dy;              // 子节点Y坐标// 绘制分支线QGraphicsLineItem* line = scene->addLine(x, y + nodeRadius, childX, childY - nodeRadius, QPen(Qt::black, 2));// 绘制分支文字QGraphicsTextItem* branchText = scene->addText(QString::fromStdString(branch.first));branchText->setDefaultTextColor(Qt::darkGray);branchText->setFont(QFont("Arial", 10));branchText->setPos((x + childX) / 2 - branchText->boundingRect().width() / 2,(y + childY) / 2 - branchText->boundingRect().height() + 30);// 递归绘制子节点visualizeTree(scene, branch.second, childX, childY, dx / 2, dy);++index;}
}

项目源代码:Data-structure-coursework/3/Question_3 at main · CUGLin/Data-structure-courseworkhttps://github.com/CUGLin/Data-structure-coursework/tree/main/3/Question_3https://github.com/CUGLin/Data-structure-coursework/tree/main/3/Question_3

相关文章:

数据结构课程设计(三)构建决策树

3 决策树 3.1 需求规格说明 【问题描述】 ID3算法是一种贪心算法&#xff0c;用来构造决策树。ID3算法起源于概念学习系统&#xff08;CLS&#xff09;&#xff0c;以信息熵的下降速度为选取测试属性的标准&#xff0c;即在每个节点选取还尚未被用来划分的具有最高信息增益的…...

深度剖析八大排序算法

欢迎并且感谢大家指出我的问题&#xff0c;由于本人水平有限&#xff0c;有些内容写的不是很全面&#xff0c;只是把比较实用的东西给写下来&#xff0c;如果有写的不对的地方&#xff0c;还希望各路大牛多多指教&#xff01;谢谢大家&#xff01;&#x1f970; 在计算机科学领…...

python-leetcode-二叉树的层序遍历

102. 二叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff09; # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right from coll…...

毕业设计:基于深度学习的高压线周边障碍物自动识别与监测系统

目录 前言 课题背景和意义 实现技术思路 一、算法理论基础 1.1 卷积神经网络 1.2 目标检测算法 1.3 注意力机制 二、 数据集 2.1 数据采集 2.2 数据标注 三、实验及结果分析 3.1 实验环境搭建 3.2 模型训练 3.2 结果分析 最后 前言 &#x1f4c5;大四是整个大学…...

顺序表(ArrayList)

1、简介 顺序表是用一段物理地址连续 的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下 采用数组存储 。在 数组 上完成数据的增删查改。&#xff08; 顺序表的底层结构是一个数组 &#xff09; 2、顺序表的实现 下面是顺序表的一些基本成员和方法&#xff0c;能够…...

【Hadoop】Hadoop的HDFS

这里写目录标题 HDFS概述HDFS产出背景及定义HDFS产生背景HDFS定义 HDFS优缺点HDFS优点HDFS缺点 HDFS组成架构HDFS文件块大小 HDFS的Shell操作常用命令实操准备工作上传下载HDFS直接操作 HDFS的API操作客户端环境准备HDFS的API案例实操HDFS文件上传HDFS文件下载HDFS文件更名和移…...

C++ Primer 迭代器

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…...

使用 Postman 进行 API 测试:从入门到精通

使用 Postman 进行 API 测试&#xff1a;从入门到精通 使用 Postman 进行 API 测试&#xff1a;从入门到精通一、什么是 API 测试&#xff1f;二、Postman 简介三、环境搭建四、API 测试流程1. 收集 API 文档2. 发送基本请求示例&#xff1a;发送 GET 请求示例代码&#xff08;…...

Leetcode面试高频题分类刷题总结

https://zhuanlan.zhihu.com/p/349940945 以下8个门类是面试中最常考的算法与数据结构知识点。 排序类&#xff08;Sort&#xff09;&#xff1a; 基础知识&#xff1a;快速排序&#xff08;Quick Sort&#xff09;&#xff0c; 归并排序&#xff08;Merge Sort&#xff09;的…...

8.原型模式(Prototype)

动机 在软件系统中&#xff0c;经常面临着某些结构复杂的对象的创建工作&#xff1b;由于需求的变化&#xff0c;这些对象经常面临着剧烈的变化&#xff0c;但是它们却拥有比较稳定一致的接口。 之前的工厂方法和抽象工厂将抽象基类和具体的实现分开。原型模式也差不多&#…...

简单介绍一下什么是OpenFeign

OpenFeign是什么&#xff1f; OpenFeign是一个声明式的Http客户端&#xff0c;它可以用来发起Http请求 它主要用于SpringCloud微服务之间的通讯&#xff0c;让调用另一个服务的Java方法和调用本地方法一样快速和便捷 之前我们是用RestTemplate写一大堆东西发起Http请求远程调…...

力扣动态规划-20【算法学习day.114】

前言 ###我做这类文章一个重要的目的还是记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&#xff01;&#xff01;&#xff01; 习题 1.网格中的最小路径代价 题目链接…...

Codeforces Round 1002 (Div. 2)(部分题解)

补题链接 A. Milya and Two Arrays 思路&#xff1a;题意还是比较好理解&#xff0c;分析的话我加了一点猜的成分&#xff0c;对a&#xff0c;b数组的种类和相加小于4就不行&#xff0c;蒋老师的乘完后小于等于2也合理。 AC代码&#xff1a; #include <bits/stdc.h> u…...

在线销售数据集分析:基于Python的RFM数据分析方法实操训练

一、前言 个人练习&#xff0c;文章用于记录自己的学习练习过程&#xff0c;分享出来和大家一起学习。 数据集&#xff1a;在线销售数据集 分析方法&#xff1a;RFM分析方法 二、过程 1.1 库的导入与一些必要的初始设置 import pandas as pd import datetime import matplo…...

小程序设计和开发:要如何明确目标和探索用户需求?

一、明确小程序的目标 确定业务目标 首先&#xff0c;需要明确小程序所服务的业务领域和目标。例如&#xff0c;是一个电商小程序&#xff0c;旨在促进商品销售&#xff1b;还是一个服务预约小程序&#xff0c;方便用户预订各类服务。明确业务目标有助于确定小程序的核心功能和…...

【C语言深入探索】:指针高级应用与极致技巧(二)

目录 一、指针与数组 1.1. 数组指针 1.2. 指向多维数组的指针 1.2.1. 指向多维数组元素的指针 1.2.2. 指向多维数组行的指针 1.3. 动态分配多维数组 1.4. 小结 二、指针与字符串 2.1. 字符串表示 2.2. 字符串处理函数 2.3. 代码示例 2.4. 注意事项 三、指针与文件…...

2.策略模式(Strategy)

定义 定义一系列算法&#xff0c;把它们一个个封装起来&#xff0c;并且使他们可互相替换&#xff08;变化&#xff09;。该模式使算法可独立于使用它的客户程序&#xff08;稳定&#xff09;而变化&#xff08;拓展&#xff0c;子类化&#xff09;。 动机&#xff08;Motiva…...

手写MVVM框架-构建虚拟dom树

MVVM的核心之一就是虚拟dom树&#xff0c;我们这一章节就先构建一个虚拟dom树 首先我们需要创建一个VNode的类 // 当前类的位置是src/vnode/index.js export default class VNode{constructor(tag, // 标签名称&#xff08;英文大写&#xff09;ele, // 对应真实节点children,…...

【Blazor学习笔记】.NET Blazor学习笔记

我是大标题 我学习Blazor的顺序是基于Blazor University&#xff0c;然后实际内容不完全基于它&#xff0c;因为它的例子还是基于.NET Core 3.1做的&#xff0c;距离现在很遥远了。 截至本文撰写的时间&#xff0c;2025年&#xff0c;最新的.NET是.NET9了都&#xff0c;可能1…...

C++11中的bind

官方文档对于bind接口的概述解释&#xff1a;Bind function arguments 在C11中&#xff0c;std::bind 是一个非常有用的工具&#xff0c;用于将函数、成员函数或函数对象与特定的参数绑定在一起&#xff0c;生成一个新的可调用对象。std::bind 可以用于部分应用函数参数、改变…...

llama.cpp的C语言API使用

我们知道&#xff0c;一般运行大语言模型都是在Python上运行的&#xff0c;可是Python的性能太差了&#xff0c;不适合用于生产环境&#xff0c;因此可以采用llama.cpp提供的API在C语言上运行大模型。 llama.cpp的下载 Windows下的下载 我们需要下载llama.cpp的两个部分&…...

鼠标拖尾特效

文章目录 鼠标拖尾特效一、引言二、实现原理1、监听鼠标移动事件2、生成拖尾元素3、控制元素生命周期 三、代码实现四、使用示例五、总结 鼠标拖尾特效 一、引言 鼠标拖尾特效是一种非常酷炫的前端交互效果&#xff0c;能够为网页增添独特的视觉体验。它通常通过JavaScript和C…...

基于 docker 的mysql 5.7 主备集群搭建

创建挂载目录和配置文件 主节点 mkdir -p /mysql_master/mysql/log mkdir -p /mysql_master/mysql/data mkdir -p /mysql_master/mysql/conf vim /mysql_master/mysql/conf/my.cnf[mysqld] datadir/var/lib/mysql #MySQL 数据库文件存放路径 server_id 1 #指定数据库服务器的…...

金山打字游戏2010绿色版,Win7-11可用DxWnd完美运行

金山打字游戏2010绿色版&#xff0c;Win7-11可用DxWnd完美运行 链接&#xff1a;https://pan.xunlei.com/s/VOIAYCzmkbDfdASGJa_uLjquA1?pwd67vw# 进入游戏后&#xff0c;如果输入不了英文字母&#xff08;很可能是中文输入状态&#xff09;&#xff0c;就按一下“Shift”键…...

爬虫学习笔记之Robots协议相关整理

定义 Robots协议也称作爬虫协议、机器人协议&#xff0c;全名为网络爬虫排除标准&#xff0c;用来告诉爬虫和搜索引擎哪些页面可以爬取、哪些不可以。它通常是一个叫做robots.txt的文本文件&#xff0c;一般放在网站的根目录下。 robots.txt文件的样例 对有所爬虫均生效&#…...

(10) 如何获取 linux 系统上的 TCP 、 UDP 套接字的收发缓存的默认大小,以及代码范例

&#xff08;1&#xff09; 先介绍下后面的代码里要用到的基础函数&#xff1a; 以及&#xff1a; &#xff08;2&#xff09; 接着给出现代版的 读写 socket 参数的系统函数 &#xff1a; 以及&#xff1a; &#xff08;3&#xff09; 给出 一言的 范例代码&#xff0c;获取…...

【玩转 Postman 接口测试与开发2_016】第13章:在 Postman 中实现契约测试(Contract Testing)与 API 接口验证(上)

《API Testing and Development with Postman》最新第二版封面 文章目录 第十三章 契约测试与 API 接口验证1 契约测试的概念2 契约测试的工作原理3 契约测试的分类4 DeepSeek 给出的契约测试相关背景5 契约测试在 Postman 中的创建方法6 API 实例的基本用法7 API 实例的类型实…...

25.02.04 《CLR via C#》 笔记14

第二十一章 托管堆和垃圾回收 内存分配过程 CLR维护一个“下一次分配指针”&#xff08;NextObjPtr&#xff09;&#xff0c;指向当前托管堆中第一个可用的内存地址 计算类型所需的字节数&#xff0c;加上对象开销&#xff08;类型对象指针、同步块索引&#xff09;所需字节数…...

day8-面向对象

目录 面向对象1、面向对象介绍2、类和对象类和对象类的几个补充注意事项 3、封装 面向对象 1、面向对象介绍 ⭐️面向对象介绍&#xff1a; 面向&#xff1a;拿、找对象&#xff1a;能干活的东西面向对象编程&#xff1a;拿东西过来做对应的事情 面向对象编程的例子&#x…...

Pyside6 的QObject 类

PySide6 中的 QObject 是 Qt 框架的核心基类&#xff0c;所有需要信号与槽、事件处理、内存管理的对象均需要继承自它。以下是关于 QObject 的详细说明&#xff0c;从功能、关键特性到实际代码示例进行阐述&#xff1a; 1. 核心功能 QObject 提供了以下基本能力&#xff1a; …...