算法可视化:实现插入排序时不使用循环,但每次调用函数时变量递增

如何解决算法可视化:实现插入排序时不使用循环,但每次调用函数时变量递增

我正在处理过程中构建排序算法可视化程序(扩展Java和用于可视化的额外库),我对此问题非常执着,我认为其他人将可以帮助我解决这个问题。 在处理过程中,有一个名为draw()的函数每秒被调用60次。每次调用draw()时,我都在这里执行插入算法的一个步骤。我已经用冒泡排序实现了它。 (请参见下面的代码)。 在draw()中调用了updateBubble(),“ colors”是我用来保留颜色的不同值进行排序的arraylist的名称。

图片以获得更好的理解: [![可视化算法预览] [1]] [1]

...
int j = 0
...
void updateBubble() {
  bubble.sort(j);
  j++;
  if (i<bubble.colors.size()) {
    if (j >= bubble.colors.size()-i-1) {
      j = 0;
      i++;
    }
  } else {
    bubble.sorted = true;
  }
}

这是BubbleSort类中的函数(bubble是此类的对象)

void sort(int j) {
    if (j<colors.size()-1) {
      if (colors.get(j) > colors.get(j+1)) 
      { 
        int temp = colors.get(j); 
        colors.set(j,colors.get(j+1)); 
        colors.set((j+1),temp);
      } 
    }
  }

通过这种方式,我可以将可视化过程的速度减慢到帧速率的速度,而无需使用立即执行排序算法的循环即可控制自己。现在,我还想为插入排序算法做一个类似的实现,但是我觉得自己陷入了困境,因为我似乎无法使用一个可行的类似实现,或者可能会有更好的方法呢? 目前,我所拥有的将按预期立即执行,而看不到该过程。

void updateInsertion() {
  insertion.sort();
}
void sort() {
    int n = colors.size(); 
    for (int i = 1; i < n; ++i) { 
      int key = colors.get(i); 
      int j = i - 1; 
      while (j >= 0 && colors.get(j) > key) { 
        colors.set(j+1,colors.get(j));
        j = j - 1;
      } 
      colors.set(j+1,key);
    }
  }

这就是我现在所得到的:这仍然是错误的,但是越来越近并弄清了我要达到的目标,使该函数仅适用于增量和if语句,而不是while和fors,因此每个不同的步骤都在进行在每次调用该方法时执行。

  // i resembles for loop variable
  if (i<insertion.colors.size()) {
    if (j<0 || insertion.colors.get(j) <= insertion.colors.get(i)) { // negative check to go out of while loop
      insertion.colors.set(j+1,keap);
      if(notSortedYet()){
      i++;
      keap = insertion.colors.get(i);
      j = i - 1;
      }
    } else { // resembles being in the while loop
      insertion.colors.set((j+1),insertion.colors.get(j));
      j = j - 1;
    }
  }
}                                                                                                                                       

编辑:我已修复它,您可以在下面找到我的解决方案:)每次调用updateInsertion()时,我的代码将在算法中执行确切的一步!感谢所有努力发表评论的人,我不知道这是否是最佳实践,因此,如果您愿意,请随时与我联系!

void updateInsertion() {

  // i resembles for loop variable

  if (i<insertion.colors.size()) {
    if (j>=0 && insertion.colors.get(j) > firstUnsorted) {
      int temp = insertion.colors.get(j+1);
      insertion.colors.set((j+1),insertion.colors.get(j));
      insertion.colors.set(j,temp);
      j = j - 1;
    } else {
      insertion.colors.set(j+1,firstUnsorted);
      if (i<insertion.colors.size()-1) {
        i++;
      }
      firstUnsorted = insertion.colors.get(i);
      j = i - 1;
    }
  }
}

解决方法

我喜欢这个项目。

处理过程还有一个millis()方法,该方法返回自开始绘制草图以来花费的毫秒数。有时我会用它来安排动画时间,在这里可以派上用场。这是计时器类的实现:

class Delay {
  int limit;
  
  Delay (int l) {
    limit = millis() + l;
  }
  
  boolean expired () {    
    return (millis() > limit);
  }
}

我建议您使用此类而不是调整FPS。通过使用“延迟”来减慢排序的执行速度,您可以让计算机按照自己的节奏工作,并且仅在需要时才绘制新帧。像这样(请原谅我说“做某事”的部分):

Delay holdTheFrame = new Delay(1);
void draw() {
  if(holdTheFrame.expired()) {
    holdTheFrame = new Delay(500); // half a second before the next frame
    // Advance one step forward in your sorting
    // Draw the visualization of the data
  }
}

您可以调整数据排序的速度,并且仅在数据更改时才对其进行绘制。这是双赢的!

玩得开心!


编辑

为帮助您实现,下面是一个示例。您可以将此代码复制并粘贴到一个空白的Processing草图中,然后按原样运行 。为了使事情变得容易,我打印到控制台而不是使用图形显示,但是您应该能够了解我正在做的事情。

这里的秘密是我的排序算法已被巧妙地修改,因此当我调用它们时,它们总是只运行一个排序步骤。亲自看看:

int _numberOfItems = 10;
int _sortingStep = 0;
IntList _bubbleList = new IntList();
boolean _bubbleListSorted = false;
IntList _selectionList = new IntList();
IntList _insertionList = new IntList();
Delay _delay = new Delay(1);

void setup() {  
  for (int i=0; i<_numberOfItems; i++) {
    _bubbleList.append((int)random(10,99));
  }
  for (int i=0; i<_numberOfItems; i++) {
    _selectionList.append((int)random(10,99));
  }
  for (int i=0; i<_numberOfItems; i++) {
    _insertionList.append((int)random(10,99));
  }
}

void draw() {
  if (_delay.expired()) {
    _delay = new Delay(500);

    // sort one step with every algo you want to display
    if (!_bubbleListSorted) {
      singleStepBubbleSort(_bubbleList);
    }
    if (_sortingStep < _numberOfItems) {
      singleStepSelectionSort(_selectionList,_sortingStep);
      singleStepInsertionSort(_insertionList,_sortingStep);
    }
    _sortingStep++;

    // update the display (I'm printing to console instead for simplicity)
    for (int i : _bubbleList) {
      print(i + " ");
    }
    print("  |  ");
    for (int i : _selectionList) {
      print(i + " ");
    }
    print("  |  ");
    for (int i : _insertionList) {
      print(i + " ");
    }
    print("\n");
  }
}

// An "single-step" implementation of Insertion Sort
void singleStepInsertionSort(IntList list,int step) {
  int k = list.get(step); 
  int j = step - 1; 
  while (j >= 0 && list.get(j) > k) { 
    list.set(j+1,list.get(j));
    j = j - 1;
  } 
  list.set(j+1,k);
}

// An "single-step" implementation of Bubble Sort
void singleStepBubbleSort(IntList list) { 
  int temp; 
  boolean swapped = false;

  for (int i=0; i<list.size()-1; i++)  
  { 
    if (list.get(i) > list.get(i + 1))  
    { 
      // swap arr[j] and arr[j+1] 
      temp = list.get(i); 
      list.set(i,list.get(i+1)); 
      list.set(i+1,temp); 
      swapped = true;
    }
  }

  if (!swapped) {
    _bubbleListSorted = true;
  }
}

// An "single-step" implementation of Selection Sort
void singleStepSelectionSort(IntList list,int step) 
{ 
  int min_idx = step; 
  for (int j = step+1; j < list.size(); j++) {
    if (list.get(j) < list.get(min_idx)) {
      min_idx = j;
    }
  }

  int temp = list.get(min_idx); 
  list.set(min_idx,list.get(step)); 
  list.set(step,temp);
}

class Delay {
  int limit;

  Delay (int l) {
    limit = millis() + l;
  }

  boolean expired () {    
    return (millis() > limit);
  }
}

让我知道您是否有疑问。


更多编辑:

插入类型的每次交换都意味着很多很多交换。这是一个真正的痛苦,因为此算法在跟踪过程中有点复杂。

幸运的是,我不在乎。在框外思考时,我选择创建一个专门用于对数组进行排序的类,同时记录如何对数组进行排序,然后能够“像实时发生一样”播放它。看看:

int numberOfItems = 10;
int sortingStep = 0;
Delay delay = new Delay(1);
ManagedSelectionSort managedSelectionSort;  // I created a class just to manage this madness

void setup() {
  IntList list = new IntList();
  for (int i=0; i<numberOfItems; i++) {
    list.append((int)random(10,99));  // some random numbers to sort later 
  }

  managedSelectionSort = new ManagedSelectionSort(list);  // take a look at the instantiation of this class

  print("Step " + String.format("%02d",sortingStep) + ": ");
  printArray(managedSelectionSort.list);
  print("\n");
}

void draw() {
  if (delay.expired()) {    
    delay = new Delay(100);  // i put a very short delay,you'll probably want to tweak this

    managedSelectionSort.sortOneStep();  // this is not what it seems
    sortingStep++;

    print("Step " + String.format("%02d",sortingStep) + ": ");
    printArray(managedSelectionSort.list);
    print("\n");
  }
}

// this class is where the magic happens
// we'll sort the array all at once while recording every move
// then we'll play back those moves on a copy of the array
class ManagedSelectionSort {
  IntList list,hiddenList;  // list is the "official" list,while hiddenList is where the heavy lifting happens
  ArrayList<SwapIndex> swapList;  // this is where I record how to sort the array

  ManagedSelectionSort(IntList baseList) {  // this way I can instantiate several similar objects with the same list
    list = new IntList();
    hiddenList = new IntList();
    swapList = new ArrayList<SwapIndex>();

    for (int i : baseList) {
      // both lists have the same initial numbers
      list.append(i);
      hiddenList.append(i);
    }

    // as soon as this object is instantiated,it knows how it'll sort the array
    // because it already did...
    hiddenSort();
  }

  // this method plays the moves which were recorded earlier according to the current sortingStep
  // the swapList array was filled with every swap needed to sort the array,one by one
  // now it's just a matter of playing them back on a copy of the initial array
  void sortOneStep() {
    if (sortingStep < swapList.size()) {
      swap(list,swapList.get(sortingStep).index1,swapList.get(sortingStep).index2);
    }
  }

  // this is the real implementation of the insertion sort
  void hiddenSort() 
  {
    for (int i=1; i<hiddenList.size(); i++) {
      int j = i;

      while (j>0 && hiddenList.get(j) < hiddenList.get(j-1)) {
        swap(hiddenList,j,j-1,true);  // swap is a class specific helper method,it swaps the numbers and also records the move
        j--;
      }
    }
  }

  // this is an overload,i could have done without but it's confortable
  void swap(IntList list,int index1,int index2) {
    swap(list,index1,index2,false);
  }
  void swap(IntList list,int index2,boolean recordMove) {
    // the swap first
    int temp = list.get(index1);
    list.set(index1,list.get(index2));
    list.set(index2,temp);

    // if the method is set on 'record',it adds this move to the swapList array
    if (recordMove) {      
      swapList.add(new SwapIndex(index1,index2));
    }
  }
}

// this class could have been a struct,but I like to start in OOP right from the bat in case things gets complicated
class SwapIndex {
  int index1;
  int index2;

  SwapIndex(int index1,int index2) {
    this.index1 = index1;
    this.index2 = index2;
  }
}

// this method is just an helper method to print to console
void printArray(IntList list) {
  for (int i : list) {
    print(i + " ");
  }
}

class Delay {
  int limit;

  Delay (int l) {
    limit = millis() + l;
  }

  boolean expired () {    
    return millis() > limit;
  }
}

如果我这次正确理解的话,这应该可以解决您的最初问题!

,

实现此目的的一种方法是通过某种存储状态。以下是我在说的高层次内容。

// Starts the procedure. Must be called before draw().
void init() {
    state = "forLoop";

    i = 1;
    n = colors.size();
}

// Single iteration of a loop.
void draw(){
    switch(state) {
        case "forLoop":
            doForBody();
            break;
        case "whileLoop":
            doWhileLoopBody();
            break;
        ...
    }
}

// Executes everything in the while loop and the one or two things
// just after it.
void doWhileLoopBody() {
    if (isThisIterationOfWhileDone()) {
        // Get out of the while loop and prepare for the next iteration of for.
        // A better way to what I'm doing on the next couple lines here would
        // be to introduce an additional state (ex: "postWhile") that would
        // execute just after this method and would handle the colors.set(),// incrementing i,etc.
        state = "forLoop";
        colors.set(j+1,key);
        i++;
        return;
    }
    // update colors,value of j,etc...
}


// Executes everything before the while loop.
void doForLoopBody() {
    if (isThisIterationOfForDone()) {
        state = "END";
        return;
    }

    // update colors,get values of key and j initialized,etc

    // switch to processing the body of the while loop
    state = "whileLoop";
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-