我的朋友在他的采访中被问到一个问题:
面试官给了他一系列未分类的数字并请他排序。限制是应该最小化写入次数,而对读取次数没有限制。答案 0 :(得分:29)
选择排序不这里是正确的算法。选择排序将交换值,每次选择最多两次写入,每次最多提供2n次写入。< / p>
一种比选择排序好两倍的算法是"cycle" sort,它不会交换。循环排序将为每种排序提供最多n次写入。写入次数绝对最小化。它只会将一个数字写入其最终目的地,并且只有当它不存在时才会写入。
它基于all permutations are products of cycles的想法,您可以简单地循环每个循环并将每个元素写入适当的位置一次。
import java.util.Random;
import java.util.Collections;
import java.util.Arrays;
public class CycleSort {
public static final <T extends Comparable<T>> int cycleSort(final T[] array) {
int writes = 0;
// Loop through the array to find cycles to rotate.
for (int cycleStart = 0; cycleStart < array.length - 1; cycleStart++) {
T item = array[cycleStart];
// Find where to put the item.
int pos = cycleStart;
for (int i = cycleStart + 1; i < array.length; i++)
if (array[i].compareTo(item) < 0) pos++;
// If the item is already there, this is not a cycle.
if (pos == cycleStart) continue;
// Otherwise, put the item there or right after any duplicates.
while (item.equals(array[pos])) pos++;
{
final T temp = array[pos];
array[pos] = item;
item = temp;
}
writes++;
// Rotate the rest of the cycle.
while (pos != cycleStart) {
// Find where to put the item.
pos = cycleStart;
for (int i = cycleStart + 1; i < array.length; i++)
if (array[i].compareTo(item) < 0) pos++;
// Put the item there or right after any duplicates.
while (item.equals(array[pos])) pos++;
{
final T temp = array[pos];
array[pos] = item;
item = temp;
}
writes++;
}
}
return writes;
}
public static final void main(String[] args) {
final Random rand = new Random();
final Integer[] array = new Integer[8];
for (int i = 0; i < array.length; i++) { array[i] = rand.nextInt(8); }
for (int iteration = 0; iteration < 10; iteration++) {
System.out.printf("array: %s ", Arrays.toString(array));
final int writes = cycleSort(array);
System.out.printf("sorted: %s writes: %d\n", Arrays.toString(array), writes);
Collections.shuffle(Arrays.asList(array));
}
}
}
一些示例运行:
array: [3, 2, 6, 1, 3, 1, 4, 4] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 6 array: [1, 3, 4, 1, 3, 2, 4, 6] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 4 array: [3, 3, 1, 1, 4, 4, 2, 6] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 6 array: [1, 1, 3, 2, 4, 3, 6, 4] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 6 array: [3, 2, 3, 4, 6, 4, 1, 1] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 7 array: [6, 2, 4, 3, 1, 3, 4, 1] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 6 array: [6, 3, 2, 4, 3, 1, 4, 1] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 5 array: [4, 2, 6, 1, 1, 4, 3, 3] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 7 array: [4, 3, 3, 1, 2, 4, 6, 1] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 7 array: [1, 6, 4, 2, 4, 1, 3, 3] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 7
array: [5, 1, 2, 3, 4, 3, 7, 0] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 5 array: [5, 1, 7, 3, 2, 3, 4, 0] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 6 array: [4, 0, 3, 1, 5, 2, 7, 3] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 8 array: [4, 0, 7, 3, 5, 1, 3, 2] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 7 array: [3, 4, 2, 7, 5, 3, 1, 0] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 7 array: [0, 5, 3, 2, 3, 7, 1, 4] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 6 array: [1, 4, 3, 7, 2, 3, 5, 0] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 7 array: [1, 5, 0, 7, 3, 3, 4, 2] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 7 array: [0, 5, 7, 3, 3, 4, 2, 1] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 4 array: [7, 3, 1, 0, 3, 5, 4, 2] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 7
答案 1 :(得分:14)
如果数组较短(即少于约100个元素),如果您还想减少写入次数,则Selection sort通常是最佳选择。
来自维基百科:
另一个关键区别是 选择排序总是执行Θ(n) 交换,插入排序执行 Θ(n 2 )在平均值和最差值中交换 案例。因为掉期需要写作 对于数组,选择排序是 写入内存时最好是 比...贵得多 读。如果是这种情况通常就是如此 物品很大但钥匙很重要 小。 写作的另一个例子 时间至关重要的是存储的数组 在EEPROM或Flash中。没有别的 数据移动较少的算法。
对于较大的数组/列表,Quicksort和朋友将提供更好的性能,但可能仍然需要更多的写入而不是选择排序。
如果您感兴趣的this is a fantastic sort visualization site允许您观看特定的排序算法,那么他们可以完成自己的工作,并且可以相互竞争不同的排序算法。
答案 2 :(得分:3)
您可以使用非常天真的算法来满足您的需求。
算法应如下所示:
i = 0
do
search for the minimum in range [i..n)
swap a[i] with a[minPos]
i = i + 1
repeat until i = n.
搜索最小值可能几乎没有任何费用,交换成本你写3,i ++花费你1 ..
如灰烬所述,这被命名为selection sort。 (对不起,我不知道这是选择排序:()
答案 3 :(得分:1)
大型数组的一个选项如下(假设n个元素):
要进行就地排序,在步骤3中,您应该确定排列中的周期,并根据需要“旋转”它们以产生排序顺序。
答案 4 :(得分:0)
如果数字在特定范围内,则任务可以在O(n)计算时间内完成,这是排序的特殊情况,通过创建数组并将每个数字映射到指定位置来完成。
如果数字不在一个范围内,最好的方法是使用QuickSort或HeapSort,它们对int O(Log2N)进行排序,但是有些人喜欢QuickSort,就像我一样。
你几乎可以在任何地方找到任何语言的QuickSort实现,只需Google就可以在几秒钟内找到它。
在组织外部数据时可以使用HeapSort,这意味着数据不在memmory中,但在硬盘中,在处理大型数组时最常见。
希望我可以提供帮助 最诚挚的问候,祝你好运!
答案 5 :(得分:0)
我在O(n)中的排序就像选择排序(上一篇文章),当你有一小部分键(或者你在2个范围之间订购数字)时很有用
如果你有一个数字数字介于-10和100之间的数组,那么你可以创建一个110的数组,并确保所有数字都适合那里,如果你考虑重复的数字,这个想法是相同的,但是你将在排序数组中有列表而不是数字
伪想法就像这样
N: max value of your array
tosort //array to be sorted
sorted = int[N]
for i = 0 to length(tosort)
do
sorted[tosort[i]]++;
end
finalarray = int[length(tosort)]
k = 0
for i = 0 to N
do
if ( sorted[i] > 0 )
finalarray[k] = i
k++;
endif
end
finalarray将具有最终排序数组,您将进行o(N)写操作,其中N是数组的范围。再一次,这在使用特定范围内的键时很有用,但也许就是你的情况。
祝你好运!