如何将两个排序数组合并为一个排序数组?[关闭]


160

这是在采访中问我的,这是我提供的解决方案:

public static int[] merge(int[] a, int[] b) {

    int[] answer = new int[a.length + b.length];
    int i = 0, j = 0, k = 0;
    while (i < a.length && j < b.length)
    {
        if (a[i] < b[j])
        {
            answer[k] = a[i];
            i++;
        }
        else
        {
            answer[k] = b[j];
            j++;
        }
        k++;
    }

    while (i < a.length)
    {
        answer[k] = a[i];
        i++;
        k++;
    }

    while (j < b.length)
    {
        answer[k] = b[j];
        j++;
        k++;
    }

    return answer;
}

有没有更有效的方法可以做到这一点?

编辑:更正的长度方法。


30
看起来对我来说是一个很好的答案。这个问题最多将具有O(n)复杂度,而您的答案就可以实现。其他任何事情都将是微优化。
德鲁·霍尔

3
你做得不错!这实际上是合并排序的一部分:将两个排序的流(来自磁带或磁盘)合并到另一个排序的流中。
2011年

9
你有工作吗?
柴2013年

5
您还可以使用三元运算符: while (i < a.length && j < b.length) answer[k++] = a[i] < b[j] ? a[i++] : b[j++]; Java语言规范:条件运算符?:
Anton Dozortsev 2014年

1
你忘了评论!!!
LiziPizi '16

Answers:


33

稍有改进,但是在主循环之后,System.arraycopy当到达另一个输入数组的末尾时,可以用来复制其中一个输入数组的结尾。但是,那不会改变O(n)您解决方案的性能特征。


109
public static int[] merge(int[] a, int[] b) {

    int[] answer = new int[a.length + b.length];
    int i = 0, j = 0, k = 0;

    while (i < a.length && j < b.length)  
       answer[k++] = a[i] < b[j] ? a[i++] :  b[j++];

    while (i < a.length)  
        answer[k++] = a[i++];

    while (j < b.length)    
        answer[k++] = b[j++];

    return answer;
}

稍微紧凑一点,但完全一样!


对于说这导致索引超出范围异常的人,您正在使用哪些输入?它在所有情况下都对我有效。
Mike Saull 2013年

1
使用for循环合并声明循环变量和循环控制的行。尽量少使用双空行-在对称“尾部复制”之间看起来是不需要的。
灰胡子'18

58

令我惊讶的是,没有人提到这种更酷,更有效和更紧凑的实现:

public static int[] merge(int[] a, int[] b) {
    int[] answer = new int[a.length + b.length];
    int i = a.length - 1, j = b.length - 1, k = answer.length;

    while (k > 0)
        answer[--k] =
                (j < 0 || (i >= 0 && a[i] >= b[j])) ? a[i--] : b[j--];
    return answer;
}

兴趣点

  1. 请注意,它执行的操作数与其他O(n)算法相同或更少,但实际上是在单个while循环中的单个语句中!
  2. 如果两个数组的大小大致相同,则O(n)的常数相同。但是,如果数组真的不平衡,则版本System.arraycopy会胜出,因为在内部它可以使用单个x86汇编指令来实现。
  3. 请注意,a[i] >= b[j]而不要注意a[i] > b[j]。这保证了“稳定性”,即当a和b的元素相等时,我们需要a之前的元素b。

这是一个非常好的方法。我很难在Swift lang中的Merge排序算法上获得良好的基准。转换此代码后,我得到了我所需要的,非常感谢
Chackle

while循环中(j <0)的意义是什么?顺便说一句,+ 1,这真的很酷!感谢分享。
亨伽美

2
@Hengameh以防万一j < 0b已经筋疲力尽,所以我们继续将其余a元素添加到answer 数组中
Natan Streppel

6
太“聪明”了,在我的脑海中难以阅读。我更喜欢容易阅读的代码,尤其是因为您实际上并没有在此代码上实现任何性能上的改善。
凯文M

1
加点为Notice,并且a [i]> = b [j]而不是a [i]> b [j]。这保证了“稳定性”
Yan Khonski

16

可以进行的任何改进都是微优化,总体算法是正确的。


如果a大而b小,则此算法是错误的。
2013年

7
这没有错,但效率不高。
2013年

@jack在生成n个项目的数组时,如何比O(n)更快?
2014年

@will System.arrayCopy()速度非常快,因为它使用了CPU优化的memcpy调用。因此,可以通过复制块来提高性能。也可以对边界进行二进制搜索。
苗条

特别是如果您可以使用排序的性质来跳过大多数条目,并且从不进行比较。您实际上可以击败O(n)。
Ta

10

除了使用System.arrayCopy复制其余数组元素外,此解决方案还与其他帖子非常相似。

private static int[] sortedArrayMerge(int a[], int b[]) {
    int result[] = new int[a.length +b.length];
    int i =0; int j = 0;int k = 0;
    while(i<a.length && j <b.length) {
        if(a[i]<b[j]) {
            result[k++] = a[i];
            i++;
        } else {
            result[k++] = b[j];
            j++;
        }
    }
    System.arraycopy(a, i, result, k, (a.length -i));
    System.arraycopy(b, j, result, k, (b.length -j));
    return result;
}

7

这是更新的功能。它将删除重复项,希望有人会发现它可用:

public static long[] merge2SortedAndRemoveDublicates(long[] a, long[] b) {
    long[] answer = new long[a.length + b.length];
    int i = 0, j = 0, k = 0;
    long tmp;
    while (i < a.length && j < b.length) {
        tmp = a[i] < b[j] ? a[i++] : b[j++];
        for ( ; i < a.length && a[i] == tmp; i++);
        for ( ; j < b.length && b[j] == tmp; j++);
        answer[k++] = tmp;
    }
    while (i < a.length) {
        tmp = a[i++];
        for ( ; i < a.length && a[i] == tmp; i++);
        answer[k++] = tmp;
    }
    while (j < b.length) {
        tmp = b[j++];
        for ( ; j < b.length && b[j] == tmp; j++);
        answer[k++] = tmp;
    }
    return Arrays.copyOf(answer, k);
}

+1,感谢您的分享。一个问题:为什么要选择数组的类型和变量'temp'的类型呢?
亨伽美

(我对方法名称有疑问。)
greybeard

5

可以通过以下4条语句完成

 int a[] = {10, 20, 30};
 int b[]= {9, 14, 11};
 int res[]=new int[a.legth+b.length]; 
 System.arraycopy(a,0, res, 0, a.length); 
 System.arraycopy(b,0,res,a.length, b.length);
 Array.sort(res)


5
我不明白为什么这个答案获得否定票。的确,它效率不高。但是有时候您所需要的只是尽快完成工作。如果您要处理的数组非常小,例如少于100个元素,我宁愿使用上面的代码,而不是编写不会对性能进行任何重要改进的冗长代码。因此,感谢Sudhir提供了这种简单的解决方案,并感谢SANN3进行了编辑。
Ahmedov

2
不成文的前提是sort函数不能将自身用作排序方法。那将是无限回归而不是递归。另外一个前提是merge_array是实现sort的函数。因此,此答案在最可能的情况下不可用。
Aki Suihkonen 2015年

提出的问题没有提到所需的代码仅适用于小型数组。因此,除非明确说明其局限性,否则该答案将具有误导性。也请看下面我的回答。编写适用于任何数组大小的有效代码所需的行数相同:)
Shital Shah 2015年

问题规定数组已按排序顺序排列。如果阵列可能非常大,则此解决方案将陷入停顿并表现不佳。因此,请确保您将获得所需的最终结果,但如果我正在面试,则该应用程序将无法运行并且您也将无法获得工作。
凯文M

Array.sort()函数使用TimSort,TimSort非常会找到已排序的运行并对其进行合并排序。奇怪的是,该代码甚至不能真正因为“效率低下”而出错,由于排序运行,它实际上会在O(n)时间内完成。您可以在上面运行一些基准测试,很有可能会经常击败OP代码。
塔塔雷泽化

4

我必须用javascript编写,这里是:

function merge(a, b) {
    var result = [];
    var ai = 0;
    var bi = 0;
    while (true) {
        if ( ai < a.length && bi < b.length) {
            if (a[ai] < b[bi]) {
                result.push(a[ai]);
                ai++;
            } else if (a[ai] > b[bi]) {
                result.push(b[bi]);
                bi++;
            } else {
                result.push(a[ai]);
                result.push(b[bi]);
                ai++;
                bi++;
            }
        } else if (ai < a.length) {
            result.push.apply(result, a.slice(ai, a.length));
            break;
        } else if (bi < b.length) {
            result.push.apply(result, b.slice(bi, b.length));
            break;
        } else {
            break;
        }
    }
    return result;
}

4

从版本4开始,Apache集合支持collat​​e方法。您可以使用以下collate方法执行此操作:

org.apache.commons.collections4.CollectionUtils

这里引用javadoc:

collate(Iterable<? extends O> a, Iterable<? extends O> b, Comparator<? super O> c)

将两个排序的Collections a和合并b到一个单独的排序列表中,以便保留根据比较器c进行的元素排序。

不要重新发明轮子!参考文档:http : //commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/CollectionUtils.html


4

GallopSearch合并:O(log(n)* log(i))而不是O(n)

我继续在评论中实施了灰胡子建议。主要是因为我需要此代码的高效关键任务版本。

  • 该代码使用gallopSearch,它是O(log(i)),其中i是与当前索引相关的索引所在的距离。
  • 疾驰搜索确定正确的范围后,代码将使用binarySearch进行搜索。由于疾驰将其限制在较小的范围内,因此生成的binarySearch也为O(log(i))
  • 疾驰和合并是向后执行的。这似乎不是关键任务,但它允许就地合并阵列。如果您的一个数组有足够的空间来存储结果值,则可以简单地将其用作合并数组,然后结果数组。在这种情况下,必须在数组内指定有效范围。
  • 在那种情况下,它不需要内存分配(在关键操作中节省了很多钱)。它只是确保它不会并且不会覆盖任何未处理的值(只能向后执行)。实际上,您对输入和结果使用相同的数组。它不会受到任何不良影响。
  • 我一直使用Integer.compare(),因此可以出于其他目的将其切换出来。
  • 我可能有一些机会被误用了,并且没有利用以前证明的信息。例如,对两个值的范围进行二进制搜索,已经检查了一个值。还有一种更好的方式来声明主循环,如果将它们依次组合为两个操作,则不需要翻转c值。既然您知道您每次都会做一个,那么另一个。还有一些地方可以擦亮。

这应该是最有效的方法,时间复杂度为O(log(n)* log(i))而不是O(n)。最坏的情况是O(n)的时间复杂度。如果您的数组很杂乱,并且有很长的值字符串,那么这将使其他方法相形见,,否则它会比它们更好。

在合并数组的末尾有两个读取值,在结果数组中有两个写入值。在找出哪个终值较小之后,它将对该数组进行一次快速搜索。1、2、4、8、16、32等。当它找到另一个数组的读取值较大的范围时。它二进制搜索到该范围(将范围切成一半,搜索正确的一半,重复直到单个值)。然后,它会将这些值复制到写入位置。请记住,必须对副本进行移动,以使其不能覆盖任何一个读取数组中的相同值(这意味着写入数组和读取数组可以相同)。然后,它对另一个阵列执行相同的操作,该操作现在已知小于另一个阵列的新读取值。

static public int gallopSearch(int current, int[] array, int v) {
    int d = 1;
    int seek = current - d;
    int prevIteration = seek;
    while (seek > 0) {
        if (Integer.compare(array[seek], v) <= 0) {
            break;
        }
        prevIteration = seek;
        d <<= 1;
        seek = current - d;
        if (seek < 0) {
            seek = 0;
        }
    }
    if (prevIteration != seek) {
        seek = binarySearch(array, seek, prevIteration, v);
        seek = seek >= 0 ? seek : ~seek;
    }
    return seek;
}

static public int binarySearch(int[] list, int fromIndex, int toIndex, int v) {
    int low = fromIndex;
    int high = toIndex - 1;
    while (low <= high) {
        int mid = (low + high) >>> 1;
        int midVal = list[mid];
        int cmp = Integer.compare(midVal, v);
        if (cmp < 0) {
            low = mid + 1;
        } else if (cmp > 0) {
            high = mid - 1;
        } else {
            return mid;// key found
        }
    }
    return -(low + 1);// key not found.
}

static public int[] sortedArrayMerge(int[] a, int[] b) {
    return sortedArrayMerge(null, a, a.length, b, b.length);
}

static public int[] sortedArrayMerge(int[] results, int[] a, int aRead, int b[], int bRead) {
    int write = aRead + bRead, length, gallopPos;
    if ((results == null) || (results.length < write)) {
        results = new int[write];
    }
    if (aRead > 0 && bRead > 0) {
        int c = Integer.compare(a[aRead - 1], b[bRead - 1]);
        while (aRead > 0 && bRead > 0) {
            switch (c) {
                default:
                    gallopPos = gallopSearch(aRead, a, b[bRead-1]);
                    length = (aRead - gallopPos);
                    write -= length;
                    aRead = gallopPos;
                    System.arraycopy(a, gallopPos--, results, write, length);
                    c = -1;
                    break;
                case -1:
                    gallopPos = gallopSearch(bRead, b, a[aRead-1]);
                    length = (bRead - gallopPos);
                    write -= length;
                    bRead = gallopPos;
                    System.arraycopy(b, gallopPos--, results, write, length);
                    c = 1;
                    break;
            }
        }
    }
    if (bRead > 0) {
        if (b != results) {
            System.arraycopy(b, 0, results, 0, bRead);
        }
    } else if (aRead > 0) {
        if (a != results) {
            System.arraycopy(a, 0, results, 0, aRead);
        }
    }
    return results;
}

这应该是最有效的方法。


一些答案具有重复删除功能。这将需要O(n)算法,因为您必须实际比较每个项目。因此,这是一个独立的方法,将在事实之后应用。如果需要查看所有条目,则不能一路浏览多个条目,但是如果有很多条目,则可以浏览多个条目。

static public int removeDuplicates(int[] list, int size) {
    int write = 1;
    for (int read = 1; read < size; read++) {
        if (list[read] == list[read - 1]) {
            continue;
        }
        list[write++] = list[read];
    }
    return write;
}

更新:以前的答案,不是可怕的代码,但明显不如上述。

另一个不必要的超优化。它不仅为结尾位调用arraycopy,而且还为开头调用。通过BinarySearch处理O(log(n))中的任何介绍性非重叠数据。O(log(n)+ n)为O(n),在某些情况下效果会非常明显,尤其是在合并数组之间完全没有重叠的情况下。

private static int binarySearch(int[] array, int low, int high, int v) {
    high = high - 1;
    while (low <= high) {
        int mid = (low + high) >>> 1;
        int midVal = array[mid];
        if (midVal > v)
            low = mid + 1;
        else if (midVal < v)
            high = mid - 1;
        else
            return mid; // key found
    }
    return low;//traditionally, -(low + 1);  // key not found.
}

private static int[] sortedArrayMerge(int a[], int b[]) {
    int result[] = new int[a.length + b.length];
    int k, i = 0, j = 0;
    if (a[0] > b[0]) {
        k = i = binarySearch(b, 0, b.length, a[0]);
        System.arraycopy(b, 0, result, 0, i);
    } else {
        k = j = binarySearch(a, 0, a.length, b[0]);
        System.arraycopy(a, 0, result, 0, j);
    }
    while (i < a.length && j < b.length) {
        result[k++] = (a[i] < b[j]) ? a[i++] : b[j++];
    }
    if (j < b.length) {
        System.arraycopy(b, j, result, k, (b.length - j));
    } else {
        System.arraycopy(a, i, result, k, (a.length - i));
    }
    return result;
}

1
赞成开始对对称做一些事情,但为什么到此为止呢?使用疾驰搜索,让它等号返回索引 。仅在3个以上的元素时使用数组复制。请注意,在该副本之后,除了a)一个输入中的起始索引和输出数组b)您对哪个“ next”元素较小的了解之外,什么都没有改变。
灰胡子

这完全是实现的Arrays.sort所做的。最糟糕的是,这是一种合并排序。我认为他们在需要的地方交换了2个元素,但是落入arraycopy的两个以上元素。我不确定是要线性检查下一个元素还是对其进行二进制搜索。推测性地检查是否可以疾驰更大的距离会有很大的优势。就像前面的检查8一样,如果可以复制,您可以自己保存7项操作,而无需查看。
塔塔雷泽

@greybeard ...完成。也倒退了,所以我可以重用相同的内存。
Tatarize

你激励弹道的好事。白天时间后,我们将近距离观察。
灰胡子'18

That is totally what the implemented Arrays.sort does那是:从您的答案的第一个修订版起-或-从我2月19日的评论起?)-在Sunsoft的JDK 8中找不到:Arrays.sort您指的是哪种实现?
灰胡子'18

2

这是用javascript编写的简化形式:

function sort( a1, a2 ) {

    var i = 0
        , j = 0
        , l1 = a1.length
        , l2 = a2.length
        , a = [];

    while( i < l1 && j < l2 ) {

        a1[i] < a2[j] ? (a.push(a1[i]), i++) : (a.push( a2[j]), j++);
    }

    i < l1 && ( a = a.concat( a1.splice(i) ));
    j < l2 && ( a = a.concat( a2.splice(j) ));

    return a;
}

1
    public class Merge {

    // stably merge a[lo .. mid] with a[mid+1 .. hi] using aux[lo .. hi]
    public static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {

        // precondition: a[lo .. mid] and a[mid+1 .. hi] are sorted subarrays
        assert isSorted(a, lo, mid);
        assert isSorted(a, mid+1, hi);

        // copy to aux[]
        for (int k = lo; k <= hi; k++) {
            aux[k] = a[k]; 
        }

        // merge back to a[]
        int i = lo, j = mid+1;
        for (int k = lo; k <= hi; k++) {
            if      (i > mid)              a[k] = aux[j++];
            else if (j > hi)               a[k] = aux[i++];
            else if (less(aux[j], aux[i])) a[k] = aux[j++];
            else                           a[k] = aux[i++];
        }

        // postcondition: a[lo .. hi] is sorted
        assert isSorted(a, lo, hi);
    }

    // mergesort a[lo..hi] using auxiliary array aux[lo..hi]
    private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
        if (hi <= lo) return;
        int mid = lo + (hi - lo) / 2;
        sort(a, aux, lo, mid);
        sort(a, aux, mid + 1, hi);
        merge(a, aux, lo, mid, hi);
    }

    public static void sort(Comparable[] a) {
        Comparable[] aux = new Comparable[a.length];
        sort(a, aux, 0, a.length-1);
        assert isSorted(a);
    }


   /***********************************************************************
    *  Helper sorting functions
    ***********************************************************************/

    // is v < w ?
    private static boolean less(Comparable v, Comparable w) {
        return (v.compareTo(w) < 0);
    }

    // exchange a[i] and a[j]
    private static void exch(Object[] a, int i, int j) {
        Object swap = a[i];
        a[i] = a[j];
        a[j] = swap;
    }


   /***********************************************************************
    *  Check if array is sorted - useful for debugging
    ***********************************************************************/
    private static boolean isSorted(Comparable[] a) {
        return isSorted(a, 0, a.length - 1);
    }

    private static boolean isSorted(Comparable[] a, int lo, int hi) {
        for (int i = lo + 1; i <= hi; i++)
            if (less(a[i], a[i-1])) return false;
        return true;
    }


   /***********************************************************************
    *  Index mergesort
    ***********************************************************************/
    // stably merge a[lo .. mid] with a[mid+1 .. hi] using aux[lo .. hi]
    private static void merge(Comparable[] a, int[] index, int[] aux, int lo, int mid, int hi) {

        // copy to aux[]
        for (int k = lo; k <= hi; k++) {
            aux[k] = index[k]; 
        }

        // merge back to a[]
        int i = lo, j = mid+1;
        for (int k = lo; k <= hi; k++) {
            if      (i > mid)                    index[k] = aux[j++];
            else if (j > hi)                     index[k] = aux[i++];
            else if (less(a[aux[j]], a[aux[i]])) index[k] = aux[j++];
            else                                 index[k] = aux[i++];
        }
    }

    // return a permutation that gives the elements in a[] in ascending order
    // do not change the original array a[]
    public static int[] indexSort(Comparable[] a) {
        int N = a.length;
        int[] index = new int[N];
        for (int i = 0; i < N; i++)
            index[i] = i;

        int[] aux = new int[N];
        sort(a, index, aux, 0, N-1);
        return index;
    }

    // mergesort a[lo..hi] using auxiliary array aux[lo..hi]
    private static void sort(Comparable[] a, int[] index, int[] aux, int lo, int hi) {
        if (hi <= lo) return;
        int mid = lo + (hi - lo) / 2;
        sort(a, index, aux, lo, mid);
        sort(a, index, aux, mid + 1, hi);
        merge(a, index, aux, lo, mid, hi);
    }

    // print array to standard output
    private static void show(Comparable[] a) {
        for (int i = 0; i < a.length; i++) {
            StdOut.println(a[i]);
        }
    }

    // Read strings from standard input, sort them, and print.
    public static void main(String[] args) {
        String[] a = StdIn.readStrings();
        Merge.sort(a);
        show(a);
    }
}

此副本a[mid+1 .. hi]aux用途是什么?
灰胡子'18

1

我认为为较大的排序数组引入跳过列表可以减少比较次数,并可以加快复制到第三个数组的过程。如果数组太大,这可能会很好。


1
public int[] merge(int[] a, int[] b) {
    int[] result = new int[a.length + b.length];
    int aIndex, bIndex = 0;

    for (int i = 0; i < result.length; i++) {
        if (aIndex < a.length && bIndex < b.length) {
            if (a[aIndex] < b[bIndex]) {
                result[i] = a[aIndex];
                aIndex++;
            } else {
                result[i] = b[bIndex];
                bIndex++;
            }
        } else if (aIndex < a.length) {
            result[i] = a[aIndex];
            aIndex++;
        } else {
            result[i] = b[bIndex];
            bIndex++;
        }
    }

    return result;
}

2
一些解释会很好。:)
gsamaras

1
public static int[] merge(int[] a, int[] b) {
    int[] mergedArray = new int[(a.length + b.length)];
    int i = 0, j = 0;
    int mergedArrayIndex = 0;
    for (; i < a.length || j < b.length;) {
        if (i < a.length && j < b.length) {
            if (a[i] < b[j]) {
                mergedArray[mergedArrayIndex] = a[i];
                i++;
            } else {
                mergedArray[mergedArrayIndex] = b[j];
                j++;
            }
        } else if (i < a.length) {
            mergedArray[mergedArrayIndex] = a[i];
            i++;
        } else if (j < b.length) {
            mergedArray[mergedArrayIndex] = b[j];
            j++;
        }
        mergedArrayIndex++;
    }
    return mergedArray;
}

节省的恩典是什么?它可以缩小到for (int i, j, k = i = j = 0 ; k < c.length ; ) c[k++] = b.length <= j || i < a.length && a[i] < b[j] ? a[i++] : b[j++];。与2014年安德鲁的答案有何不同?
灰胡子'18

1

可以通过多种方式增强算法。例如,检查a[m-1]<b[0]或是合理的b[n-1]<a[0]。在任何一种情况下,都无需进行更多比较。算法可以按照正确的顺序仅按结果数组中的一个复制源数组。

更复杂的增强功能可能包括搜索交织部分并仅针对它们运行合并算法。当合并数组的大小不同时,它可以节省很多时间。


对于此增强功能,最好使用二进制搜索检查第一个元素在第二个数组中的位置,然后用arraycopy将该数据开始。然后,在其中一项检查为真的情况下,将只对所有内容进行arraycopy,然后对三进制进行arraycopy,您将获得相同的结果。但是,在出现一点点重叠的情况下,您只需要在重叠期间执行适当的算法即可,而无需其他时间。由于您事先使用一些快速的O(logn)命令就无法使用O(n),因此不会花费任何费用。
塔塔雷泽

1

此问题与mergesort算法有关,在该算法中,两个已排序的子数组组合为一个已排序的子数组。该CLRS书中给出的算法的一个例子并清理用于如果所述端已通过添加一个标记值(一些进行比较,并“大于任何其他值”),以每个阵列的端部达到检查的需要。

我用Python编写了此代码,但它也可以很好地转换为Java:

def func(a, b):
    class sentinel(object):
        def __lt__(*_):
            return False

    ax, bx, c = a[:] + [sentinel()], b[:] + [sentinel()], []
    i, j = 0, 0

    for k in range(len(a) + len(b)):
        if ax[i] < bx[j]:
            c.append(ax[i])
            i += 1
        else:
            c.append(bx[j])
            j += 1

    return c

批量复制元素一次(熟练地)使用哨兵…
灰胡子

1

您可以使用2个线程来填充结果数组,一个从前面开始,一个从后面开始。

在数字的情况下,这可以工作而无需任何同步,例如,如果每个线程都插入一半的值。


0
//How to merge two sorted arrays into a sorted array without duplicates?
//simple C Coding
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

main()
{
    int InputArray1[] ={1,4,5,7,8,9,12,13,14,17,40};
    int InputArray2[] ={4,5,11,14,15,17,18,19,112,122,122,122,122};
    int n=10;
    int OutputArray[30];
    int i=0,j=0,k=0;
    //k=OutputArray
    while(i<11 && j<13)
    {
        if(InputArray1[i]<InputArray2[j])
        {
            if (k == 0 || InputArray1[i]!= OutputArray[k-1])
            {
                OutputArray[k++] = InputArray1[i];
            }
            i=i+1;
        }
        else if(InputArray1[i]>InputArray2[j])
        {
            if (k == 0 || InputArray2[j]!= OutputArray[k-1])
            {
                OutputArray[k++] = InputArray2[j];
            }
            j=j+1;
        }
        else
        {
            if (k == 0 || InputArray1[i]!= OutputArray[k-1])
            {
                OutputArray[k++] = InputArray1[i];
            }
            i=i+1;
            j=j+1;
        }
    };
    while(i<11)
    {
        if(InputArray1[i]!= OutputArray[k-1])
            OutputArray[k++] = InputArray1[i++];
        else
            i++;
    }
    while(j<13)
    {
        if(InputArray2[j]!= OutputArray[k-1])
            OutputArray[k++] = InputArray2[j++];
        else
            j++;
    }
    for(i=0; i<k; i++)
    {
        printf("sorted data:%d\n",OutputArray[i]);
    };
}

0
public static int[] merge(int[] listA, int[] listB) {
        int[] mergedList = new int[ listA.length + listB.length];
        int i = 0; // Counter for listA
        int j = 0; // Counter for listB
        int k = 0; // Counter for mergedList
        while (true) {
            if (i >= listA.length && j >= listB.length) {
                break;
            }
            if (i < listA.length && j < listB.length) { // If both counters are valid.
                if (listA[i] <= listB[j]) {
                    mergedList[k] = listA[i];
                    k++;
                    i++;
                } else {
                    mergedList[k] = listB[j];
                    k++;
                    j++;
                }
            } else if (i < listA.length && j >= listB.length) { // If only A's counter is valid.
                mergedList[k] = listA[i];
                k++;
                i++;
            } else if (i <= listA.length && j < listB.length) { // If only B's counter is valid
                mergedList[k] = listB[j];
                k++;
                j++;
            }
        }
        return mergedList;
    }

0
var arrCombo = function(arr1, arr2){
  return arr1.concat(arr2).sort(function(x, y) {
    return x - y;
  });
};

2
该答案不适用于Java编程语言,尽管它对于javascript是一个很好的答案。
gknicker 2015年

这是工作面试的一部分。在这些情况下,您实际上并不希望编写上述的“普通”代码。他们正在寻找“高效”的代码,并在演示中了解所涉及的算法。
d11wtq 2015年

0

我最喜欢的编程语言是JavaScript

function mergeSortedArrays(a, b){
    var result = [];

    var sI = 0;
    var lI = 0;
    var smallArr;
    var largeArr;
    var temp;

    if(typeof b[0] === 'undefined' || a[0]<b[0]){
        smallArr = a;
        largeArr = b;
    } else{
        smallArr = b;
        largeArr = a;
    }

    while(typeof smallArr[sI] !== 'undefined'){
        result.push(smallArr[sI]);
        sI++;

        if(smallArr[sI]>largeArr[lI] || typeof smallArr[sI] === 'undefined'){
            temp = smallArr;
            smallArr = largeArr;
            largeArr = temp;
            temp = sI;
            sI = lI;
            lI = temp;
        }
    }
    return result;
}

0

也许使用System.arraycopy

public static byte[] merge(byte[] first, byte[] second){
    int len = first.length + second.length;
    byte[] full = new byte[len];
    System.arraycopy(first, 0, full, 0, first.length);
    System.arraycopy(second, 0, full, first.length, second.length);
    return full;
}

3
您只是合并它们;结果数组本身未排序,这是必需的。
Sanjeev Dhiman

0
public static void main(String[] args) {
    int[] arr1 = {2,4,6,8,10,999};
    int[] arr2 = {1,3,5,9,100,1001};

    int[] arr3 = new int[arr1.length + arr2.length];

    int temp = 0;

    for (int i = 0; i < (arr3.length); i++) {
        if(temp == arr2.length){
            arr3[i] = arr1[i-temp];
        }
        else if (((i-temp)<(arr1.length)) && (arr1[i-temp] < arr2[temp])){
                arr3[i] = arr1[i-temp];
        }
        else{
            arr3[i] = arr2[temp];
            temp++;
        }
    }

    for (int i : arr3) {
        System.out.print(i + ", ");
    }
}

输出为:

1、2、3、4、5、6、8、9、10、100、999、1001,


将索引命名为arr2not ind2,but 感到困惑temp
灰胡子'18

0

您可以使用三元运算符使代码更紧凑

public static int[] mergeArrays(int[] a1, int[] a2) {
    int[] res = new int[a1.length + a2.length];
    int i = 0, j = 0;

    while (i < a1.length && j < a2.length) {
        res[i + j] = a1[i] < a2[j] ? a1[i++] : a2[j++];
    }

    while (i < a1.length) {
        res[i + j] = a1[i++];
    }

    while (j < a2.length) {
        res[i + j] = a2[j++];
    }

    return res;
}

0
public static int[] mergeSorted(int[] left, int[] right) {
    System.out.println("merging " + Arrays.toString(left) + " and " + Arrays.toString(right));
    int[] merged = new int[left.length + right.length];
    int nextIndexLeft = 0;
    int nextIndexRight = 0;
    for (int i = 0; i < merged.length; i++) {
        if (nextIndexLeft >= left.length) {
            System.arraycopy(right, nextIndexRight, merged, i, right.length - nextIndexRight);
            break;
        }
        if (nextIndexRight >= right.length) {
            System.arraycopy(left, nextIndexLeft, merged, i, left.length - nextIndexLeft);
            break;
        }
        if (left[nextIndexLeft] <= right[nextIndexRight]) {
            merged[i] = left[nextIndexLeft];
            nextIndexLeft++;
            continue;
        }
        if (left[nextIndexLeft] > right[nextIndexRight]) {
            merged[i] = right[nextIndexRight];
            nextIndexRight++;
            continue;
        }
    }
    System.out.println("merged : " + Arrays.toString(merged));
    return merged;
}

与原始解决方案略有不同


0

要以O(m + n)时间复杂度对两个排序的数组进行嫁接,请使用以下方法仅使用一个循环。m和n是第一数组和第二数组的长度。

public class MargeSortedArray {
    public static void main(String[] args) {
        int[] array = new int[]{1,3,4,7};
        int[] array2 = new int[]{2,5,6,8,12,45};
        int[] newarry = margeToSortedArray(array, array2);
        //newarray is marged array
    }

    // marge two sorted array with o(a+n) time complexity
    public static int[] margeToSortedArray(int[] array, int[] array2) {
        int newarrlen = array.length+array2.length;
        int[] newarr = new int[newarrlen];

        int pos1=0,pos2=0;
        int len1=array.length, len2=array2.length;

        for(int i =0;i<newarrlen;i++) {     
            if(pos1>=len1) {
                newarr[i]=array2[pos2];
                pos2++;
                continue;
            }
            if(pos2>=len2) {
                newarr[i]=array[pos1];
                pos1++;
                continue;
            }

            if(array[pos1]>array2[pos2]) {
                newarr[i]=array2[pos2];
                pos2++;
            } else {
                newarr[i]=array[pos1];
                pos1++;
            }   
        }

        return newarr;
    }

}

0
var arr1 = [2,10,20,30,100];
var arr2 = [2,4,5,6,7,8,9];
var j = 0;
var i =0;
var newArray = [];

for(var x=0;x< (arr1.length + arr2.length);x++){
    if(arr1[i] >= arr2[j]){                //check if element arr2 is equal and less than arr1 element
        newArray.push(arr2[j]);
      j++;
    }else if(arr1[i] < arr2[j]){            //check if element arr1 index value  is less than arr2 element
        newArray.push(arr1[i]);
        i++;
    }
    else if(i == arr1.length || j < arr2.length){    // add remaining arr2 element
        newArray.push(arr2[j]);
        j++
    }else{                                                   // add remaining arr1 element
        newArray.push(arr1[i]); 
        i++
    }

}

console.log(newArray);

-1

由于问题不采用任何特定语言。这是Python中的解决方案。假设数组已经排序。

方法1-使用numpy数组:import numpy

arr1 = numpy.asarray([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 11, 14, 15, 55])
arr2 = numpy.asarray([11, 32, 43, 45, 66, 76, 88])

array = numpy.concatenate((arr1,arr2), axis=0)
array.sort()

方法2-使用列表,假设列表已排序。

list_new = list1.extend(list2)
list_new.sort()

Since the question doesn't assume any specific language从2011/5/11/19:43起,它被标记为java
灰胡子

您的解决方案没有利用事实列表已经排序的优势,并且其运行时不是O(n),因为充其量.sort()O(n log n)最好的
dark_ruby

-1

这是我的java实施,删除重复项。

public static int[] mergesort(int[] a, int[] b) {
    int[] c = new int[a.length + b.length];
    int i = 0, j = 0, k = 0, duplicateCount = 0;

    while (i < a.length || j < b.length) {
        if (i < a.length && j < b.length) {
            if (a[i] == b[j]) {
                c[k] = a[i];
                i++;j++;duplicateCount++;
            } else {
                c[k] = a[i] < b[j] ? a[i++] : b[j++];
            }
        } else if (i < a.length) {
            c[k] = a[i++];
        } else if (j < a.length) {
            c[k] = b[j++];
        }
        k++;
    }

    return Arrays.copyOf(c, c.length - duplicateCount);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.