学习冒泡排序的可视化实现(一)

文章目录

  • 学习冒泡排序的可视化实现(一)
    • 1.确保已经具备rust code environment;
    • 2.创建新项目;
    • 3.添加依赖项
    • 4.初步展示图形化成果
    • 5.优化图形化展示
      • 实现思路:
    • 6.整体优化

学习冒泡排序的可视化实现(一)

使用Rust实现冒泡排序的图形化,需要两个主要组件:Rust编程语言本身来实现冒泡排序算法,以及一个图形库来进行可视化。

使用piston_window库作为图形界面,因为它相对简单易用,适合入门级的项目。

1.确保已经具备rust code environment;

2.创建新项目;

cargo new rust_bubble_sort_visualization
cd rust_bubble_sort_visualization

3.添加依赖项

在项目文件中的cargo.toml文件中添加依赖项;

[dependencies]
piston_window = "0.120.0"

4.初步展示图形化成果

使用cargo run运行代码后可以看见显示的红色矩形图;

extern crate piston_window;
use piston_window::*;fn bubble_sort(arr: &mut Vec<i32>) {let mut n = arr.len();let mut swapped = true;while swapped {swapped = false;for i in 1..n {if arr[i - 1] > arr[i] {arr.swap(i - 1, i);swapped = true;}}n -= 1;}
}fn main() {let mut window: PistonWindow = WindowSettings::new("Bubble Sort Visualization", [640, 480]).exit_on_esc(true).build().unwrap();let mut numbers = vec![10, 30, 20, 50, 40];bubble_sort(&mut numbers);while let Some(e) = window.next() {window.draw_2d(&e, |c, g, _| {clear([0.0, 0.0, 0.0, 1.0], g); // 清除屏幕// 绘制排序后的数组for (i, &val) in numbers.iter().enumerate() {rectangle([1.0, 0.0, 0.0, 1.0], // 红色[i as f64 * 100.0, 0.0, 50.0, val as f64], // 矩形位置和大小c.transform, g);}});}
}

5.优化图形化展示

  • 实时可视化排序过程

    • 将排序逻辑与绘图逻辑更紧密地结合起来。一种方法是,在每次交换元素后立即重新绘制界面。然而,由于Piston的事件循环是连续运行的,直接在排序函数中添加绘图逻辑可能会导致程序逻辑变得复杂。
  • 添加用户交互元素

  • 分步执行排序:通过全局状态控制排序的每一步执行。例如,您可以使用一个全局变量来记录当前排序的进度,并在每次窗口绘制事件中只执行一次或几次元素比较和交换。

  • 处理输入事件:监听键盘或鼠标事件来控制排序的开始、暂停和重置。例如,您可以在按下特定键时开始排序,并在再次按下时暂停。

  • 绘制控制按钮:在窗口中绘制表示开始、暂停和重置操作的按钮,并处理点击这些按钮的事件。

实现思路:

定义控制状态变量:在main函数中,定义几个变量来表示排序的状态(是否正在排序、是否暂停等)和一个变量来存储原始数组以方便重置。

let mut is_sorting = false;
let mut is_paused = false;
let original_numbers = numbers.clone();

处理键盘事件:在事件循环中,使用match语句来检测和响应键盘事件。例如,我们可以约定使用“S”键开始排序、“P”键暂停或恢复排序、“R”键重置数组到初始状态。

if let Some(Button::Keyboard(key)) = e.press_args() {match key {Key::S => {is_sorting = true;is_paused = false;},Key::P => {if is_sorting {is_paused = !is_paused;}},Key::R => {numbers = original_numbers.clone();is_sorting = false;is_paused = false;n = total_numbers;},_ => {}}
}

调整排序逻辑以响应状态变量:在绘制循环中,根据is_sorting和is_paused变量的值来决定是否执行排序步骤。如果is_sorting为true且is_paused为false,则执行一步排序操作。

if is_sorting && !is_paused && n > 1 {let mut swapped = false;for i in 1..n {if numbers[i - 1] > numbers[i] {numbers.swap(i - 1, i);swapped = true;break; // 在每次交换之后退出循环以重新绘制}}if !swapped {n -= 1;}if n <= 1 {is_sorting = false; // 排序完成}
}

完整代码

extern crate piston_window;
use piston_window::*;fn main() {let mut window: PistonWindow = WindowSettings::new("Bubble Sort Visualization", [640, 480]).exit_on_esc(true).build().unwrap();let mut numbers = vec![10, 30, 20, 50, 40];let original_numbers = numbers.clone(); // 保存原始数组以便重置let mut is_sorting = false;let mut is_paused = false;let mut i = 0;let mut n = numbers.len();while let Some(e) = window.next() {// 处理键盘事件if let Some(Button::Keyboard(key)) = e.press_args() {match key {Key::S => { // 开始排序is_sorting = true;is_paused = false;},Key::P => { // 暂停/恢复排序if is_sorting {is_paused = !is_paused;}},Key::R => { // 重置数组和状态numbers = original_numbers.clone();is_sorting = false;is_paused = false;i = 0;n = numbers.len();},_ => {}}}// 根据状态执行排序逻辑if is_sorting && !is_paused && i < n - 1 {for j in 0..n-i-1 {if numbers[j] > numbers[j+1] {numbers.swap(j, j+1);break; // 在每次交换之后退出循环以重新绘制}}i += 1;} else if i >= n - 1 {i = 0; // 重置i以循环排序过程}window.draw_2d(&e, |c, g, _| {clear([0.0, 0.0, 0.0, 1.0], g); // 清除屏幕// 绘制数组for (i, &val) in numbers.iter().enumerate() {rectangle([1.0, 0.0, 0.0, 1.0], // 红色[i as f64 * 100.0, 480.0 - val as f64 * 10.0, 50.0, val as f64 * 10.0], // 矩形位置和大小c.transform, g);}});}
}

6.整体优化

将冒泡排序逻辑抽象成独立函数:这样做可以提高代码的可读性和可维护性。
增加枚举来管理程序状态:使用枚举替代布尔变量来控制排序状态,以便更清晰地管理不同的程序状态。

extern crate piston_window;
use piston_window::*;enum SortState {Idle,Sorting,Paused,
}fn bubble_sort_step(numbers: &mut Vec<i32>, n: &mut usize) -> bool {let mut swapped = false;for i in 0..*n-1 {if numbers[i] > numbers[i+1] {numbers.swap(i, i+1);swapped = true;break; // 为了可视化,只进行一次交换}}if !swapped {*n = 0; // 如果没有发生交换,则排序完成}swapped
}fn main() {let mut window: PistonWindow = WindowSettings::new("Bubble Sort Visualization", [640, 480]).exit_on_esc(true).build().unwrap();let mut numbers = vec![10, 30, 20, 50, 40];let original_numbers = numbers.clone();let mut sort_state = SortState::Idle;let mut n = numbers.len();while let Some(e) = window.next() {// 处理键盘事件if let Some(Button::Keyboard(key)) = e.press_args() {match key {Key::S => sort_state = SortState::Sorting,Key::P => match sort_state {SortState::Sorting => sort_state = SortState::Paused,SortState::Paused => sort_state = SortState::Sorting,_ => {},},Key::R => {numbers = original_numbers.clone();sort_state = SortState::Idle;n = numbers.len();},_ => {}}}// 根据状态执行排序逻辑match sort_state {SortState::Sorting => {if n > 0 {bubble_sort_step(&mut numbers, &mut n);} else {sort_state = SortState::Idle; // 排序完成}},_ => {}}window.draw_2d(&e, |c, g, _| {clear([0.0, 0.0, 0.0, 1.0], g); // 清除屏幕// 绘制数组for (i, &val) in numbers.iter().enumerate() {rectangle([1.0, 0.0, 0.0, 1.0], // 红色[i as f64 * 100.0, 480.0 - val as f64 * 10.0, 50.0, val as f64 * 10.0], // 矩形位置和大小c.transform, g);}});}
}

增加缓步执行的功能使查看变化更加清晰

extern crate piston_window;
use piston_window::*;use std::time::{Duration, Instant};enum SortState {Idle,Sorting,Paused,
}fn bubble_sort_step(numbers: &mut Vec<i32>, n: &mut usize, last_swap_time: &mut Instant, delay: Duration) -> bool {if last_swap_time.elapsed() >= delay {let mut swapped = false;for i in 0..*n-1 {if numbers[i] > numbers[i+1] {numbers.swap(i, i+1);*last_swap_time = Instant::now(); // 更新交换时间swapped = true;break; // 为了可视化,只进行一次交换}}if !swapped {*n = 0; // 如果没有发生交换,则排序完成}swapped} else {false // 如果未达到延迟时间,不执行交换}
}fn main() {let mut window: PistonWindow = WindowSettings::new("Bubble Sort Visualization", [640, 480]).exit_on_esc(true).build().unwrap();let mut numbers = vec![10, 30, 20, 50, 40];let original_numbers = numbers.clone();let mut sort_state = SortState::Idle;let mut n = numbers.len();let mut last_swap_time = Instant::now(); // 记录上次交换的时间let delay = Duration::from_millis(500); // 设置延迟时间为500毫秒while let Some(e) = window.next() {if let Some(Button::Keyboard(key)) = e.press_args() {match key {Key::S => {if matches!(sort_state, SortState::Idle) || matches!(sort_state, SortState::Paused) {sort_state = SortState::Sorting;}},Key::P => {if matches!(sort_state, SortState::Sorting) {sort_state = SortState::Paused;}},Key::R => {numbers = original_numbers.clone();sort_state = SortState::Idle;n = numbers.len();last_swap_time = Instant::now(); // 重置交换时间},_ => {}}}if matches!(sort_state, SortState::Sorting) {bubble_sort_step(&mut numbers, &mut n, &mut last_swap_time, delay);}window.draw_2d(&e, |c, g, _| {clear([0.0, 0.0, 0.0, 1.0], g); // 清除屏幕for (i, &val) in numbers.iter().enumerate() {rectangle([1.0, 0.0, 0.0, 1.0], // 红色[i as f64 * 100.0, 480.0 - val as f64 * 10.0, 50.0, val as f64 * 10.0],c.transform, g);}});}
}

支持大数据量的同时将缓步执行变为可选项,支持按键S开始排序,按键R重置,按键space进行缓步执行,按键p暂停:

extern crate piston_window;
use piston_window::*;use std::time::{Duration, Instant};#[derive(PartialEq)] // 为了能够使用 == 操作符
enum SortState {Idle,Sorting,Paused,Step,
}fn bubble_sort_step(numbers: &mut Vec<i32>, n: &mut usize, last_swap_time: &mut Instant, delay: Duration) -> bool {if last_swap_time.elapsed() >= delay {let mut swapped = false;for i in 0..*n - 1 {if numbers[i] > numbers[i + 1] {numbers.swap(i, i + 1);*last_swap_time = Instant::now(); // 更新交换时间swapped = true;break; // 为了可视化,只进行一次交换}}if !swapped {*n = 0; // 如果没有发生交换,则排序完成}swapped} else {false // 如果未达到延迟时间,不执行交换}
}fn main() {let mut window: PistonWindow = WindowSettings::new("Bubble Sort Visualization", [1280, 720]).exit_on_esc(true).build().unwrap();let original_numbers = vec![10, 5, 3, 8, 2, 6, 4, 7, 9, 1, 55, 23, 12, 34, 11, 22, 33, 44]; // 初始数列let mut numbers = original_numbers.clone(); // 数列的工作副本let mut n = numbers.len();let mut last_swap_time = Instant::now();let delay = Duration::from_millis(10);let mut sort_state = SortState::Idle;while let Some(e) = window.next() {// 处理按键事件if let Some(Button::Keyboard(key)) = e.press_args() {match key {Key::S => {if matches!(sort_state, SortState::Idle) || matches!(sort_state, SortState::Paused) {sort_state = SortState::Sorting;}},Key::P => {if matches!(sort_state, SortState::Sorting) {sort_state = SortState::Paused;}},Key::Space => { // 处理空格键if matches!(sort_state, SortState::Sorting) {// 如果在排序中,按下空格键暂停排序sort_state = SortState::Paused;} else if matches!(sort_state, SortState::Paused) {// 如果已暂停,按下空格键执行单步排序if bubble_sort_step(&mut numbers, &mut n, &mut last_swap_time, delay) {// 如果执行了交换操作,则继续保持暂停状态等待下一步sort_state = SortState::Paused;} else {// 如果没有执行交换(排序完成),则切换到Idle状态sort_state = SortState::Idle;}}},Key::R => {numbers = original_numbers.clone();sort_state = SortState::Idle;n = numbers.len();last_swap_time = Instant::now(); // 重置交换时间},_ => {}}}// 根据当前状态进行排序或暂停if sort_state == SortState::Sorting {if !bubble_sort_step(&mut numbers, &mut n, &mut last_swap_time, delay) && n == 0 {sort_state = SortState::Idle; // 排序完成,回到空闲状态}}window.draw_2d(&e, |c, g, _| {clear([0.0, 0.0, 0.0, 1.0], g); // 清除背景let max_number = *numbers.iter().max().unwrap() as f64;let rect_width = (1280.0 / numbers.len() as f64).floor();for (i, &number) in numbers.iter().enumerate() {let rect_height = (720.0 * (number as f64 / max_number)).floor(); // 根据数值大小动态调整高度rectangle([1.0, 0.0, 0.0, 1.0], // 红色矩形[i as f64 * rect_width, 720.0 - rect_height, rect_width, rect_height], // 矩形位置和大小c.transform,g);}});}
}

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

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

相关文章

Debian操作系统的常用指令介绍

Debian是一个流行的Linux操作系统&#xff0c;以其稳定性和安全性而闻名。对于Debian用户来说&#xff0c;掌握一些基本的命令行指令是非常重要的&#xff0c;因为它们可以帮助你更高效地管理系统。在这篇博客中&#xff0c;我们将介绍一些在Debian系统中常用的指令及其功能。 …

13.1 QQ邮箱

1. 邮箱发送 2. 准备工作 3. 整合SpringBoot 3.1 配置 依赖引入 <!-- 邮件服务--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>application.…

不讲武德,能怼哭你的Chatgpt

这几天逛网站的时候突然发现个新玩意儿&#xff0c;叫做Chatgpt Onima&#xff0c;乍一看&#xff0c;哦原来是Chatgpt 但是&#xff0c;Onima是什么东东&#xff1f;它是我见过最狂的AI Onima 我礼貌的问了一句&#xff1a;你在干嘛&#xff1f; 结果它回复 不知这个攻击性…

Java基础,每日两问(5.3.2):重载和重写的区别

重载&#xff08;overloading&#xff09;和重写&#xff08;overriding&#xff09;是两个与方法相关的概念。它们的区别如下&#xff1a; 重载&#xff08;overloading&#xff09;同的是指在同一个类中定义多个方法&#xff0c;它们具有相名称但具有不同的参数列表。重载的…

containerd的原理及应用详解(二)

本系列文章简介&#xff1a; 随着容器技术的迅猛发展&#xff0c;容器运行时成为了关注的焦点之一。而容器运行时的核心组件之一就是containerd。containerd是一个高度可扩展的容器运行时&#xff0c;它负责管理容器的生命周期、镜像管理以及资源隔离等核心功能。它是由Docker团…

通义灵码:智能编码的革命性助手

通义灵码是由阿里云推出的一款基于通义大模型的智能编码辅助工具&#xff0c;它通过先进的人工智能技术&#xff0c;为开发者提供了一系列的智能编码功能&#xff0c;极大地提升了编码效率和质量。以下是通义灵码的一些核心功能和应用案例。 核心功能 代码智能生成 通义灵码…

你知道JSON.stringify()实现拷贝有什么问题吗?

在说 JSON.stringify() 深拷贝之前&#xff0c;我们先说一说深拷贝和浅拷贝的事情吧。 目录 1 为什么要做深拷贝&#xff1f; 2 哪些做法算浅拷贝&#xff1f; 2.1 直接变量赋值 2.2 Object.assign 浅拷贝 3 哪些做法算深拷贝 &#xff1f; 3.1 JSON.stringify() 3.2 …

SpringBoot实现图片上传(个人头像的修改)

SpringBootlayui实现个人信息头像的更改 该文章适合对SpringBoot&#xff0c;Thymeleaf&#xff0c;layui入门的小伙伴 废话不多说&#xff0c;直接上干货 Springbootlayui实现头像更换 前端公共部分代码 HTML页面代码 <div class"layui-card-header" style&quo…

20240502解决ARM32编译器编译quectel-CM时for循环出错的解决

20240502解决ARM32编译器编译quectel-CM时for循环出错的解决 2024/5/2 17:17 缘起&#xff1a;QMIThread.c:2100:9: error: ‘for’ loop initial declarations are only allowed in C99 or C11 mode 1、修改Makefile为ARM32架构&#xff1a; Z:\quectel-CM\Makefile ifneq ($…

基于SpringBoot+Vue的旅游网站系统

初衷 在后台收到很多私信是咨询毕业设计怎么做的&#xff1f;有没有好的毕业设计参考?能感觉到现在的毕业生和当时的我有着同样的问题&#xff0c;但是当时的我没有被骗&#xff0c;因为现在很多人是被骗的&#xff0c;还没有出学校还是社会经验少&#xff0c;容易相信别人。…

【算法设计与分析】实验报告c++python实现(TSP问题、哈夫曼编码问题、顾客安排问题、最小生成树问题、图着色问题)

一、实验目的 1&#xff0e;加深学生对贪心算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 用贪心算…

个人站点重启

Hexo项目在硬盘&#xff0c;换电脑后需要的配置 下载git 安装node.js https://www.nodejs.com.cn/download.html 安装hexo npm install -g hexo-cli npm install 安装依赖 hexo server 测试成功即可 github仓库项目在硬盘&#xff0c;换电脑后配置 git config -g user.name “…

docker 获取离线镜像包

docker 获取离线镜像包 1、问题背景2、问题分析 3、解决方法 1、问题背景 在内网服务器上因为不能访问互联网&#xff0c;不能使用docker pull命令拉取镜像包&#xff0c;怎么创建docker容器呢&#xff1f; 2、问题分析 在docker hub官网上没有提供下载镜像包的功能&#xf…

Spring基于AspectJ实现验签切点

文章目录 引言I AspectJ 依赖II 验签切点2.1 匹配方法执行的连接点2.2 设置带有CustomAnnotation注解的方法为切点III 案例:验签2.1 用法2.2 定义注解2.3 定义切面和切点引言 需求:验签 实现:基于AspectJ实现验签切点 I AspectJ 依赖 AspectJ 是一个基于 Java 语言的 AOP …

go稀疏数组

稀疏数组 稀疏数组 稀疏数组 package testimport ("encoding/json""fmt""io/ioutil""log""reflect""testing" )type ValNode struct {Row int json:"row"Col int json:"col"Val int json:&qu…

Spring Cloud Kubernetes 实践 服务注册发现、服务动态配置

一、Spring Cloud Kubernetes 随着云计算和微服务架构的不断发展&#xff0c;k8s 和Spring Cloud成为了当今技术领域的两大热门话题。k8s作为一个开源的容器编排平台&#xff0c;已经在自动化部署、扩展和管理方面取得了巨大的成功&#xff0c;而Spring Cloud则以其丰富的生态…

MFC 列表控件修改实例(源码下载)

1、本程序基于前期我的博客文章《MFC下拉菜单打钩图标存取实例&#xff08;源码下载&#xff09;》 2、程序功能选中列表控件某一项&#xff0c;修改这一项的按钮由禁止变为可用&#xff0c;双击这个按钮弹出对话框可对这一项的记录数据进行修改&#xff0c;点击确定保存修改数…

基于Spring Boot的体质测试数据分析及可视化系统设计与实现

基于Spring Boot的体质测试数据分析及可视化系统的设计与实现 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 前台首页界面图&#xff0c;体质测试…

Android 11 12 13耳机图标不显示问题解决方案以及整个图标显示流程

目录 1.解决方案 2.原理分析 ①.config.xml配置文件 ②.StatusBarIconControllerImpl ③.StatusBarIconView类

Github查找代码项目高级语法(含科研项目查找案例)

基础搜索语法 1.搜索名字 in:name XXX 2.搜索描述 in:description XXX 3.搜索readme in:readme XXX 4.根据stars stars:>2000 5.根据fork fork:>3000 6.仓库大小搜索 size:>5000 [注意: 该处单位大小为 k] 7.根据更新时间 …