20. 图(2):图的储存结构

本文介绍了图的两种主要存储结构——邻接矩阵和邻接表。邻接矩阵适用于存储边信息,尤其是带有权值的网,但对于边数较少的图,存在空间浪费。邻接表则通过链表解决空间效率问题,尤其适合边数远小于顶点数的图。内容详细阐述了无向图和有向图在两种结构下的实现,并提及了边集数组作为补充。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  图的存储结构相比较线性表与树来说就复杂很多。我们回顾下,对于线性表来说,是一对一的关系,所以用数组或者链表均可简单存放。树结构是一对多的关系,所以我们要将数组和链表的特性结合在一起才能更好的存放。那么我们的图,是多对多的情况,另外图上的任何一个顶点都可以被看作是第一个顶点,任一顶点的邻接点之间也不存在次序关系。如下图所示

  我们可以看出,这四幅图实际上是相同的图。因为任意两个顶点之间都可能存在联系,因此无法以数据元素在内存中的物理位置来表示元素之间的关系(内存物理位置是线性的,图的元素关系是平面的)。如果用多重链表来描述倒是可以做到,但在几节课前的树章节我们已经讨论过,纯粹用多重链表导致的浪费是无法想像的(如果各个顶点的度数相差太大,就会造成巨大的浪费)。

  因此下面将介绍五种可用的数据结构,重点介绍前两种,后面三种作为一种拓展。

1. 邻接矩阵

  考虑到图是由顶点和边或弧两部分组成,合在一起比较困难,那就很自然地考虑到分为两个结构来分别存储。顶点因为不区分大小、主次,所以用一个一维数组来存储是狠不错的选择。而边或弧由于是顶点与顶点之间的关系,一维数组肯定就搞不定了,那我们不妨考虑用一个二维数组来存储。

1.1 无向图的邻接矩阵

  图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息,如下图所示

import QtQuick 2.12 import QtQuick.Controls 2.12 Rectangle { id: mainRect property bool storage: false //储存 property bool subMenu: false property bool start //是否为录屏时 property string message: "" focus: true color: "#4c4c4c" width: 100 height: 100 radius: 5 // 矩形的圆角半径 border.width: 2 // 边框的宽度 border.color: "#4c4c4c" anchors.horizontalCenter: parent.horizontalCenter Column { anchors.verticalCenter: parent.verticalCenter Text { id: statusText text: message font.pointSize: 30 // 增大字体大小 font.bold: true // 设置字体加粗 color: "white" visible: true // 始终可见 anchors.topMargin: 20 anchors.horizontalCenter: parent.horizontalCenter } } Timer { id: statusCheckTimer interval: 1000 // 检查间隔(毫秒) running: true // 自动启动 repeat: true // 循环执行 triggeredOnStart: true // 立即执行首次检查 onTriggered: { // 状态同步逻辑 } } function updateMessage() { if (storage) { message = start ? "录屏ing...." : "中键录屏+暂停" } else { message = "未检测到存储设备" } } // 当 subMenu 状态发生变化时触发 onSubMenuChanged: { if(storage) { if(!start) // 处理录屏开始 { if (subMenu) { backend.video(); message = "录屏ing...."; start = true; subMenu = false; pathview.forceActiveFocus(); } } else if(start) // 处理录屏停止 { if (subMenu) { message = "录屏已经停止"; backend.video_stop(); start = false; subMenu = false; pathview.forceActiveFocus(); } } } else if(!storage) // 处理没有存储设备的情况 { if (subMenu) { subMenu = false; pathview.forceActiveFocus(); } } // else if(!subMenu) // { // message = "未检测到存储设备"; // pathview.forceActiveFocus() // } } Keys.onReturnPressed: { if(start) { if (storage) { message = "录屏已经停止"; backend.video_stop(); subMenu = false; pathview.forceActiveFocus(); } event.accepted = true // 接受事件 } } Keys.onUpPressed: { subMenu = false; pathview.forceActiveFocus(); keyboard.simulateKeyPressAndRelease(Qt.Key_Up) } Keys.onDownPressed: { subMenu = false; pathview.forceActiveFocus(); keyboard.simulateKeyPressAndRelease(Qt.Key_Down) } Component.onCompleted: { console.log("初始化完成。"); subMenu = true; storage = backend.monitor_SD(); start = backend.return_start(); if (storage) { if(start) { message = "录屏ing...."; }else{message = "中键录屏+暂停";} } else { message = "未检测到存储设备"; } } } 在这里怎么声明变量
最新发布
03-27
<think>好的,我现在要帮助用户解决在QtQuick/QML中如何声明变量的问题。首先,我需要仔细看看用户提供的代码,找出他们当前声明变量的方式以及可能存在的问题。 用户提供的代码是一个Rectangle组件,里面有一些属性和函数。用户提到想要在QML中声明变量,但可能对现有的方法不太清楚,或者有特定的需求需要满足。根据用户之前的提问历史,他们之前询问过条件判断逻辑,现在转向变量声明,可能是在开发过程中遇到了相关问题。 首先,我需要回忆QML中的变量声明机制。在QML中,通常可以通过两种方式声明变量:使用property关键字声明属性,或者在函数内部使用var或let声明局部变量。属性(properties)是组件的特性,可以在整个组件内访问,并且可以绑定到其他属性或表达式。而局部变量则只在函数的作用域内有效。 观察用户的代码,他们已经在Rectangle中使用property声明了一些变量,比如storage、subMenu、start、message等。这些属性都是根组件的属性,可以在内部任何地方访问,包括子组件和函数。用户可能在问如何正确声明这些属性,或者是否有其他方式声明变量。 接下来,我需要检查用户现有的代码是否存在变量声明的问题。例如,是否有地方需要局部变量,而用户错误地使用了属性,或者反之。比如,在updateMessage函数中,用户可能不需要声明新的属性,而是直接使用现有的属性。另外,在onTriggered处理函数中,用户可能需要临时变量来存储中间结果,这时候应该使用var或let。 然后,我需要考虑用户可能的疑问点。例如,属性与局部变量的区别,何时使用哪种方式声明,以及作用域的问题。用户可能在函数内部需要临时变量,这时候应该用var,而如果是需要跨组件或跨函数访问的变量,则应该声明为property。 此外,用户可能在代码中遗漏了一些必要的变量声明,或者错误地重复声明。例如,在Timer的onTriggered处理程序中,是否需要声明变量来存储backend.monitor_SD()的结果?这时候可能需要一个局部变量,或者直接使用现有属性storage。 还需要注意QML的语法规范,确保用户声明的变量符合类型要求。例如,使用property bool声明布尔类型,property string声明字符串类型等。如果用户没有正确指定类型,可能会导致绑定或更新问题。 最后,结合用户提供的代码,他们可能在Component.onCompleted中初始化变量,但需要确认是否正确。例如,storage被赋值为backend.monitor_SD(),start被赋值为backend.return_start(),这些都是正确的初始化方式。 总结用户的需求:他们希望了解在提供的QML代码中如何正确声明变量,可能需要区分属性声明和局部变量声明,以及正确的语法和使用场景。需要给出清晰的步骤说明,包括属性声明的位置、类型、命名规范,以及局部变量的使用示例,并指出可能需要注意的问题,如作用域、类型匹配等。</think>在 QtQuick/QML 中声明变量可分为 **组件级属性** 和 **函数内局部变量** 两种形式,以下是针对你代码的具体实现指导: --- ### 一、组件级属性声明 (全局可用) 在 `Rectangle` 根组件中声明,使用 `property <类型> 变量名` 语法: ```qml Rectangle { id: mainRect // ✅ 标准属性声明 property bool storage: false // 存储设备状态 property bool subMenu: false // 子菜单状态 property bool start: false // 录屏状态 property string message: "" // 显示文本 property int retryCount: 3 // 新增整型变量示例 // ✅ 派生属性(自动计算) readonly property color borderColor: storage ? "green" : "red" } ``` --- ### 二、函数内局部变量 (仅在函数内有效) 在 JavaScript 函数中使用 `var` 或 `let` 声明: ```qml function updateMessage() { // ✅ 局部变量(仅在函数内有效) var currentTime = new Date().toLocaleTimeString() let debugInfo = "状态更新于: " + currentTime if (storage) { message = start ? "录屏ing...." + debugInfo : "中键录屏+暂停" } else { message = "未检测到存储设备 | " + debugInfo } } ``` --- ### 三、针对你代码的优化建议 #### 1. 初始化逻辑优化 在 `Component.onCompleted` 中集中初始化: ```qml Component.onCompleted: { storage = backend.monitor_SD() start = backend.return_start() message = storage ? (start ? "录屏ing...." : "中键录屏+暂停") : "未检测到存储设备" } ``` #### 2. 定时器状态检查 在 `Timer` 中同步状态: ```qml Timer { onTriggered: { let previousStorage = storage // ✅ 使用局部变量保存旧值 storage = backend.monitor_SD() if (previousStorage !== storage) { updateMessage() } } } ``` --- ### 四、关键注意事项 1. **类型明确性** 优先使用具体类型声明(如 `bool`/`string`/`int`),避免默认 `var` 类型导致的隐式转换问题 2. **响应式更新** 属性变化时自动触发绑定(例如 `message` 变化会自动更新 `Text` 显示) 3. **作用域控制** 组件级属性可被子项访问,局部变量仅在函数内有效 --- 通过这种结构化声明方式,既能保持代码可维护性,又能充分利用 QML 的响应式特性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值