介绍
有时需要用到整数1-n的随机排列,如决定出场顺序等。这里用java做一个简单的小界面,显示整数1-n的随机排列。
这里界面用javafx工具实现。
原理
整数1-n的排列,共n!种,所以我们的目的相当于是从n!个样本点构成的总体中,随机等概率地抽取一个样本点。
当然,我们的实现算法不采取上述的n!的方式,需要采用计算量合理的算法。
一个可能出现的误区是:不断地产生1~n之间的随机整数;如果遇到与已经产生的整数出现重复,则舍弃掉这个整数,并继续产生,一直到产生n个不同的整数(>=1, <=n)。这个方法简单也直观,但从概率的角度看,这样产生的结果与上述的随机等概率抽样并不等价。
这里采用一种比较简单的方法:让计算机产生n个0~1均匀分布的随机数(一般我们使用的n较小,那么计算机产生的这n个随机并不重复),得到一个随机数序列。按顺序记录着n个随机数,即为每一个随机数贴上“标签”,标签上记录的是它在这个序列中的序号。
然后对这n个随机数排序。排序之后,随机数的位置自然发生了变换,我们按现在的位置顺序把它们的“标签”取出来,就得到一个1-n整数的随机排列。
实现
输入n后,建立一个数组和一个哈希表。n轮产生随机数,在第i轮中,将产生的这个随机数添加到数组,同时将其作为键添加到哈希表中,键对应的值为轮次,即整数i。
对数组排序。这里我用的是二路归并排序的方法。
按顺序取出排好序后的数组中的数,之后查找它在哈希表中对应的值。这样得到的值序列,就是我们想要的一个整数随机排列。
代码
package random;
import java.util.*;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class RandomPermutation extends Application {
private Text text = new Text("Enter the maximun integer:");
private TextField tfInput = new TextField();
private TextArea ta = new TextArea();
private Button btRun = new Button("Run");
private Button btClear = new Button("Clear");
private boolean allow = true;
@Override
public void start(Stage primaryStage) {
// UI
ta.setEditable(false);
ta.setWrapText(true);
BorderPane pane = new BorderPane();
HBox hBox = new HBox();
hBox.getChildren().addAll(text, tfInput, btRun, btClear);
pane.setBottom(hBox);
pane.setCenter(ta);
Scene scene = new Scene(pane, 700, 400);
primaryStage.setTitle("Random");
primaryStage.setScene(scene);
primaryStage.show();
btRun.setOnAction(e -> runAction());
btClear.setOnAction(e -> clearAction());
}
public static void main(String[] args) {
Application.launch(args);
}
// Clear
public void clearAction() {
allow = true;
ta.clear();
tfInput.clear();
}
// Run
public void runAction() {
if(allow) {
Integer n = Integer.parseInt(tfInput.getText());
if(n instanceof Integer) {
// Hash map to store key(random_number)-value(integer)
MaphashMap = new HashMap<>();
// Array to store random_number
double[] randomNumbers = new double[n];
for(int i = 1; i <= n; i++) {
double r = Math.random();
hashMap.put(r, i);
randomNumbers[i - 1] = r;
}
// Sort the array
mergeSort(randomNumbers);
// Get the value(integer) sequence
for(int i = 1; i <=n; i++) {
double randomNumber = randomNumbers[i - 1];
Integer integer = hashMap.get(randomNumber);
ta.appendText(integer.toString() + " ");
if( i % 15 == 0) {
ta.appendText("\n");
}
}
}
allow = false;
}
}
// Merge sort method
public static void mergeSort(double[] list) {
if(list.length > 1) {
double[] firstHalf = new double[list.length / 2];
System.arraycopy(list, 0, firstHalf, 0, list.length / 2);
mergeSort(firstHalf);
int secondHalfLength = list.length - list.length / 2;
double[] secondHalf = new double[secondHalfLength];
System.arraycopy(list, list.length / 2, secondHalf, 0,
secondHalfLength);
mergeSort(secondHalf);
merge(firstHalf, secondHalf, list);
}
}
public static void merge(double[] list1, double[] list2, double[] temp) {
int current1 = 0;
int current2 = 0;
int current3 = 0;
while(current1 < list1.length && current2 < list2.length) {
if(list1[current1] < list2[current2])
temp[current3++] = list1[current1++];
else
temp[current3++] = list2[current2++];
}
while(current1 < list1.length)
temp[current3++] = list1[current1++];
while(current2 < list2.length)
temp[current3++] = list2[current2++];
}
}