2017-03-24 22 views
2

我正在使用javaFX实现一些合并排序动画。我使用一些动画功能来完成它。但是,翻译路线是错误的。我一遍又一遍地检查我的代码,但没有发现问题。问题可能出现在合并方法中,但我找不到问题所在。我使用绝对坐标定位节点:javaFX:move shapes with absolute coordinates using translatetransition。谁能帮我??javaFX:错误的合并排序动画结果

这些代码:

public class Main extends Application { 
double speed = 400; 

int[] helper; 

final ArrayList<Integer> CenterX = new ArrayList(); 
int listindex = 0; 
@Override 
public void start(Stage primaryStage) throws Exception { 

    Pane pane = new Pane(); 
    ArrayList<StackPane> list = new ArrayList<>(); 
    Random random = new Random(5); 
    for (int i = 0; i < 13; i++) { 
     int num = random.nextInt(10); 
     Rectangle rectangle = new Rectangle(40, (num * 10) + 50); 
     rectangle.setFill(Color.valueOf("#FF7F50")); 
     Text text = new Text(String.valueOf(num)); 
     StackPane stackPane = new StackPane(); 
     stackPane.setPrefSize(rectangle.getWidth(), rectangle.getHeight()); 
     stackPane.setId(String.valueOf(num)); 
     stackPane.getChildren().addAll(rectangle, text); 
     StackPane.setAlignment(text,Pos.TOP_CENTER); 
     stackPane.setAlignment(Pos.TOP_CENTER); 
     stackPane.setTranslateX(60*i); 
     list.add(stackPane); 
    } 


    pane.getChildren().addAll(list); 

    BorderPane borderPane = new BorderPane(); 
    borderPane.setCenter(pane); 
    HBox hBox1 = new HBox(); 
    Button b = new Button("Sort"); 


    AnchorPane bottomPane = new AnchorPane(); 
    hBox1.getChildren().add(b); 
    bottomPane.getChildren().add(hBox1);  
    borderPane.setBottom(bottomPane); 


    b.setOnAction(event -> { 
     SequentialTransition sq = new SequentialTransition(); 
     int[] = arr; 
     arr = generateArray(list); 
     sq = MergeSort(arr, list,sq); 
     b.setDisable(true); 
     sq.play(); 
     sq.setOnFinished(new EventHandler<ActionEvent>() { 
      @Override 
      public void handle(ActionEvent event) { 
       b.setDisable(false); 
      } 
     }); 
     b.setDisable(false); 

    }); 

    Scene scene = new Scene(borderPane,800, 800); 
    primaryStage.setTitle("Sorting"); 
    primaryStage.setResizable(false); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 

    for (int i = 0; i < 13; i++) { 
     int centerx = (int) list.get(i).getLayoutX(); 
     CenterX.add(i,centerx+60*i); 
     System.out.println(centerx+60*i); 

    } 
} 



private int[] generateArray(List<StackPane> list) { 
    int arr[] = new int[list.size()]; 
    for (int i = 0; i < arr.length; i++) { 
     arr[i] = Integer.parseInt(list.get(i).getId()); 
    } 
    return arr; 
} 

private TranslateTransition AddtoOriginal(StackPane sp, double speed,int X){ 
    TranslateTransition t = new TranslateTransition(); 
    t.setNode(sp); 
    t.setDuration(Duration.millis(speed)); 
    t.setToX(X); 
    t.setToY(300); 
    return t; 

} 

public SequentialTransition MergeSort(int arr[],ArrayList<StackPane> list,SequentialTransition sq) { 
    int number = arr.length; 
    this.helper = new int[number]; 
    mergesort(0, number - 1,arr,sq,list); 
    return sq; 
} 

private void mergesort(int low, int high,int arr[],SequentialTransition sq,ArrayList<StackPane> list) { 
    // check if low is smaller then high, if not then the array is sorted 
    if (low < high) { 
      // Get the index of the element which is in the middle 
      int middle = low + (high - low)/2; 
      // Sort the left side of the array 
      mergesort(low, middle,arr,sq,list); 
      // Sort the right side of the array 
      mergesort(middle + 1, high,arr,sq,list); 
      // Combine them both 
      merge(low, middle, high,arr,list,sq); 
    } 

} 


private void merge(int low, int middle, int high,int arr[],ArrayList<StackPane> list,SequentialTransition sq) { 
// Copy both parts into the helper array 
    for (int i = low; i <= high; i++) { 
      helper[i] = arr[i]; 

    } 
    int i = low; 
    int j = middle + 1; 
    int k = low; 
    // Copy the smallest values from either the left or the right side back 
    // to the original array 

    while (i <= middle && j <= high) { 
      if (helper[i] <= helper[j]) { 
        arr[k] = helper[i]; 
        sq.getChildren().add(AddtoOriginal(list.get(i),speed,CenterX.get(k))); 
        i++; 
      } else { 
        arr[k] = helper[j]; 
        sq.getChildren().add(AddtoOriginal(list.get(j),speed,CenterX.get(k))); 
        j++; 
      } 
      k++; 
    } 
    // Copy the rest of the left side of the array into the target array 
    while (i <= middle) { 
      arr[k] = helper[i]; 
      sq.getChildren().add(AddtoOriginal(list.get(i),speed,CenterX.get(k))); 
      k++; 
      i++; 
    } 

    ParallelTransition pl = new ParallelTransition(); 
    ArrayList<TranslateTransition> Transitionlist = new ArrayList<>(high-low); 

    for (int z = low; z <= high; z++) { 
     TranslateTransition t = new TranslateTransition(); 
     t.setNode(list.get(z)); 
     t.setDuration(Duration.millis(speed)); 
     t.setByY(-300); 
     Transitionlist.add(t); 
} 
pl.getChildren().addAll(Transitionlist); 
sq.getChildren().add(pl); 

} 

public static void main(String[] args) { 
    launch(args); 
} 
} 
+1

与您先前删除的问题类似,这与[Javafx:交换矩形形状沿与锯切数组元素](http://stackoverflow.com/questions/41026018/javafx-swap-rectangle-shapes-along-with-sawping-array-elements)。那里的解决方案对你没有帮助吗? – jewelsea

+0

@jewelsea但我不知道问题出在哪里。我为每个翻译添加了“SequentialTransition”。我还在每个循环中重新定位了矩形的位置。 – happyeveryday

+1

如果你想帮助调试你的特定解决方案,你应该提供一个[mcve](https://stackoverflow.com/help/mcve),有人可以复制和粘贴来复制你的问题。否则,有人很难帮助你。即使如此,这种问题可能会有点棘手。 – jewelsea

回答

1

与您的代码的问题,以及如何解决这些问题

你的主要问题是,当你做这样的事情:

arr[k] = helper[j]; 
sq.getChildren().add(AddtoOriginal(list.get(j),speed,CenterX.get(k))); 

什么你正在做的是有一些数组(arrhelper),它们表示正在排序的值,并且哟你移动数组中的位置值(在赋值中),但是当你运行AddToOriginal例程时,你也不会移动表示视觉显示的列表中的值。所以发生的事情是,视觉显示与排序数组不同步。

此外,合并排序算法(如您实施的)不是在内存中进行排序,实际上涉及到两个数组,arr数组和helper数组,辅助程序有必要跟踪原始值当您分配arr值时,原始值不会被覆盖。你需要用视觉表现来做同样的事情。对于我基于原始代码实现的示例代码,我所做的是添加一个额外的数组helperNodes,它追踪帮助程序数组的位置引用,但是以可视化的形式。

把这两个东西放在一起,只要你换一个节点,你做一个额外的声明是这样,保持与值阵列可视列表内联,你正在操纵:

arr[k] = helper[j]; 
list.set(k, helperNodes[j]); 
sq.getChildren().add(move(helperNodes[j], k * SPACING)); 

另外,还要注意交换移动基于未被突变的helperNodes[j]元素而不是list.get(j)元素,其可能已经被突变。上面的代码正在做什么是映射值赋值的逻辑与操作可视化列表数组以及在sq连续转换中的动画移动。

一个额外的问题是,你有算法合并排序不会为了做任何事情时,在合并段的右侧部分节点进行排序已经。但是,您正在执行合并段中所有元素的动画移动,并将其恢复到原始起始高度。因此,即使数组中的值位置没有改变,您也需要添加一些额外的代码来执行该可视化动画。

如果您发现了这个困难,不要担心(因为它似乎IMO :-)它不是那么容易

信用

我猜(也许是错误的),您的合并排序算法基于Vogella Merge Sort Tutorial。如果是这样,这是不错的承认,在这个问题,因为它有助于理解灵感的上下文中的源(如果没有,你可以忽略此注意事项)。

未排序

unsorted

排序在进展

in progress

排序

sorted

示例应用程序

import javafx.animation.*; 
import javafx.application.Application; 
import javafx.geometry.*; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.layout.*; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Rectangle; 
import javafx.scene.text.Text; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

import java.util.*; 

public class Merge extends Application { 
    private static final int N_VALUES = 13; 
    private static final int SPACING = 60; 
    private static final int SORT_GROUP_MOVE_DELTA = 200; 

    private static final Duration SPEED = Duration.millis(400); 

    private int[] helper; 
    private StackPane[] helperNodes; 
    private Random random = new Random(5); 

    @Override 
    public void start(Stage stage) throws Exception { 
     Pane displayPane = new Pane(); 
     ArrayList<StackPane> list = new ArrayList<>(); 
     for (int i = 0; i < N_VALUES; i++) { 
      StackPane stackPane = createValueNode(i); 
      list.add(stackPane); 
     } 

     displayPane.getChildren().addAll(list); 

     Button sortButton = new Button("Sort"); 
     sortButton.setOnAction(event -> { 
      SequentialTransition sq = new SequentialTransition(); 
      int[] arr = generateArray(list); 
      sq = mergeSort(arr, list, sq); 
      sortButton.setDisable(true); 
      sq.play(); 
      sq.setOnFinished(event1 -> sortButton.setDisable(false)); 
      sortButton.setDisable(false); 
     }); 

     BorderPane borderPane = new BorderPane(); 
     borderPane.setCenter(displayPane); 
     borderPane.setBottom(sortButton); 
     BorderPane.setAlignment(sortButton, Pos.CENTER); 
     BorderPane.setMargin(sortButton, new Insets(10)); 

     Scene scene = new Scene(borderPane, 800, 400); 
     stage.setTitle("Sorting"); 
     stage.setResizable(false); 
     stage.setScene(scene); 
     stage.show(); 
    } 

    private StackPane createValueNode(int i) { 
     int num = random.nextInt(10); 
     Rectangle rectangle = new Rectangle(40, (num * 10) + 50); 
     rectangle.setFill(Color.valueOf("#FF7F50")); 
     Text text = new Text(String.valueOf(num)); 
     StackPane stackPane = new StackPane(); 
     stackPane.setPrefSize(rectangle.getWidth(), rectangle.getHeight()); 
     stackPane.setId(String.valueOf(num)); 
     stackPane.getChildren().addAll(rectangle, text); 
     StackPane.setAlignment(text, Pos.TOP_CENTER); 
     stackPane.setAlignment(Pos.TOP_CENTER); 
     stackPane.setTranslateX(SPACING * i); 
     return stackPane; 
    } 


    private int[] generateArray(List<StackPane> list) { 
     int arr[] = new int[list.size()]; 
     for (int i = 0; i < arr.length; i++) { 
      arr[i] = Integer.parseInt(list.get(i).getId()); 
     } 
     return arr; 
    } 

    private TranslateTransition move(StackPane sp, int X) { 
     TranslateTransition t = new TranslateTransition(); 
     t.setNode(sp); 
     t.setDuration(SPEED); 
     t.setToX(X); 
     t.setToY(SORT_GROUP_MOVE_DELTA); 
     return t; 

    } 

    public SequentialTransition mergeSort(int arr[], ArrayList<StackPane> list, SequentialTransition sq) { 
     int number = arr.length; 
     this.helper = new int[number]; 
     this.helperNodes = new StackPane[number]; 
     sortRange(0, number - 1, arr, sq, list); 
     return sq; 
    } 

    private void sortRange(int low, int high, int arr[], SequentialTransition sq, ArrayList<StackPane> list) { 
     // check if low is smaller then high, if not then the array is sorted 
     if (low < high) { 
      // Get the index of the element which is in the middle 
      int middle = low + (high - low)/2; 
      // Sort the left side of the array 
      sortRange(low, middle, arr, sq, list); 
      // Sort the right side of the array 
      sortRange(middle + 1, high, arr, sq, list); 
      // Combine them both 
      merge(low, middle, high, arr, list, sq); 
     } 
    } 


    private void merge(int low, int middle, int high, int arr[], ArrayList<StackPane> list, SequentialTransition sq) { 
     // Copy both parts into the helper array 
     for (int i = low; i <= high; i++) { 
      helper[i] = arr[i]; 
      helperNodes[i] = list.get(i); 
     } 

     int i = low; 
     int j = middle + 1; 
     int k = low; 
     // Copy the smallest values from either the left or the right side back 
     // to the original array 

     while (i <= middle && j <= high) { 
      if (helper[i] <= helper[j]) { 
       arr[k] = helper[i]; 
       list.set(k, helperNodes[i]); 
       sq.getChildren().add(move(helperNodes[i], k * SPACING)); 
       i++; 
      } else { 
       arr[k] = helper[j]; 
       list.set(k, helperNodes[j]); 
       sq.getChildren().add(move(helperNodes[j], k * SPACING)); 
       j++; 
      } 
      k++; 
     } 
     // Copy the rest of the left side of the array into the target array 
     while (i <= middle) { 
      arr[k] = helper[i]; 
      list.set(k, helperNodes[i]); 
      sq.getChildren().add(move(helperNodes[i], k * SPACING)); 
      k++; 
      i++; 
     } 

     // Even if we didn't move in the array because it was already ordered, 
     // move on screen for any remaining nodes in the target array. 
     while (j <= high) { 
      sq.getChildren().add(move(helperNodes[j], k * SPACING)); 
      k++; 
      j++; 
     } 

     ParallelTransition moveUp = new ParallelTransition(); 

     for (int z = low; z <= high; z++) { 
      TranslateTransition moveNodeUp = new TranslateTransition(); 
      moveNodeUp.setNode(helperNodes[z]); 
      moveNodeUp.setDuration(SPEED); 
      moveNodeUp.setByY(-SORT_GROUP_MOVE_DELTA); 
      moveUp.getChildren().add(moveNodeUp); 
     } 

     sq.getChildren().add(moveUp); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

可能的替代实现

一个你可以做的事情是创建一个SortableNode类,以取代正在定义来保存值StackPane。可排序节点可以将节点的值保存在字段中而不是ID中。可排序节点也可以实现Comparable。然后,可以更新合并排序算法,以将可比对象的列表作为输入,而不是整数的整数。这样你就不需要跟踪算法中的值和视觉表示的单独数组(并保持它们同步)。这可能会简化实施。但我不会在这里添加额外的示例来实现这种替代方法(因为上面的当前示例似乎工作正常;-)

+0

谢谢你sooooo多!!稍后我会尝试你的建议(替代方法)。是的,合并排序基于该链接。我很抱歉,我在这个问题中没有提到它。我会提供它。 – happyeveryday