仅从数组中排序奇数或偶数

时间:2017-03-22 14:29:00

标签: c arrays sorting

我需要对数组中的奇数或偶数进行排序,而其余部分保持不变。由于这是内存管理课程的一部分,我强烈建议不要复制任何数据,因此我没有采用明显的解决方案。

我想通过跳过比较的“坏”第一或第二个参数来使用简单的冒泡排序功能。我将仅发布该功能,因为其余部分无关紧要。

//these are passed as sort_type_remainder
#define REMAINDER_EVEN 0
#define REMAINDER_ODD 1

void sort_integers(int *integer_list, int num_integers, int sort_type_remainder)
{
    int i, j, aux, offset = 1;
    for(i = 0; i < num_integers - 1; i++)
    {
        offset = 1;
        for(j = 0; j + offset < num_integers - i; j++)
        {
            if(abs(integer_list[j] % 2) != sort_type_remainder) //first element to be compared is of wrong type, skip
            {
                j++;
            }
            else
            {
                //first element is of good type, but second element is not, increase offset and reloop first element
                if(abs(integer_list[j + offset] % 2) != sort_type_remainder)
                {
                    j--;
                    offset++;
                }
                else //both elements are of good type, bubble sort them
                {
                    if(integer_list[j] > integer_list[j + offset])
                    {
                        aux = integer_list[j + offset];
                        integer_list[j + offset] = integer_list[j];
                        integer_list[j] = aux;
                    }
                    offset = 1;
                }
            }
        }
    }
}

这种工作但有些输入没有正确处理,我无法弄清楚原因。我尝试减少输入大小以获得更简单的方法来重现这个,但是一旦我这样做,它就会开始正常工作。

这是输入/输出,我删除了偶数,因为它们保持在它们的位置,这使得错误更容易被注意到。

odd
20
13 5 -3 4 2 -7 23 -33 1 6 -8 7 10 -51 9 -5 12 92 69 55

output

我们将非常感谢任何帮助或建议,最好只提供解释而不只是解决方案。

编辑::完整程序就在这里,不要混淆问题http://pastebin.com/vZDcmppV

2 个答案:

答案 0 :(得分:2)

想要什么

给出描述和输入数据:

  13   5  -3   4   2  -7  23 -33   1   6  -8   7  10 -51   9  -5  12  92  69  55

我认为将奇数按升序排序以保持偶数不变的要求要求输出:

 -51 -33  -7   4   2  -5  -3   1   5   6  -8   7  10   9  13  23  12  92  55  69

并且要将偶数按升序排序而使奇数保持不变需要输出:

  13   5  -3  -8   2  -7  23 -33   1   4   6   7  10 -51   9  -5  12  92  69  55

算法背后的概念

一种方法是创建要排序位置的索引数组:

int O = 13; // for sorting odd:
int opos[] = { 0,  1,  2,  5,  6,  7,  8, 11, 13, 14, 15, 18, 19 };

int E =  7; // for sorting even:
int epos[] = {  3,  4,  9, 10, 12, 16, 17 };

然后,通常先扫描for (i = 0; i < N; i++)然后引用A[i]的任何排序算法都将扫描for (e = 0; e < E; e++)并引用A[epos[e]]

因此,我们从一个简单的冒泡排序开始,该排序对具有A个元素的int类型的完整数组N进行排序:

void bsort_1(int *A, int N)
{
     for (int i = 0; i < N - 1; i++)
     {
         for (int j = 0; j < N - 1 - i; j++)
         {
              if (A[j+1] < A[j])
              {
                  int t = A[j+1];
                  A[j+1] = A[j];
                  A[j] = t;
              }
         }
    }
}

使用O(N)辅助存储器

我们可以对其进行修改以仅对具有指定奇偶校验(0表示偶数,1表示奇数)的元素进行排序:

void bsort_4(int *A, int N, int parity)
{
    assert(parity == 0 || parity == 1);
    assert(N < 1024 * 1024);
    int posn[N];
    int count = 0;
    for (int i = 0; i < N; i++)
    {
        if ((A[i] & 1) == parity)
            posn[count++] = i;
    }
    if (count < 2)
        return;
    for (int i = 0; i < count - 1; i++)
    {
        for (int j = 0; j < count - 1 - i; j++)
        {
            if (A[posn[j + 1]] < A[posn[j]])
            {
                int t = A[posn[j + 1]];
                A[posn[j + 1]] = A[posn[j]];
                A[posn[j]] = t;
            }
        }
    }
}

这将建立与数组中奇数或偶数条目相对应的索引,然后仅对数组中的那些元素进行排序。

测试代码和结果

需要一些测试代码来合理地确定它正在执行应做的事情。

#include <assert.h>
#include <stdio.h>

static void bsort_4(int *A, int N, int parity)
{
    assert(parity == 0 || parity == 1);
    assert(N < 1024 * 1024);
    int posn[N];
    int count = 0;
    for (int i = 0; i < N; i++)
    {
        if ((A[i] & 1) == parity)
            posn[count++] = i;
    }
    if (count < 2)
        return;
    for (int i = 0; i < count - 1; i++)
    {
        for (int j = 0; j < count - 1 - i; j++)
        {
            if (A[posn[j + 1]] < A[posn[j]])
            {
                int t = A[posn[j + 1]];
                A[posn[j + 1]] = A[posn[j]];
                A[posn[j]] = t;
            }
        }
    }
}

static void dump_array(const char *tag, const int *a, int n)
{
    printf("%-8s", tag);
    for (int i = 0; i < n; i++)
        printf(" %3d", a[i]);
    putchar('\n');
}

static void test_sorting(const int *data, int size, int parity)
{
    int array[size];
    for (int i = 0; i < size; i++)
        array[i] = data[i];
    dump_array("Before:", array, size);
    bsort_4(array, size, parity);
    dump_array("After:", array, size);
}

int main(void)
{
    const int array[] =
    {
        13,   5,  -3,   4,   2,  -7,  23, -33,   1,   6,
        -8,   7,  10, -51,   9,  -5,  12,  92,  69,  55,
    };
    enum { A_SIZE = sizeof(array) / sizeof(array[0]) };

    printf("Sort even numbers:\n");
    test_sorting(array, A_SIZE, 0);
    printf("Sort odd  numbers:\n");
    test_sorting(array, A_SIZE, 1);

    return 0;
}

输出:

Sort even numbers:
Before:   13   5  -3   4   2  -7  23 -33   1   6  -8   7  10 -51   9  -5  12  92  69  55
After:    13   5  -3  -8   2  -7  23 -33   1   4   6   7  10 -51   9  -5  12  92  69  55
Sort odd  numbers:
Before:   13   5  -3   4   2  -7  23 -33   1   6  -8   7  10 -51   9  -5  12  92  69  55
After:   -51 -33  -7   4   2  -5  -3   1   5   6  -8   7  10   9  13  23  12  92  55  69

您必须相信,在运行我用来获得最终结果的任何程序之前,已创建了必需的输出。

此代码可以适应其他排序策略-插入,选择,shell,合并,快速。在顶层操作中需要进行扫描来建立posn数组(但对于诸如归并排序和快速排序之类的递归调用,应避免扫描),然后其余代码使用额外的间接。

避免O(N)辅助存储

如果由于某种原因而无法使用多余的数组,那么您必须以一种更加扭曲的方式处理事情,并且由于必须计算{{1}动态数组,而不是预先计算一次。排序中的比较总是在相邻位置之间进行。没有posn数组,代码仍会建立奇数或偶数的计数,但是仍有代码可以逐步遍历数据数组以找到具有正确奇偶校验的下一个值:

posn

我对#include <assert.h> #include <stdio.h> static void bsort_4(int *A, int N, int parity) { assert(parity == 0 || parity == 1); assert(N < 1024 * 1024); int count = 0; for (int i = 0; i < N; i++) { if ((A[i] & 1) == parity) count++; } if (count < 2) return; for (int i = 0; i < count - 1; i++) { int i0 = 0; while ((A[i0] & 1) != parity) i0++; for (int i1 = 0; i1 < i; i1++) { while ((A[i0] & 1) != parity) i0++; } int j0 = i0; for (int j = 0; j < count - 1 - i; j++) { int j1 = j0 + 1; while ((A[j1] & 1) != parity) j1++; /*printf("P = %d; j0 = %2d; A[j0] = %3d; j1 = %2d; A[j1] = %3d\n",*/ /* parity, j0, A[j0], j1, A[j1]);*/ if (A[j1] < A[j0]) { int t = A[j1]; A[j1] = A[j0]; A[j0] = t; } j0 = j1; } } } static void dump_array(const char *tag, const int *a, int n) { printf("%-8s", tag); for (int i = 0; i < n; i++) printf(" %3d", a[i]); putchar('\n'); } static void test_sorting(const int *data, int size, int parity) { int array[size]; for (int i = 0; i < size; i++) array[i] = data[i]; dump_array("Before:", array, size); bsort_4(array, size, parity); dump_array("After:", array, size); } int main(void) { const int array[] = { 13, 5, -3, 4, 2, -7, 23, -33, 1, 6, -8, 7, 10, -51, 9, -5, 12, 92, 69, 55, }; enum { A_SIZE = sizeof(array) / sizeof(array[0]) }; printf("Sort even numbers:\n"); test_sorting(array, A_SIZE, 0); printf("Sort odd numbers:\n"); test_sorting(array, A_SIZE, 1); return 0; } 中的变量命名不满意,但是我没有立即使用更好的名称。

输出:

bsort_5()

请注意,这取决于以下事实:显示的冒泡排序仅比较相同奇偶校验的相邻条目。对于像shell,merge,快速排序这样可以在任意位置工作的排序,这是不合适的-查找正确索引的循环会非常昂贵。几乎可以肯定,使用冒泡排序(或选择排序或插入排序)会更好。

GitHub

此代码在我的GitHub上的SOQ(堆栈溢出问题)存储库中以src/so-4295-4541子文件夹中的文件Sort even numbers: Before: 13 5 -3 4 2 -7 23 -33 1 6 -8 7 10 -51 9 -5 12 92 69 55 After: 13 5 -3 -8 2 -7 23 -33 1 4 6 7 10 -51 9 -5 12 92 69 55 Sort odd numbers: Before: 13 5 -3 4 2 -7 23 -33 1 6 -8 7 10 -51 9 -5 12 92 69 55 After: -51 -33 -7 4 2 -5 -3 1 5 6 -8 7 10 9 13 23 12 92 55 69 bsort1.cbsort4.c的形式提供,目录。

答案 1 :(得分:0)

如果你需要从数组中对奇数或偶数进行排序,这是我的方法:

我首先会从起始数组中选择所有奇数或偶数数字取决于您想要做什么,用指标替换所有内容(1或2取决于您是否要对赔率或平均值进行排序)。

然后自己对数组进行排序(如果你想使用另一种算法而不是冒泡排序,there's Big-o cheat sheet,非常有用)。

然后你只需要扫描你的第一个数组,每个数据取决于它们的位置。

简而言之:

您希望将数组1中的每个奇数(或偶数)数放入数组2中,并用指示符替换它们(在扫描数组1之后您可能会识别的任何数字)。

您想要对数组2进行排序。

然后你想用数组2中的每个元素替换每个指标。