FlutterUnit 周边 | 收录排序算法可视化

news2024/9/22 17:32:19

theme: cyanosis

1. FlutterUnit 更新:排序算法可视化

排序算法可视化是用视图层表现出算法执行过程中排序的过程,感谢 编程的平行世界 在 《十几种排序算法的可视化效果,快来看看!👀》》 一文中提供的算法支持。我进行了一些代码和交互上的优化,将其集成到了 FlutterUnit 中,大家可以在 release v2.9.3 下载全平台应用查看体验 ~

image.png


掘金目前已经支持插入视频了,但目前支持西瓜视频。下面通过两个视频来看一下效果:

移动端: 交互视频

jvideo

桌面端: 交互视频

jvideo


2. 交互界面介绍

在移动端,排序算法可视化被放在 知识/可视排序 页签下,左上角的绿色按钮点击后启动排序,从而驱动数字列表数据变化,更新主界面产生排序的动态效果。下拉可以展开排序算法列表,选择对应的算法进行排序:

| 标题 | | | --- | --- | | 0240f2d1ca9b3778246fa722d1382bc.jpg | 433d6cab476b3dbc51ac22ed58b6854.jpg |

在桌面端,排序算法可视化先放在 可视排序 侧栏导航下,以后可能会拓展其他的有趣案例。

image.png

另外排序有设置界面,可以设置配置参数。

个数表示数据的数量,每个数据对应主界面中的一个线条。
间隔时长是排序过程中每步间的停顿时间,单位是微秒。
随机种子是随机数的种子,不为 -1 的话,相同的种子,每次重置生成的随机数列表一致。便于比较不排序算法下,同一组数据表现。

image.png


3. 项目的结构

这里核心代码新建了一个 algorithm 的包来单独维护,其中 algorithm/sort 文件夹中盛放排序的具体算法。把它们分文件放置,更便于阅读。

image.png


algorithm/data_scope 中,用于维护界面中的数据;在 algorithm/views 中处理视图组件的构建。

image.png


最后在 pubspec.yaml 中通过 path 引入本地的包,就可以在主项目中使用 algorithm 包中的组件进行展示。比如下面,在侧栏导航中添加一个 可视排序 的菜单栏,对应 DeskSortPage 组件。

yaml algorithm: path: packages/algorithm

image.png


4. 代码实现细节:算法方面

可视化排序的思路是:在每次排序列表数据发生变化时,通过回调来通知处理。这里定义 SortCallback 类型方便维护,其返回 Future<void> 对象,可以回调排序过程中此时的列表数据。

dart typedef SortCallback = Future<void> Function(List<int> dist);

拿冒泡排序来说,定义 bubbleSort 函数,传入待排序的数字列表,每次循环完成,出发 callback 通知调用者。比如想要放慢排序的过程,每一步可以等待一定的时间,也就是设置中的间隔微秒数。

dart ///冒泡排序 Future<void> bubbleSort(List<int> src, SortCallback callback) async{ //控制需要进行排序的次数。每一轮循环都会确定一个数字的最终位置。 for (int i = 0; i < src.length; ++i) { //遍历当前未排序的元素,通过相邻的元素比较并交换位置来完成排序。 for (int j = 0; j < src.length - i - 1; ++j) { //如果 _numbers[j] 大于 _numbers[j + 1],则交换它们的位置,确保较大的元素移到右边。 if (src[j] > src[j + 1]) { int temp = src[j]; src[j] = src[j + 1]; src[j + 1] = temp; } //实现一个延迟,以便在ui上展示排序的动画效果 await callback(src); } } }

另外排序的函数结构都是一致的,输入待排序列表与回调,可以通过 typedef 定义一个排序函数类型 SortFunction

dart typedef SortFunction = Future<void> Function(List<int> src, SortCallback callback);

这样就可以维护排序的名称和排序函数间的映射关系:

dart Map<String, SortFunction> sortFunctionMap = { 'insertion': insertionSort, 'bubble': bubbleSort, 'cocktail': cocktailSort, 'comb': combSort, 'pigeonHole': pigeonHoleSort, 'shell': shellSort, 'selection': selectionSort, 'gnome': gnomeSort, 'cycle': cycleSort, 'heap': heapSort, 'quick': quickSort, 'merge': mergeSort, };


5. 代码实现细节:数据方面

数据方面的代码在 data_scope 包中,这里排序界面中的数据有三大类:

其一是待排序数字列表。
其二是配置的参数。
其三是排序状态。

配置参数包括四个,通过 SortConfig 类维护:

```dart class SortConfig { final int count; // 列表数字数量 final int seed; // 随机数种子 final Duration duration; // 间隔时长 final String name; // 算法名称

SortConfig({ this.count = 100, this.duration = const Duration(microseconds: 1500), this.seed = -1, this.name = 'insertion', });

SortConfig copyWith({ int? count, int? seed, Duration? duration, String? name, }) => SortConfig( count:count??this.count, seed:seed??this.seed, duration:duration??this.duration, name:name??this.name, ); } ```


排序状态通过 SortStatus 枚举定义:

dart enum SortStatus{ none, // 未操作 sorting, // 排序中 sorted, // 排序完成 }


排序界面整体的数据状态通过 SortState 维护,它继承自 ChangeNotifier,可以在数据变化时调用 notifyListeners 通知监听者,从而实现界面的更新。 SortState 调用 sort 方法触发排序,会根据排序算法名,从 sortFunctionMap 中拿到排序算法调用。每次回调时触发 notifyListeners 方法通知更新。

```dart class SortState with ChangeNotifier{

SortState(){ reset(); }

SortStatus status = SortStatus.none; List data = []; SortConfig _config = SortConfig(); SortConfig get config => _config; Random random = Random();

set config(SortConfig config){ _config = config; reset(); notifyListeners(); }

void reset(){ data.clear(); status = SortStatus.none; notifyListeners(); int count = config.count; if(config.seed!=-1){ random = Random(config.seed); } for (int i = 0; i < count; i++) { data.add(random.nextInt(1000)); } }

void sort() async{ status = SortStatus.sorting; notifyListeners(); SortFunction? sortFunction = sortFunctionMap[config.name]; if(sortFunction!=null){ await sortFunction(data,(arr) async { await Future.delayed(config.duration); notifyListeners(); }); } status = SortStatus.sorted; notifyListeners(); } } ```


6. 代码实现细节:界面方面

这里目前没有使用三方状态管理包,而是通过 Flutter 内部的 InheritedNotifier 完成子树共享可监听数据的任务。

```dart class SortStateScope extends InheritedNotifier { const SortStateScope({ required super.notifier, required super.child, super.key, });

static SortState of(BuildContext context) => context.dependOnInheritedWidgetOfExactType ()!.notifier!; } ```

如果某个组件是数据的依赖者,在可监听对象发生变化时,会通知其更新。拿 SortButton 来说,他需要依赖排序状态 SortStatus 数据来展示不同的图标,或响应不同的事件。使用 SortStateScope.of(context) 相当于依赖了数据,那么数据(SortState)在 notifyListeners 时,就会通知 SortButton 进行重新构建,这就是 InheritedNotifier 组件的功能。

| none | sorting |sorted | | --- | --- |--- | | image.png | image.png |image.png

```dart class SortButton extends StatelessWidget { const SortButton({super.key});

@override Widget build(BuildContext context) { SortState state = SortStateScope.of(context); VoidCallback? action; IconData icon; Color color; switch (state.status) { case SortStatus.none: icon = Icons.notstartedoutlined; color = Colors.green; action = state.sort; break; case SortStatus.sorting: icon = Icons.stopcircleoutlined; color = Colors.grey; action = null; break; case SortStatus.sorted: icon = Icons.refresh; color = Colors.black; action = state.reset; break; }

return GestureDetector(
  onTap: action,
  child: Icon(
    icon,
    color: color,
  ),
);

} } ```


最后,主体界面通过 CustomPainter 对数字列表进行绘制,遍历数据根据数值大小绘制不同高度的线条。

```dart class DataPainter extends CustomPainter { final List data;

DataPainter({required this.data});

@override void paint(Canvas canvas, Size size) { canvas.clipRect(Offset.zero & size); double itemWidth = size.width / data.length;

Paint paint = Paint();
paint.strokeWidth = itemWidth;
paint.strokeCap = StrokeCap.round;

for (int i = 0; i < data.length; i++) {
  int value = data[i];
  if (value < 1000 * .10) {
    paint.color = Colors.blue.shade100;
  } else if (value < 1000 * .20) {
    paint.color = Colors.blue.shade200;
  } else if (value < 1000 * .30) {
    paint.color = Colors.blue.shade300;
  } else if (value < 1000 * .40) {
    paint.color = Colors.blue.shade400;
  } else if (value < 1000 * .50) {
    paint.color = Colors.blue.shade500;
  } else if (value < 1000 * .60) {
    paint.color = Colors.blue.shade600;
  } else if (value < 1000 * .70) {
    paint.color = Colors.blue.shade700;
  } else if (value < 1000 * .80) {
    paint.color = Colors.blue.shade800;
  } else if (value < 1000 * .90) {
    paint.color = Colors.blue.shade900;
  } else {
    paint.color = const Color(0xFF011E51);
  }
  canvas.drawLine(
      Offset(i * itemWidth + itemWidth / 2, 0),
      Offset(
        i * itemWidth + itemWidth / 2,
        size.height * (value / 1000),
      ),
      paint);
}

}

@override bool shouldRepaint(covariant DataPainter oldDelegate) { return true; } } ```

整个核心的逻辑就是这些,有兴趣的可以自己查阅 FlutterUnit 中的相关代码,那么本文就到这里,谢谢观看,我们下次再见~

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

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

相关文章

【Proteus仿真】【Arduino单片机】继电器和按键

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用蜂鸣器、按键、继电器、电机等。 主要功能&#xff1a; 系统运行后&#xff0c;K1键控制蜂鸣器发声&#xff0c;K2键控制LED开关&#xff0c;…

计算机图形学——二维变换

二维变换 概念 应用于对象几何描述并改变其位置、方向或者大小的变换叫做几何变换&#xff0c;有时候也被叫做建模变换。而本文仅讨论平面中的几何变换&#xff0c;即二维变换。 矩阵表示和齐次坐标 对于普通的2x2矩阵&#xff0c;我们总是要将平移项与其它变换对应的矩阵写…

MYSQL表的连接方式

mysql表连接方式可以分为 1、内连接 2、外连接 3、全连接 4、交叉连接 t1表 t2表 1、内连接&#xff0c;包括自然连接&#xff0c;等值连接&#xff0c;不等值连接 1.1、自然连接&#xff0c;根据相同字段进行连接匹配…

容联七陌百度营销通BCP解决方案,让营销更精准

百度营销通作为一个快速迭代、满足客户多元化营销需求的高效率营销工具成为众多企业的选择&#xff0c;通过百度营销通BCP对接&#xff0c;企业就可以在百度咨询页接入会话&#xff0c;收集百度来源的访客搜索关键词&#xff0c;通过百度推广获取更多的精准客户&#xff0c;从而…

基于JAVA的天猫商场系统设计与实现,springboot+jsp,MySQL数据库,前台用户+后台管理,完美运行,有一万五千字论文

目录 演示视频 基本介绍 论文目录 系统截图 演示视频 基本介绍 基于JAVA的天猫商场系统设计与实现&#xff0c;springbootjsp&#xff0c;MySQL数据库&#xff0c;前台用户后台管理&#xff0c;完美运行&#xff0c;有一万五千字论文。 本系统在HTML和CSS的基础上&#xf…

计算机起源(二)

一、前言 冯诺依曼奠定了计算机体系结构后&#xff0c;早期的计算机是没有操作系统的&#xff0c;还是需要大量的人为参与&#xff0c;比如纸卡打孔。通过纸卡上的方格&#xff0c;打孔来表示二进制数。那么如果能使计算机自动能够进行计算&#xff0c;就需要一个模拟人工的操…

Node学习笔记之使用Express框架开发接口

我们利用nodeexpressmysql开发接口&#xff0c;对数据库数据进行简单增、删、查改等操作。 工具 数据库可视化 接口测试工具Postman 1、初始化 我们这里利用nodeexpressmysql开发一个简单的书城商店API。后面会使用result API规范接口 1、创建项目 新建文件夹server 安装依…

记:2023香山杯-Ez加密器-题目复现和学习记录““

文章目录 前言题目分析and调试过程完整exp 前言 前段时间的比赛&#xff0c;那会刚入门o(╥﹏╥)o都不会写&#xff0c;现在复现一下。 题目分析and调试过程 查壳nie 进入IDA&#xff0c;shiftF12查找下字符串看看&#xff0c;定位过去 先用N重命名一下函数&#xff0c;方便…

GPDB7-新特性-角色创建

GPDB7-新特性-角色创建 9月GPDB7发布了release版本&#xff0c;新增了很多新特性及性能改进&#xff0c;对GPDB用户带来福音。业务在调研GPDB6升级到GPDB7的过程中&#xff0c;生产环境会创建用户&#xff0c;利用这些用户进行迁移。但是出现问题了&#xff0c;竟然会报&#x…

如何使用Linux编写STM32程序并且烧录

前言 &#xff08;1&#xff09;如果有嵌入式企业需要招聘湖南区域日常实习生&#xff0c;任何区域的暑假Linux驱动实习岗位&#xff0c;可C站直接私聊&#xff0c;或者邮件&#xff1a;zhangyixu02gmail.com&#xff0c;此消息至2025年1月1日前均有效 &#xff08;2&#xff0…

Z41H-64C高压闸阀型号解析

Z41H-64C型号字母含义 Z41H-64C型号是德特森阀门常用的高压闸阀型号字母分别代表的意思是: Z——代表阀门类别《闸阀》 4——代表连接方式《法兰》 1——代表结构形式《明杆》 H——代表密封堆焊《硬质合金》 -《分隔键》 64——代表公称压力《6.4MPA》 C——代表阀体材…

RT-Thread 6. ENV增加组件(从服务器下载得到)

键入“Y”、或者空格选中 保存 保存之后&#xff0c;自动修改这个文件 退回到ENV界面&#xff0c;输入&#xff1a;pkgs --update 多了 如果用keil4编译的话&#xff0c;输入&#xff1a;scons --targetmdk4&#xff0c;重新生成keil4工程&#xff0c;双击“project.uvpro…

10-类加载器

类加载器 类与类加载器 判断类是否“相等” 任意一个类&#xff0c;都由加载它的类加载器和这个类本身一同确立其在 Java 虚拟机中的唯一性&#xff0c;每一个类加载器&#xff0c;都有一个独立的类名称空间。 因此&#xff0c;比较两个类是否“相等”&#xff0c;只有在这…

北邮22级信通院数电:Verilog-FPGA(6)第六周实验:全加器(关注我的uu们加群咯~)

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 作者建群啦&#xff01;&#xff01;&#xff01;欢…

【计网 P2P】计算机网络 P2P(Peer to Peer)详解:中科大郑烇老师笔记 (七)

目录 0 引言1 C/S 模式 VS P2P模式2 P2P 概述2.1 纯P2P架构2.2 非结构化P2P和结构化&#xff08;DHT&#xff09;P2P2.2.1 非结构化P2P2.2.1 结构化P2P 2.3 P2P需要解决的问题及解决方案2.3.1 集中式目录2.3.2 完全分布式2.3.3 混合体 &#x1f64b;‍♂️ 作者&#xff1a;海码…

智能井盖监测系统功能,万宾科技传感器效果

智能井盖传感器的出现是高科技产品的更新换代&#xff0c;同时也是智慧城市建设中的需求。在智慧城市建设过程之中&#xff0c;高科技产品的应用数不胜数&#xff0c;智能井盖传感器的出现&#xff0c;解决了城市道路安全保护着城市地下生命线&#xff0c;改善着传统井盖带来的…

【Qt样式(qss)-5】qss局部渲染混乱,错乱,不生效的一种原因

前言&#xff1a; 之前写过一些关于qss的文章&#xff1a; 【Qt样式&#xff08;qss&#xff09;-1】手册小结&#xff08;附例&#xff1a;软件深色模式&#xff09;_深蓝色主题qss表-CSDN博客 【Qt样式&#xff08;qss&#xff09;-2】使用小结&#xff08;软件换肤&#…

拆贡献+统计非法可能不统计非法贡献:ARC150D

https://atcoder.jp/contests/arc150/tasks/arc150_d 先拆贡献成每个点&#xff0c;然后就只需要考虑这条链上的情况了 我们现在要求的是&#xff1a; 在所有点选完之前&#xff0c;最后一个点被选了多少次 我们发现这很难做&#xff0c;但有个性质&#xff1a; 在所有点选…

国外创意二维码案例:利马博物馆的二维码艺术展!

今天我们要分享的品牌创意二维码案例来自国外一家博物馆。 2022年12月&#xff0c;位于秘鲁的利马艺术博物馆策划并展出了一场别开生面的艺术展。和以往的展览不同&#xff0c;这次展览的主角是一些艺术画作“雕刻”而成的二维码。 利马博物馆&#xff08;The Lima Art Museum…

OPC UA:工业领域的“HTML”

OPC UA是工业自动化领域的一项重要的通信协议。它的特点是包括了信息模型构建方法。能够建立工业领域各种事物的信息模型。在工业自动化行业&#xff0c;OPCUA 类似互联网行业的HTTP协议和“HTML”语言。能够准确&#xff0c;可靠地描述复杂系统中各个元素&#xff0c;并且实现…