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

文章目录

  • 学习冒泡排序的可视化实现(一)
    • 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.mfbz.cn/a/589560.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode刷题记录—回溯

目录 22. 括号生成 39. 组合总和 46. 全排列 77. 组合 79. 单次搜索 回溯全集 22. 括号生成 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[&qu…

三维坐标点按剖面分类

一、写在前面 ①配套文件&#xff1a;根据剖面对三维坐标点&#xff08;X,Y,Z&#xff09;分类资源-CSDN文库 ②脱敏处理&#xff1a;蚀变数据已采用随机数生成覆盖 ③剖面坐标按顺序排列在“剖面坐标点.xlsx”文件中 二、3点确定空间中平面方程 原理&#xff1a; 设3点A&…

达梦(DM) SQL聚集函数及日期运算操作

达梦DM SQL聚集函数及日期运算操作 聚集函数MAX、MIN、SUM、AVG、COUNT使用分析函数 sum (…) over (order by…) 可以生成累计和更改累计和的值计算出现次数最多的值 日期运算加减日、月、年加减时、分、秒日期间隔之时、分、秒日期间隔之日、月、年求两个日期间的工作天数确定…

uniapp 异步加载级联选择器(Cascader,data-picke)

目录 Props 事件方法 inputChange事件回调参数说明&#xff1a; completeChange事件回调参数说明&#xff1a; temList 属性Object参数说明 defaultItemList 属性Object参数说明 在template中使用 由于uniapp uni-ui的data-picke 不支持异步作者自己写了一个 插件市场下…

VBA技术资料MF147:从Excel运行PowerPoint演示文稿

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

VULHUB复现log4j反序列化漏洞-CVE-2021-44228

本地下载vulhub复现就完了&#xff0c;环境搭建不讲&#xff0c;网上其他文章很好。 访问该环境&#xff1a; POC 构造&#xff08;任选其一&#xff09;&#xff1a; ${jndi:ldap://${sys:java.version}.xxx.dnslog.cn} ${jndi:rmi://${sys:java.version}.xxx.dnslog.cn}我是…

DHCPv4_CLIENT_SUMMARY_03:接收至少包含312个八位字节长度的‘options‘字段的DHCP消息

测试目的&#xff1a; 验证DHCP客户端是否能够接收至少312个八位字节长度的’options’字段的DHCP消息。 描述&#xff1a; 本测试用例旨在确保DHCP客户端准备接收包含至少312个八位字节&#xff08;即312 octets&#xff09;长度的’options’字段的DHCP消息。这意味着DHCP…

pthread线程相关

LWP :轻量级 进程&#xff0c;本质仍是进程 进程 &#xff1a;独立地址空间&#xff0c;拥有PCB 线程&#xff1a;有独立的TCB&#xff0c;但没有独立的地址空间&#xff08;共享&#xff09; 区别 &#xff1a;在与是否共享地址文件 进程 &#xff08;独居&#xff09;&am…

excel办公系列-图表元素及其作用

Excel图表元素及其作用 Excel图表由各种元素组成&#xff0c;每个元素都有其特定的作用&#xff0c;可以帮助我们更清晰地传达数据信息。下面将介绍Excel图表中常见的一些元素及其作用&#xff0c;并附上相关截图。 原始数据 月份 网站访问量 (万次&#xff09; 销售额 (万…

从一到无穷大 #25 DataFusion:可嵌入,可扩展的模块化工业级计算引擎实现

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 引言架构总览与可扩展性Catalog and Data SourcesFront End逻辑计划与逻辑计划优化器…

基于java,SpringBoot和VUE的求职招聘简历管理系统设计

摘要 基于Java, Spring Boot和Vue的求职招聘管理系统是一个为了简化求职者与雇主间互动流程而设计的现代化在线平台。该系统后端采用Spring Boot框架&#xff0c;以便快速搭建具有自动配置、安全性和事务管理等特性的RESTful API服务&#xff0c;而前端则使用Vue.js框架构建动…

超越数据的确定性:通过概率主成分分析拥抱不确定性

原文地址&#xff1a;beyond-determinism-in-data-embracing-uncertainty-with-probabilistic-principal-component-analysis 2024 年 4 月 24 日 主成分分析法&#xff08;Principal Component Analysis&#xff0c;PCA&#xff09;是一种统计方法&#xff0c;它可以通过正交…

笔试狂刷--Day9(模拟 + dp + 规律)

大家好,我是LvZi,今天带来笔试狂刷--Day9 一.添加逗号 题目链接:添加逗号 分析: 模拟 代码: import java.util.*;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);i…

Linux工具

本期我们来学习Linux的相关工具&#xff0c;这是我们未来经常使用的一些工具&#xff0c;是必须掌握的技能 目录 Linux 软件包管理器 yum rzsz Linux编辑器-vim使用 三种模式的切换 命令模式命令集 底行模式命令集 vim的配置 解决sudo的白名单问题 Linux编辑器—gcc/…

MacBook Pro 原生安装 Ubuntu 24.04 ARM 版

趁着休假整理家里闲置的设备&#xff0c;看到了一台许久不用的 M2 芯片的 MacBook Pro&#xff0c;想着或许应该把它改造成 ARMv64 的 CI/CD 构建机&#xff0c;于是就有了这篇文章。 本篇文章适用于 M1、M2 全系列的设备&#xff0c;包括&#xff1a;MacBook Air、MacBook Pr…

基于Java的智慧社团综合管理系统的设计与实现(论文+源码)_kaic

摘 要 随着校园文化的不断丰富&#xff0c;大学里各种社团越来越多&#xff0c;社团活动也越来越频繁&#xff0c;社员也越来越多&#xff0c;而且大学生退社、入社比较频繁&#xff0c;社团管理就显得非常繁琐而又复杂,如果采用人工管理,对管理员来说将是一件很头疼的事情。设…

加州大学欧文分校英语中级语法专项课程02:Adjectives and Adjective Clauses 学习笔记

Adjectives and Adjective Clauses course certificate 本文是 https://www.coursera.org/learn/adjective-clauses 这门课的学习笔记。 文章目录 Adjectives and Adjective ClausesWeek 01: Adjectives and Adjective PhrasesLearning Objectives Adjectives Introduction Le…

解码Starknet Verifier:深入逆向工程之旅

1. 引言 Sandstorm为&#xff1a; 能提交独立proof给StarkWare的Ethereum Verifier&#xff0c;的首个开源的STARK prover。 开源代码见&#xff1a; https://github.com/andrewmilson/sandstorm&#xff08;Rust&#xff09; L2Beat 提供了以太坊上Starknet的合约架构图&…

单链表经典算法

一&#xff0c;移除链表元素 思路一 遍历数组&#xff0c;如果遇到链表中的元素等于val的节点就执行删除操作 typedef struct ListNode ListNode;struct ListNode* removeElements(struct ListNode* head, int val) {if(headNULL){return NULL;} ListNode*pnewhead(ListNode*)m…

14.集合、常见的数据结构

集合 概念 Java中的集合就是一个容器&#xff0c;用来存放Java对象。 集合在存放对象的时候&#xff0c;不同的容器&#xff0c;存放的方法实现是不一样的&#xff0c; Java中将这些不同实现的容器&#xff0c;往上抽取就形成了Java的集合体系。 Java集合中的根接口&#x…
最新文章