Java 算法可视化:实现无循环的插入排序,但每次调用函数时都以可变增量执行
我正在处理中构建一个排序算法可视化工具(java的扩展,带有额外的可视化库),我非常专注于这个问题,我认为其他人可以帮助我解决这个问题。 在处理过程中,有一个名为draw()的函数每秒被调用60次。每次调用draw()时,我都要在这里执行插入算法的一个步骤。我已经用冒泡排序实现了它。(见下面的代码)。 updateBubble()在draw()中被调用,“colors”是我用来保存不同颜色值以进行排序的arraylist的名称 通过图片更好地了解: [![可视化算法预览][1][1]Java 算法可视化:实现无循环的插入排序,但每次调用函数时都以可变增量执行,java,algorithm,sorting,processing,data-visualization,Java,Algorithm,Sorting,Processing,Data Visualization,我正在处理中构建一个排序算法可视化工具(java的扩展,带有额外的可视化库),我非常专注于这个问题,我认为其他人可以帮助我解决这个问题。 在处理过程中,有一个名为draw()的函数每秒被调用60次。每次调用draw()时,我都要在这里执行插入算法的一个步骤。我已经用冒泡排序实现了它。(见下面的代码)。 updateBubble()在draw()中被调用,“colors”是我用来保存不同颜色值以进行排序的arraylist的名称 通过图片更好地了解: [![可视化算法预览][1][1] ... i
...
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;
}
}
void排序(){
int n=colors.size();
对于(inti=1;i=0&&colors.get(j)>key){
colors.set(j+1,colors.get(j));
j=j-1;
}
颜色。设置(j+1,键);
}
}
这就是我现在得到的:这仍然是错误的,但它越来越接近并明确了我试图达到的目标,生成了一个只使用递增和if语句而不是whiles和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;
}
}
}
//我类似于for循环变量
如果(i实现这一点的一种方法是通过某种存储状态。下面是我所说的高层
// 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";
}
我喜欢这个项目
Processing还有一个millis()
方法,该方法返回自开始绘制草图以来所花费的毫秒数。我有时使用它来计时动画,这在这里很有用。下面是计时器类的一个实现:
class Delay {
int limit;
Delay (int l) {
limit = millis() + l;
}
boolean expired () {
return (millis() > limit);
}
}
我建议您使用这个类,而不是调整FPS。通过使用延迟来减慢排序的实现,您让计算机按照自己的节奏工作,并且只在需要时绘制一个新的帧。像这样(请原谅我说“做东西”的部分):
您可以微调数据的排序速度,并仅在数据发生变化时绘制数据。这是双赢的
玩得开心
编辑
为了帮助您实现,这里有一个示例。您可以将此代码复制并粘贴到一个空的处理草图中,它将按原样运行。为了让我的工作更轻松,我将打印到控制台,而不是使用图形显示,但您应该能够了解我正在执行的操作
这里的秘密是,我的排序算法被巧妙地修改了,所以当我调用它们时,它们总是只运行一个排序步骤。请参见:
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\u numberOfItems=10;
int _sortingStep=0;
IntList _bubbleList=新的IntList();
布尔值_bubbleListSorted=false;
IntList _selectionList=new IntList();
IntList _insertionList=new IntList();
延迟_延迟=新延迟(1);
无效设置(){
对于(int i=0;i极限;
}
}
如果我这次理解正确的话,这应该可以解决您最初的问题!我会像中一样使用迭代器。现在您可以逐步完成算法,并将绘图代码置于控制之下。嘿,感谢您的快速评论!我不太明白这将如何帮助我,或者我将如何实现它?有一个循环和一段时间的loop、 在这个过程中,每次使用迭代器调用draw()时,我怎么能只执行一个步骤呢?嘿!谢谢你的回答,我肯定会实现一个algo计时器:)问题是,我希望这4种算法在同一时间以相同的速度生成步骤。因此,它们生成步骤的方法都应该在绘图中调用。如果我在绘图中延迟,我仍然无法一步一步地执行排序算法:)是有意义的。信不信由你,但我昨晚想了想:你可以把延迟放在排序算法中。这样,每个算法都可以在您选择的时间进行调整。确保每个延迟对象都是不同的对象,否则可能会意外放弃某些排序步骤。如果这种实现让你感到奇怪,让我知道,我会给你看一段代码片段,让你看得更清楚。如果我在算法中加了一个延迟,是不是下一个算法不会被调用,除非上一个算法结束了?还是我错了?我能假设你希望所有的排序算法都以同样的速度逐步前进吗?@Arnepanemans我用一些代码更新了答案,这应该能帮助你理解我的意思。
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;
}
}
}
// 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";
}
class Delay {
int limit;
Delay (int l) {
limit = millis() + l;
}
boolean expired () {
return (millis() > limit);
}
}
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
}
}
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 index1, 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;
}
}