2017-03-24 92 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