我一直在尝试编写合并排序,而没有创建额外的数组来保存已排序的部分,几个小时后我找不到错误,这导致数组的最后一位按错误的顺序排序。有很多辅助方法,我用于调试,我把它们留在了。
public class Sorter2
{
public static void toString(int [] list)
{
for(int i = 0; i < list.length; i++)
{
System.out.print(list[i]);
if(!(i + 1 == list.length))
{
System.out.print(",");
}
}
System.out.println("");
}
public static void toString(int list[], int from, int to)
{
for(int i = from; i <= to; i++)
{
System.out.print(list[i]);
if(i + 1 <= to)
{
System.out.print(",");
}
}
System.out.println("");
}
public static void insertAt(int [] list, int insert_at, int taken_from)
{
int to_insert = list[taken_from];
for(int i = taken_from; i >= insert_at; i--)
{
if(i != insert_at)
{
list[i] = list[i - 1];
}
else
{
list[i] = to_insert;
}
}
}
public static void sortSegments(int [] list ,int segment_one_begin, int segment_one_end, int segment_two_begin, int segment_two_end)
{
toString(list, segment_one_begin, segment_two_end);
int sorted = 0;
for(int i = segment_two_begin; i <= segment_two_end; i++)
{
for(int l = segment_one_begin + sorted; l <= segment_one_end; l++)
{
if(list[i] <= list[l])
{
insertAt(list, l, i);
sorted++;
}
}
}
toString(list, segment_one_begin, segment_two_end);
}
public static void mergeSort(int [] list, int segment_begining, int segment_end)
{
if(segment_end - segment_begining < 1)
{
return;
}
else
{
int midpoint = (segment_end + segment_begining) / 2;
mergeSort(list, segment_begining, midpoint);
mergeSort(list, midpoint + 1, segment_end);
sortSegments(list, segment_begining, midpoint, midpoint + 1, segment_end);
}
}
public static void mergeSort(int [] list)
{
mergeSort(list, 0, list.length - 1);
}
public static boolean isInOrder(int [] toCheck)
{
for(int i = 1; i < toCheck.length; i++)
{
if(toCheck[i] < toCheck[i - 1])
{
return false;
}
}
return true;
}
public static int [] populate(int numOfItems)
{
int [] toReturn = new int[numOfItems];
for(int i = 0; i < toReturn.length; i++)
{
toReturn[i] = (int) (Math.random() * 100 + 1);
}
return toReturn;
}
public static void main(String [] args)
{
int [] nums = populate(20);
mergeSort(nums);
toString(nums);
System.out.println(isInOrder(nums));
}
}
答案 0 :(得分:4)
让我们稍微调整一下代码,以便测试可以重复,我们可以看到整个过程:
import java.util.Random;
public class Sorter2 {
public static final Random RANDOM = new Random(55);
public static void toString(int[] list) {
System.out.println(Arrays.toString(list));
}
public static void toString(int list[], int from, int to) {
System.out.print(from + "\t" + to + "\t");
for (int i = from; i <= to; i++) {
System.out.print(list[i]);
if (i + 1 <= to) {
System.out.print(",");
}
}
System.out.println("");
}
public static void insertAt(int[] list, int insert_at, int taken_from) {
int to_insert = list[taken_from];
for (int i = taken_from; i >= insert_at; i--) {
if (i != insert_at) {
list[i] = list[i - 1];
} else {
list[i] = to_insert;
}
}
}
public static void sortSegments(int[] list, int segment_one_begin, int segment_one_end, int segment_two_begin, int segment_two_end) {
System.out.println("Sorter2.sortSegments("+segment_one_begin + "," + segment_one_end + "," + segment_two_begin + "," + segment_two_end + ")");
toString(list, segment_one_begin, segment_two_end);
int sorted = 0;
for (int i = segment_two_begin; i <= segment_two_end; i++) {
for (int l = segment_one_begin + sorted; l <= segment_one_end; l++) {
if (list[i] <= list[l]) {
insertAt(list, l, i);
sorted++;
}
}
}
toString(list, segment_one_begin, segment_two_end);
}
public static void mergeSort(int[] list, int segment_begining, int segment_end) {
if (segment_end - segment_begining < 1) {
return;
}
int midpoint = (segment_end + segment_begining) / 2;
mergeSort(list, segment_begining, midpoint);
mergeSort(list, midpoint + 1, segment_end);
sortSegments(list, segment_begining, midpoint, midpoint + 1, segment_end);
}
public static void mergeSort(int[] list) {
mergeSort(list, 0, list.length - 1);
}
public static boolean isInOrder(int[] toCheck) {
for (int i = 1; i < toCheck.length; i++) {
if (toCheck[i] < toCheck[i - 1]) {
return false;
}
}
return true;
}
public static int[] populate(int numOfItems) {
int[] toReturn = new int[numOfItems];
for (int i = 0; i < toReturn.length; i++) {
toReturn[i] = (int) (nextRandom() * 100 + 1);
}
return toReturn;
}
private static double nextRandom() {
return RANDOM.nextDouble();
}
public static void main(String[] args) {
int[] nums = populate(20);
mergeSort(nums);
toString(nums);
System.out.println(isInOrder(nums));
}
}
输出如下:
Sorter2.sortSegments(0,0,1,1)
0 1 73,47
0 1 47,73
Sorter2.sortSegments(0,1,2,2)
0 2 47,73,48
0 2 47,48,73
Sorter2.sortSegments(3,3,4,4)
3 4 42,64
3 4 42,64
Sorter2.sortSegments(0,2,3,4)
0 4 47,48,73,42,64
0 4 42,47,48,73,64
Sorter2.sortSegments(5,5,6,6)
5 6 12,38
5 6 12,38
Sorter2.sortSegments(5,6,7,7)
5 7 12,38,14
5 7 12,14,38
Sorter2.sortSegments(8,8,9,9)
8 9 18,87
8 9 18,87
Sorter2.sortSegments(5,7,8,9)
5 9 12,14,38,18,87
5 9 12,14,18,38,87
Sorter2.sortSegments(0,4,5,9)
0 9 42,47,48,73,64,12,14,18,38,87
0 9 12,42,14,18,38,47,48,64,73,87
Sorter2.sortSegments(10,10,11,11)
10 11 60,29
10 11 29,60
Sorter2.sortSegments(10,11,12,12)
10 12 29,60,95
10 12 29,60,95
Sorter2.sortSegments(13,13,14,14)
13 14 21,37
13 14 21,37
Sorter2.sortSegments(10,12,13,14)
10 14 29,60,95,21,37
10 14 21,29,37,60,95
Sorter2.sortSegments(15,15,16,16)
15 16 28,66
15 16 28,66
Sorter2.sortSegments(15,16,17,17)
15 17 28,66,73
15 17 28,66,73
Sorter2.sortSegments(18,18,19,19)
18 19 80,69
18 19 69,80
Sorter2.sortSegments(15,17,18,19)
15 19 28,66,73,69,80
15 19 28,66,69,73,80
Sorter2.sortSegments(10,14,15,19)
10 19 21,29,37,60,95,28,66,69,73,80
10 19 21,28,29,37,60,95,66,69,73,80
Sorter2.sortSegments(0,9,10,19)
0 19 12,42,14,18,38,47,48,64,73,87,21,28,29,37,60,95,66,69,73,80
0 19 12,21,28,29,37,42,14,18,38,47,48,64,73,87,60,95,66,69,73,80
12,21,28,29,37,42,14,18,38,47,48,64,73,87,60,95,66,69,73,80
false
如您所见,第一个问题表现在以下几行:
Sorter2.sortSegments(0,2,3,4)
0 4 47,48,73,42,64
0 4 42,47,48,73,64
我们采取两个有序的块,结果得到一个无序的块。在第for (int i = segment_two_begin; i <= segment_two_end; i++) {
行放置一个断点,并试着抓住Sorter2.sortSegments(0,2,3,4)
的案例:
42 <= 47
,因此我们呼叫insertAt
在47 segment_two
- 并且相信已到位!以下是您的错误:您的sortSegments
无法正常宣传。
如果你想一下这个方法,你会发现你实际上并不需要嵌套循环:你需要的只是逐步找到必要的元素。因此,从segment_one_begin
到segment_two_end
的一个周期和第二个列表中当前位置的指针最好:如果第一个列表中的元素低于第二个列表中的一个,则只需跳到新的位置。如果不是,则执行所需的移位 - 并移动指针。
我已经修复了它对我来说效果很好 - 所以它似乎是你实现中唯一的错误。如果你仍然卡住,请描述你的问题,我会尽力帮助。
答案 1 :(得分:0)
答案 2 :(得分:0)
import java.util.Scanner;
public class Main {
public static int[] t;
public static void merge(int[] a, int lo, int mid, int hi) {
int i = lo;
int j = mid + 1;
for (int k = lo; k <= hi; k++) t[k] = a[k];
for (int k = lo; k <= hi; k++) {
if (i > mid) a[k] = t[j++];
else if (j > hi) a[k] = t[i++];
else if (t[j] < t[i]) {
a[k] = t[j++];
} else a[k] = t[i++];
}
}
public static void sort(int[] a) {
t = new int[a.length];
sort(a, 0, a.length - 1);
}
private static void sort(int[] a, int lo, int hi) {
if (lo >= hi) return;
int mid = lo + (hi - lo) / 2;
sort(a, lo, mid);
sort(a, mid + 1, hi);
merge(a, lo, mid, hi);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) arr[i] = sc.nextInt();
sort(arr);
}
}