如何解决算法可视化:实现插入排序时不使用循环,但每次调用函数时变量递增
我正在处理过程中构建排序算法可视化程序(扩展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 举报,一经查实,本站将立刻删除。