golang和java中的shuffle
2018-08-10
本文总阅读量:次
golang和java中的shuffle
有篇文章中讲了golang中shuffle的使用 代码如下:
a := []int{1, 2, 3, 4, 5, 6, 7, 8}
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] })
结果
[5 8 6 4 3 7 2 1]
golang-1.10中shuffle的实现
// Shuffle pseudo-randomizes the order of elements.
// n is the number of elements. Shuffle panics if n < 0.
// swap swaps the elements with indexes i and j.
func (r *Rand) Shuffle(n int, swap func(i, j int)) {
if n < 0 {
panic("invalid argument to Shuffle")
}
// Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
// Shuffle really ought not be called with n that doesn't fit in 32 bits.
// Not only will it take a very long time, but with 2³¹! possible permutations,
// there's no way that any PRNG can have a big enough internal state to
// generate even a minuscule percentage of the possible permutations.
// Nevertheless, the right API signature accepts an int n, so handle it as best we can.
i := n - 1
for ; i > 1<<31-1-1; i-- {
j := int(r.Int63n(int64(i + 1)))
swap(i, j)
}
for ; i > 0; i-- {
j := int(r.int31n(int32(i + 1)))
swap(i, j)
}
}
golang的实现和java有很大区别,下面看下java的实现
public static void shuffle(List<?> list) {
Random rnd = r;
if (rnd == null) {
r = rnd = new Random();
}
shuffle(list, rnd);
}
public static void shuffle(List<?> list, Random rnd) {
int size = list.size();
if (size >= 5 && !(list instanceof RandomAccess)) {
Object[] arr = list.toArray();
for(int i = size; i > 1; --i) {
swap(arr, i - 1, rnd.nextInt(i));
}
ListIterator it = list.listIterator();
for(int i = 0; i < arr.length; ++i) {
it.next();
it.set(arr[i]);
}
} else {
for(int i = size; i > 1; --i) {
swap(list, i - 1, rnd.nextInt(i));
}
}
}
首先获取集合的元素个数,如果小于5
个或者实现了RandomAccess
接口,就循环一遍,随机交换集合中两个相邻的元素的位置,RandomAccess
是一个标记接口,如果实现了这个接口就表示支持快速的随机访问操作,类似于数组。
如果大于等于5
个元素也没有实现RandomAccess
接口,那么就转为数组,之后也是循环,随机交换集合中两个相邻的元素的位置,最后再将数组放回原来的list中。
之所以做这样的区别是和速度有关系,其中涉及到了RandomAccess这个类,有篇文章讲了这个类的用处
ArrayList实现了RandomAccess,而LinkedList没实现这个接口,所以ArrayList是做直接的下标遍历,而LinkedList是先转成Array结构,再用下标遍历