如何对两个数组进行排序而不更改原始数组或使用新数组?

时间:2015-11-09 18:43:46

标签: c arrays sorting malloc

为简单起见,这是我想要做的一个例子:

假设我们有两个数组,A和B;

A = [5,5,5,9,1]

B = [9,5,1,4,4]

在程序中,有数百个这样的小阵列。我试图根据它们的最大值对它们进行排序。所以在这种情况下,它们都有9个,所以转到下一个最大的数字。好的,他们都有五个,下一个号码。 A数组有5,B数组有4,所以A数组首先排序。这里的问题是,我不知道如何对这些人进行排序,而不需要使用新数组来对这些值进行排序。

这是我得到的:

int compare(const void *x, const void *y)
{
struct Data *s1, *s2;
s1 = (struct Data *)x;
s2 = (struct Data *)y;

int maxv=-1000;
int maxv2=-1000;
int maxvn=1000;
int maxv2n=1000;


int j=0;
int k=0;

for (k=0; k < 5;k++)
{
max = -1000;
max2= -1000;
    for (j=0; j<5;j++)
    {
        if (s1->margin[j]>max && s1->margin[j]<maxvn)
            maxv=s1->margin[j];
        if (s2->margin[j]>max2 && s2->margin[j]<maxv2n)
            maxv2=s2->margin[j];
    }
if (max2<max)
    return 1;
if (max<max2)
    return -1;

maxvn=maxv;
maxv2n=maxv2;
}
return 0;
}

所以,理论上,我希望数组A在数组B之前列出。不幸的是,数组B在数组A之前被列出,因为(我认为)这个参数中的第二个条件:

if (s1->margin[j]>max && s1->margin[j]<maxvn)

由于第二个参数,数组A中的另外两个5被忽略。

现在,我不知道如何实际解决这个问题,除非我只是malloc一些数组然后冒泡它们。这虽然减慢了我的程序速度。这里的任何人都可以想到我可以实现的修复方法,这会阻止我使用任何类型的malloc并且不会忽略重复出现的数字吗?

感谢。

3 个答案:

答案 0 :(得分:3)

至少有两种可能的方法。更通用的是在堆栈上声明工作数组,将原始数据复制到这些工作数组中,对它们进行排序,然后比较它们。这避免了malloc()的费用和复杂性,并使您获得简单的(-ish)元素比较。它仍然使用辅助空间。例如:

int compare(const void *x, const void *y)
{
    struct Data *s1 = (struct Data *) x;
    struct Data *s2 = (struct Data *) y;
    int temp1[5];  /* or replace `int` with the correct type */
    int temp2[5];  /* or replace `int` with the correct type */
    int i;

    memcpy(temp1, s1->margin, sizeof(temp1));
    memcpy(temp2, s2->margin, sizeof(temp2));

    /* ... sort temp1 and temp2 however you want ... */

    /* compare */
    for (i = 0; i < 5; i += 1) {
        if (temp1[i] < temp2[i]) return -1;
        if (temp1[i] > temp2[i]) return  1;
    }

    return 0;
}

或者,如果数组元素的边界足够小,那么您可以为每个元素计算一个键值并进行比较。如果数组元素都在020之间,则可以使用此特定的元素:

int compare(const void *x, const void *y)
{
    struct Data *s1 = (struct Data *) x;
    struct Data *s2 = (struct Data *) y;
    uint64_t key1 = 0;
    uint64_t key2 = 0;
    int i;

    for (i = 0; i < 5; i += 1) {
        key1 += 1 << (s1->margin[i] * 3);
        key2 += 1 << (s2->margin[i] * 3);
    }

    if (key1 < key2) return -1;
    if (key1 > key2) return  1;
    return 0;
}

将键视为3位元素的数组,并在每个元素中累积元素索引在相应原始数组中出现的次数。生成的64位值可以通过普通的整数比较运算符进行比较。

如果原始数组的元素在09之间有界,那么32位密钥就足以用于第二种方法。

已更新以添加:

另请注意,如果要对这些阵列进行大量排序,那么最大限度地降低比较成本对您有利。计算密钥方法的优点是,您只需为每个数组计算一次密钥,将其存储在某处,然后对其余的数组进行非常快速的比较。在各个比较中的任何类型的临时数组或多循环方法都会对你的表现非常粗糙(甚至每次重新计算密钥,虽然不是很糟糕,但也不是很好)。

答案 1 :(得分:0)

您可以在每个数组中分配一个额外元素,并在该元素中存储数组中包含的最大值。然后,每当更新阵列时,执行更新的代码可以在需要时保留最大值槽。你总是在插槽0中使用数组的最高值(例如,如果数组总是包含5个元素,则为插槽5)。

这是典型的速度与尺寸之间的权衡。每个阵列的一个额外元素的RAM占用空间加上保持最大元素更新的时间与排序阵列的复杂性或串行扫描它们的复杂性。

答案 2 :(得分:-1)

首先,对所有小数组进行排序(使用qsort(),或者如果它们非常小,您自己的气泡或插入排序可能会更快),以使比较更容易。这将使您的比较功能更小。然后简化compare()函数(现在它只需要同时传递两个数组),并在数组数组上使用qsort()传递新的compare()函数。