给出一个整数数组,其中第一和第二半被排序。编写一个函数来合并这两个部分来创建一个单独的排序数组(不要使用额外的空间)。 一种方法是 例如: // 1,3,6,8,-5,-2,3,8
int l = 0;
int u = size;
int mid = (l+u)/2;
int i;
for (i = 0; i < mid; i++) {
for (j = mid; j < size; j++) {
if (a[i] >= a[j]) {
temp = a[j];
for (i = mid-1; i >= 0; i--)
a[i+1] = a[i];
a[0] = temp;
}
}
}
但我认为必须有一些O(n)算法......
答案 0 :(得分:3)
确实存在用于就地合并的O(n)算法。但它们通常很复杂。对于一些想法,请参阅Huang, Langston (PDF)或Katajainen, Pasanen, Teuhola (PostScript)等论文。这些实际上是基于允许哪种额外内存的精确术语来定义的,而不会通过使用递归堆栈等来作弊。
答案 1 :(得分:2)
你可以通过走一次数组,从0到它的最后一个元素来做到这一点。你只需要考虑比较或交换“当前”元素所需的内容,它就变得非常容易了。
你必须保留一些额外的变量来跟踪当前元素,以及你需要比较它的“其他”元素。
此外,您可能希望查看主要的C代码格式样式。没有一种风格让每个人都百分百满意,但有很多风格让每个人都不高兴。
----编辑----
好吧,这更像是一个“脑筋急转弯”问题而非严重的计算机科学问题。问题在于“额外内存”的定义非常糟糕,因此如果您只记得编程语言中允许递归,那么有很多方法可以实现结果,that a recursive call requires extra stack(没有人会去考虑编程语言实现所需的内存分配。
基本上,这样的问题是为了看看你是否看到问题并看到递归解决方案。
#include <stdio.h>
void sort(int index, int start1, int end1, int start2, int end2, int* array) {
if (index >= end2) {
return;
}
int lower;
if (array[start1] <= array[start2]) {
lower = array[start1];
sort(index+1, start1+1, end1, start2, end2, array);
} else {
lower = array[start2];
sort(index+1, start1, end1, start2+1, end2, array);
}
array[index]=lower;
}
int main(int argc, char** argv) {
int a[] = {1,3,6,8,-5,-2,3,8};
sort(0, 0, 3, 4, 7, a);
int i;
for (i = 0; i <= 7; i++) {
printf("%d, ", a[i]);
}
printf("\n");
return 0;
}
这是骗子吗?你决定。但是,排序是就地完成的,缓存的数字整齐地隐藏在调用堆栈的本地空间中,在那里你无法真正分配/解除分配它们。
可以进行额外的优化,但它们是核心思想的改进:使用递归和调用堆栈来缓存信息。
答案 2 :(得分:1)
我发现,假设您不能使用任何辅助内存,我发现的最佳答案是对数组进行导航,这是theta(n log n)
,比您当前的插入排序方案稍快一些。
答案 3 :(得分:0)
我再次看到这个,这是你的O(n-1)和记忆(n + 1):
/**
* Created by deian on 2016-12-22.
*/
public class Merge {
public static void swap(int[] a, int i1, int i2) {
int t = a[i1];
a[i1] = a[i2];
a[i2] = t;
}
public static void merge(int[] a) {
int i1 = 0;
int i2 = a.length / 2;
System.out.printf(" %s, i(%d,%d) \n", Arrays.toString(a), i1, i2 );
for (int di = 0; di < a.length-1; di++) {
int ni;
int oi1=i1;
int oi2=i2;
// i1 and i2 - always point to the smallest known numbers
if (a[i1] > a[i2]) {
ni = i2;
i2++;
if (i2>=a.length) {
i2--;
}
} else {
ni = i1;
i1++;
if (i1 >= i2) {
i1 = di;
}
}
if (di == i1) {
i1 = ni;
}
swap(a, di, ni);
System.out.printf("#%d: %s, i(%d,%d)s(%d>%d)i(%d,%d) \n", di+1, Arrays.toString(a), oi1, oi2,ni, di, i1,i2);
}
System.out.printf(" %s\n", Arrays.toString(a));
}
public static void main(String[] args) {
// int[] a = new int[]{1, 3, 6, 8, -5, -2, 3, 8};
// int[] a = new int[]{1, 3, 6, 8, -5, 2, 3, 8};
int[] a = new int[]{1, 5, 6, 8, -5, 2, 3, 4};
merge(a);
}
}
答案 4 :(得分:0)
以下任何一项
void Merge(int array[N])
{
for(int i=N/2;i<N;i++){
int j=i;
while(array[j]<array[j-1]&& j>=1){
int temp=array[j];
array[j]=array[j-1];
array[j-1]=temp;
j--;
}
}
}
void Merge2(int array[N])
{
for(int i=N/2;i<N;i++){
int key=array[i];
int j=i-1;
while(array[j]>key&& j>=0){
array[j+1]=array[j];
j--;
}
array[j+1]=key;
}
}