我有2个排序的数组,a1
和a2
,分别为l1
和l2
。数组a2
在长度l1
的末尾有空格,因此除了自己的元素外,它还可以包含a1
的所有元素。现在,我想将a1
合并到a2
中,以便a2
按排序顺序包含a1
和a2
的所有元素。理想情况下,这应该使用O(1)辅助存储空间。我有以下鳕鱼,但是出了点问题:
public static int[] merge(int []a1,int a2[],int l1, int l2){
System.out.println("l1 =" +l1 + " l2=" +l2);
int es = l2-l1;
int fs = l2-es;
System.out.println("es= " +es);
System.out.println("fs = " + fs);
int j=0;
for(int i=0;i< l1;i++){
if(j<fs){
// System.out.println("i= " + i + "a1[i]=" + a1[i]);
// System.out.println("j= " + j + "a2[j]=" + a2[j]);
if(a1[i]<a2[j]){
add(a2,j,a1[i],l2);
//i++;
fs++;
}
}else{
System.out.println("***");
a2[j]=a1[i];
}
j++;
}
return a2;
}
public static void add(int []a,int p,int key,int l){
for(int i=l-1;i>p;i--){
a[i]= a[i-1];
}
a[p]= key;
}
有没有人对如何解决这个问题有任何想法?我使用以下数据来运行代码:
int a1[]= new int[]{-1,0,7,8};
int a2[]= new int[7];
a2[0]=1;
a2[1]=3;
a2[2]=9;
输出
l1 =4 l2=7
es= 3
fs = 4
-1
0
1
3
9
0
0
答案 0 :(得分:9)
很难说出你的代码做了什么,但似乎有一个次优(O(n^2)
)的复杂性:add
方法中有第二个循环。
另请注意,fs
始终等于l1
。
但是有更简单的方法:从后面开始。如果你考虑一下,总有足够的空间。
像这样的东西
int i = l1 - 1;
int j = l2 - 1;
int result_pos = l1 + l2 - 1;
while (i >= 0 || j >= 0) {
if (a1[i] >= a2[j]) {
a2[result_pos--] = a1[i--];
} else {
a2[result_pos--] = a2[j--];
}
}
PS当i
和j
中的一个在循环中为负时,您需要为该案例添加处理。显然,在这种情况下,应该复制另一个元素。
修改强>
以后可以用这个条件来完成
if (j < 0 || (i >= 0 && a1[i] >= a2[j])) {
而不是
if (a1[i] >= a2[j]) {
答案 1 :(得分:4)
如果a1
和a2
中的元素已排序,那么您将拥有以下内容:
a1 : [-1] [0] [7] [8]
a2 : [1] [3] [9] [] [] [] []
所以在代码中你可以这样做:
int a1i = 0; // pointer to the ith element in the array a1
int tmp = 0;
int i = 0;
for(i = 0; i < a1.length; i++) {
if(a2[i] > a1[a1i]) {
tmp = a2[i];
a2[i] = a1[a1i];
a1[a1i] = tmp;
Arrays.sort(a1); // This might take more memory though...
} else {
a1i++;
}
}
a1i = 0;
for(i; i < a2.length; i++) {
a2[i] = a1[a1i];
a1i++;
}
这可以解决:
a1 : [-1] [0] [7] [8]
^
a2 : [1] [3] [9] [] [] [] []
^
SWAP
a1 : [1] [0] [7] [8]
^
a2 : [-1] [3] [9] [] [] [] []
^
SORT
a1 : [0] [1] [7] [8]
^
a2 : [-1] [3] [9] [] [] [] []
^
SWAP
a1 : [3] [1] [7] [8]
^
a2 : [-1] [0] [9] [] [] [] []
^
SORT
a1 : [1] [3] [7] [8]
^
a2 : [-1] [0] [9] [] [] [] []
^
SWAP
a1 : [9] [3] [7] [8]
^
a2 : [-1] [0] [1] [] [] [] []
^
SORT
a1 : [3] [7] [8] [9]
^
a2 : [-1] [0] [1] [] [] [] []
^
COPY
a1 : [3] [7] [8] [9]
^
a2 : [-1] [0] [1] [3] [] [] []
^
COPY
a1 : [3] [7] [8] [9]
^
a2 : [-1] [0] [1] [3] [7] [] []
^
COPY
a1 : [3] [7] [8] [9]
^
a2 : [-1] [0] [1] [3] [7] [8] []
^
COPY
a1 : [3] [7] [8] [9]
^
a2 : [-1] [0] [1] [3] [7] [8] [9]
^
END
答案 2 :(得分:2)
首先,将a1的元素移到a1的后面。第二次合并a1和a2从a1的前面开始(即,将两个元素的最小值与a1中的当前索引进行比较,其中当前索引从0开始,范围最大为a1.length + a2.length - 1) 。这将阻止您覆盖a1。
的任何元素答案 3 :(得分:1)
我会从最后开始合并。
在最后一个元素处,放置max(lastOf(a1), lastOf(f2))
。继续从任一阵列的其余部分一次咬掉一个元素,直到其中一个元素耗尽。把剩下的剩下的数组放在开头(可能是一个no-op)。
答案 4 :(得分:1)
有很多好的答案。我只是想添加一些东西(评论已经被埋没了):
这只是merge-sort或类似的合并阶段,例如k-way sort。只需使用就地合并例程。 “较小的数组”或“空格”可用于在“较大的数组”中存储值,这些值当前不是按排序顺序。
可以借用不同算法的点点滴滴: - )
答案 5 :(得分:1)
解决该问题的更好方法是将插入排序用于合并O(1)辅助空间中的两个排序数组。
/ *,因为我们必须合并array2中的2个排序数组。我们从array2的末尾开始,并在acc的正确位置插入array元素。插入排序* /
public static int[] merge(int []a1,int a2[],int l1, int l2){
int len2=l2-l1;
for(int i=l1-1;i>=0;i--){
int j=len2-1;
for(;j>=0 && j+1<l2 && a2[j]>a[i];j--){
a2[j+1]=a2[j];
}
a2[j+1]=a1[i];
len2++;
}
}
答案 6 :(得分:0)
为什么要编写自己的代码呢?如果a2有足够的空白空间来容纳a1的元素,只需将元素从a1复制到a2(使用arraycopy),然后使用Arrays.sort()。这会给你O(n * log(n)),而你的简单方法似乎也是O(n * n)。
(但合并可以在O(n)中完成。)
答案 7 :(得分:0)
我假设您对算法的时间复杂性没有限制。 我的建议是将a1的值附加到a2并应用任何O(nlogn)排序算法,如quicksort。但是,如果您想进行合并,我认为此代码可以帮助您:
public static void main(String[] args) {
// TODO Auto-generated method stub
int a1[]= new int[]{-1,0,7,8};
int a2[]= new int[7];
a2[0]=1;
a2[1]=3;
a2[2]=9;
merge(a1, a2, 3);
}
private static void merge(int[] a1, int[] a2, int lastPos) {
for ( int i = 0; i < a1.length; i++)
{
for ( int j = 0; j < a2.length; j++)
if ( a1[i] < a2[j] )
{
add(a1[i], a2, j, lastPos);
lastPos++;
break; //since a2 is also sorted
}
}
}
private static void add(int val, int[] a2, int j, int lastPos) {
for ( int i = lastPos; i > j; i--)
a2[i] = a2[i-1];
a2[j] = val;
}
答案 8 :(得分:0)
合并两个排序数组而不使用额外内存
#include<iostream>
using namespace std ;
const int N = 100 ;
int a[N] , b[N] , n , m , len , L ;
int main() {
cin >> n ;
for( int i = 0 ; i < n ; i++ ) cin >> a[i] ;
cin >> m ;
for( int i = 0 ; i < m ; i++ ) cin >> b[i] ;
len = n + m - 1 ;
L = n + m ;
n-- , m-- ;
while( len >= 0 ) {
if( m < 0 ) a[len] = a[n--];
else if( n < 0 ) a[len] = b[m--];
else if( a[n] > b[m] ) a[len] = a[n--];
else a[len] = b[m--];
len--;
}
for( int i = 0 ; i < L ; i++ ) cout << a[i] << " " ;
}
答案 9 :(得分:0)
这只是合并排序的合并阶段,
(1,2,3,4)
的末尾复制a2 (5,6,7,8)
的所有元素,现在a1将包含(4,5,6,7,8,1,2,3,4)
inPlaceMerge(collection, 0<low>,3<mid>,7<high>);
这是Java中的算法,
public static <T extends Comparable<? super T>> void inPlaceMerge(T[] collection, int low, int mid, int high) {
int left = low;
int right = mid + 1;
if(collection[mid].equals(collection[right])) {
return ;//Skip the merge if required
}
while (left <= mid && right <= high) {
// Select from left: no change, just advance left
if (collection[left].compareTo(collection[right]) <= 0) {
left ++;
} else { // Select from right: rotate [left..right] and correct
T tmp = collection[right]; // Will move to [left]
rotateRight(collection, left, right - left);
collection[left] = tmp;
// EVERYTHING has moved up by one
left ++; right ++; mid ++;
}
}
}
private static <T extends Comparable<? super T>> void rotateRight(T[] collection, int left, int numberOfElements) {
System.arraycopy(collection, left, collection, left+1, numberOfElements);
}
这是单元测试
@Test
public void inPlaceMergeFirstTest() {
Integer[] collection = new Integer[]{5,6,7,8,1,2,3,4};
ArrayUtils.<Integer>inPlaceMerge(collection, 0,3,7);
Integer[] result = new Integer[]{1,2,3,4,5,6,7,8};
assertThat(collection, equalTo(result));
}
答案 10 :(得分:0)
/ ,或者简单地,您可以执行此操作-> /
public static int[] merge(int []a1,int a2[],int l1, int l2){
int j=0;
for(int i=l2-l1;i<l2;i++)
{
a2[i]=a1[j];
j++;
}
Arrays.sort(a2);
return a2;
}
答案 11 :(得分:-1)
你试过System.arrayCopy吗?类似的东西:
...
System.arraycopy(a2, 0, a2, a1.length, a2.length);
System.arraycopy(a1, 0, a1, 0, a1.length);
...
在不浪费时间的情况下应该做到这一点(arraycopy针对这些用例进行了优化)。