【发布时间】:2021-09-19 12:48:55
【问题描述】:
算法:
Procedure SELECT( k,S)
{ if ISI =1 then return the single element in S
else { choose an element a randomly from S;
let S1,S2,and S3 be he sequences of elements in S
less than, equal to, and greater than m, respectively;
if IS1I >=k then return SELECT(k,S1)
else
if (IS1I + IS2I >=k then return m
else return SELECT(k-IS1I-IS2I , S3);
}
}
问题是实现第一个算法以在一组整数中找到第 k 个最小的整数,并针对随机数生成器生成的不同整数组测试您的程序。 以下是我的解决方案。
import java.util.Random;
import java.util.Scanner;
public class main {
private static Random rand = new Random();
private static Scanner keyboard = new Scanner(System.in);
public static int firstAlgorithm(int k, int[] S) {
int m = S[rand.nextInt(S.length)];
int[] S1 = new int[S.length];
int[] S2 = new int[S.length];
int[] S3 = new int[S.length];
int p = 0;
int q = 0;
int r = 0;
if (S.length == 1)
return S[0];
for (int i = 0; i < S.length; i++) {
if (S[i] < m) {
S1[p] = S[i];
p++;
} else if (S[i] == m) {
S2[q] = S[i];
q++;
} else {
S3[r] = S[i];
r++;
}
}
S1 = trimToSize(S1, p);
S2 = trimToSize(S2, q);
S3 = trimToSize(S3, r);
if (S1.length >= k)
return firstAlgorithm(k, S1);
else if (S1.length + S2.length >= k)
return m;
else
return firstAlgorithm(k - S1.length - S2.length, S3);
}
private static int[] trimToSize(int[] arr, int size) {
int[] temp = new int[size];
for (int i = 0; i < size; i++) {
temp[i] = arr[i];
}
return temp;
}
public static void printArray(int[] S) {
for (int i = 0; i < S.length; i++) {
System.out.print(S[i] + "\t");
if (i % 10 == 9)
System.out.println();
}
}
// start main method
public static void main(String[] args) {
System.out.print("Enter the size of an array: ");
int size = keyboard.nextInt();
while (size < 1) {
System.out.println("Size of the array should be greater than 0.");
System.out.print("Enter the size of an array: ");
size = keyboard.nextInt();
}
System.out.print("Enter the value of k: ");
int k = keyboard.nextInt();
while (k < 1 || k > size) {
System.out.println("Value of k should be in the range 1-" + size + ".");
System.out.print("Enter the value of k: ");
k = keyboard.nextInt();
}
int[] S = new int[size];
for (int i = 0; i < size; i++) {
S[i] = 100 + rand.nextInt(900);
}
System.out.println("\nRandom values generated in the array:");
printArray(S);
System.out.println();
System.out.println(k + "th smallest value in the array using Algorithm #1: " + firstAlgorithm(k, S));
}
}
但我需要在不使用临时数组进行分区的情况下实现上述算法。我该怎么做?
【问题讨论】:
-
如果你的输入是:
1, 4, 2, 6, 2and k = 2 它的输出应该是什么? -
答案应该是 2,因为该数组的第二小是 2
-
(就地)分区算法与快速排序中的相同。你可以在这里找到伪代码:en.wikipedia.org/wiki/Quicksort#Lomuto_partition_scheme
-
请注意,您的算法是递归的,我认为 java 不会进行 tall-call 优化。这意味着在编写时,您的代码可能占用 O(n) 空间(在堆栈上)。您还应该摆脱“trimToSize”并使用数组视图(例如:stackoverflow.com/questions/39218468/…)。自己维护高低指数是列表子视图的一种简单而好的替代方法。
-
@Paul Hankin。我刚刚更新到上面给定的算法。