2-х цветное сглаживание - PullRequest
4 голосов
/ 10 марта 2011

У меня есть массив, содержащий смесь 0 с и 1 с. Я хочу переставить содержимое массива так, чтобы как можно больше четных позиций в массиве содержало 0, а нечетные позиции содержали 1, насколько это возможно, при условии ограничения числа 0 s и 1 s. без изменений. Это означает, что если число 0 s превышает количество 1 s или наоборот, то в конце переставленного массива будет блок, состоящий из all- 0 s или all- 1 s. Как я могу сделать это за один проход, модифицируя массив на месте?

Например:

Input:  {0,1,1,0,1,0,1,0,1,1,1,0,0,1,0,1,1}
Output: {0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1}

Ответы [ 9 ]

4 голосов
/ 10 марта 2011

Для этого вы можете просто использовать стандартный алгоритм двухцветной сортировки; просто отредактируйте ссылки на массив, чтобы сопоставить доступы к первой половине массива с четными элементами в вашем фактическом массиве и доступ ко второй половине массива с нечетными элементами в вашем реальном массиве (в обратном направлении). По существу, a[i] становится (при условии, что size является четным):

a[i < size/2 ? i * 2 : (size - i) * 2 - 1]
2 голосов
/ 12 декабря 2012
int a[10] = {1, 1, 0, 1, 1, 0, 1, 1, 1, 0};
int i;
int count_0 = 0;
int count_1 = 0;
for(i = 0; i < 10; i++)
{
  if(a[i] == 0)
  {
    if(count_1 > 0)
    {
      if(i % 2 == 0)
      {
        a[i-2*count_1+1] = 0;
        a[i] = 1;
        count_1--;
      }
      else
      {
        a[i-2*count_1] = 0;
        a[i] = 1;
      }
    }
    else
    {
      if(i % 2 == 0)
      count_0++;
    }
  }
  else
  {
    if(count_0 > 0)
    {
      if(i % 2 != 0)
      {
        a[i-2*count_0+1] = 1;
        a[i] = 0;
        count_0--;
      }
      else
      {
        a[i-2*count_0] = 1;
        a[i] = 0;
      }
    }
    else
    {
      if(i % 2 != 0)
      count_1++;
    }
  }
}
2 голосов
/ 11 марта 2011

Цикл по массиву, поддерживая инварианты для 3 переменных и массива:

  • все, что было перед сортировкой pos.
  • color - цвет элементаэто должно быть помещено в pos.
  • все между pos и next имеет одинаковый цвет.
  • массив является перестановкой самого себя.

Во всяком случае, это похоже на работу.

def odd_even_sort(xs):
    color = 0
    pos = 0
    next = pos + 1
    while next < len(xs):
        if xs[pos] == color:
            pos += 1
            if pos >= next:
                next = pos + 1
            color = not color
        elif xs[next] == color:
            xs[pos], xs[next] = xs[next], xs[pos]
            next += 1
            pos += 1
            color = not color
        else:
            next += 1

xs = [0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1]
odd_even_sort(xs)
print xs
2 голосов
/ 10 марта 2011

Я не думаю, что это можно сделать за 1 проход, если только «оставить их там, где они есть» не означает, что «неважно, где они окажутся».

Вот моя попытка с двумя проходами:)

void zeroone(int *arr, size_t n) {
  int *ptr = arr;
  size_t nn = n;
  int s = 0;

  /* if the array has an odd number of elements
  ** the number of 0's is different then the number of 1's */    
  if (n % 2) return;

  /* 1st pass */
  while (nn--) s += *ptr++;

  /* if there are as many 0's as 1's */
  if (s+s == n) {
    /* 2nd pass */
    for (nn = 0; nn < n; nn += 2) {
      arr[nn] = 0;
      arr[nn + 1] = 1;
    }
  }
}
1 голос
/ 04 апреля 2012

Это можно сделать за один проход.

Вот еще одно решение, которое использует один проход. Идея состоит в том, чтобы сохранить два индекса pos_0 и pos_1, которые содержат место, где следующие 0 или 1 должны быть размещены в массиве. i будет использоваться для перемещения по массиву.

//
//array a[] and length are members of the class AlternateZeroAndOne
//
void AlternateZeroAndOne::sortArray()
{
    int pos_0 = 0;
    int pos_1 = 1;

    for (int i=0; i<length; ++i)
    {
        //
        // We have been waiting for a zero to be placed at the correct location.
        //
        if (pos_0 < pos_1)
        {
            if (a[i] == 0)
            {
                swap(pos_0, i);
                pos_0+=2;

                //
                // If we had a 1 already at the right place, increment pos_1.
                //
                if (a[pos_1] == 1)
                    pos_1+=2;
            }
        }

        //
        // We have been waiting for a one to be placed at the correct location.
        //
        else
        {
            if (a[i] == 1)
            {
                swap(pos_1, i);
                pos_1 += 2;

                //
                // If we had a 0 already at the right place, increment pos_0.
                //
                if (a[pos_0] == 0)
                    pos_0+=2;
            }
        }
    }
}
1 голос
/ 03 августа 2011
#include<iostream>

using namespace std;

//////////////////////////////////////////

int a[]={1,1,0,1,0,1,1,1,0,1,0,1,0,0,0,0,1,1,1,1,0,0} ;


int main()
{

    int zero = 0, one = 1;
    int n = sizeof(a)/sizeof(*a);
    int i = 0;

    while ( zero < n && one < n)
    {
        if(a[zero] != 0 && a[one] != 1)
        {
            swap(a[zero],a[one]);
        }

        if(a[zero] == 0)
        {
            zero=zero+2;
        }
        if(a[one] == 1)
        {
            one=one+2;
        }
    }
} 
1 голос
/ 11 марта 2011

Это сделает это. Результат отличается от предложенного результата, но равен приведенным правилам (текст задачи не включает слово «сортировка», только то, что в конце вы должны переместить все 0, которые вы можете сделать даже позиции и 1 вы можете в нечетных позициях. Вам не нужно их "сжимать"). Это немного сложнее сделать это "сжатие".

static void Main(string[] args)
{
    var input = new[] { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1 };

    var lastEvenToMove = -1;
    var lastOddToMove = -1;

    for (int i = 0; i < input.Length; i++)
    {
        bool needEven = i % 2 == 0;
        bool isEven = input[i] == 0;

        if (needEven == isEven)
        {
            continue;
        }

        if (needEven)
        {
            if (lastEvenToMove != -1)
            {
                var old = input[lastEvenToMove];
                input[lastEvenToMove] = 1;
                input[i] = 0;
                lastEvenToMove = old;
            }
            else
            {
                input[i] = lastOddToMove;
                lastOddToMove = i;
            }
        }
        else
        {
            if (lastOddToMove != -1)
            {
                var old = input[lastOddToMove];
                input[lastOddToMove] = 0;
                input[i] = 1;
                lastOddToMove = old;
            }
            else
            {
                input[i] = lastEvenToMove;
                lastEvenToMove = i;
            }
        }
    }

    while (lastEvenToMove != -1)
    {
        var old = input[lastEvenToMove];
        input[lastEvenToMove] = 0;
        lastEvenToMove = old;
    }

    while (lastOddToMove != -1)
    {
        var old = input[lastOddToMove];
        input[lastOddToMove] = 1;
        lastOddToMove = old;
    }

    Console.WriteLine(@"{{{0}}}", String.Join(", ", input.Select(p => p.ToString())));
}

Я храню стопку шансов и стопку четных элементов, которые нужно переместить, и использую их, когда мне нужно нечетное / четное число. Два стека хранятся во входном массиве, поэтому нет дополнительного пространства (кроме двух «головок» двух стеков, которые представляют собой два дополнительных целых числа). Я думаю, что наихудший случай - O(1.5n) для времени (например, все элементы 1, половина элементов «помещена» в стек и затем нуждается в сбросе, потому что не было пустого места), и O(1) для космоса.

Выход:

{0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1}
0 голосов
/ 28 июня 2015
#include<stdio.h>
void swap(int *p,int *q)
{
  int temp=*p;
  *p=*q;
  *q=temp;
}

int main()
{
  int a[]={0,1,1,0,1,0,1,0,1,1,1,0,0,1,0,1,1};
  int z=0,o=1,i;
  while(z<17&&o<17)
  {
    if(a[z]==1&&a[o]==0)
        swap(&a[z],&a[o]);
    if(a[z]==0)
        z+=2;
    if(a[o]==1)
        o+=2;
  }
  if(z<17&&a[z]==1)
  {
    while(z<15)
    {
        swap(&a[z],&a[z+2]);
        z+=2;
    }
  }
  if(o<17&&a[o]==0)
  {
    while(o<15)
    {
        swap(&a[o],&a[o+2]);
        o+=2;
    }
  }
  for(i=0;i<17;i++)
    printf("%d ",a[i]);
}
0 голосов
/ 11 марта 2011

, так как это только 1 и 0, вы можете просто посчитать разницу их количества, и сортировка будет очень простой:

int size = arr.length();
int diff = 0, i;
for(i = 0; i < size; i++) // put 0 in odd places and 1 in even and count the extra changes
    if(i % 2 == 0)
        if(arr[i] == 1){
            arr[i] = 0;
            diff++;
        }
    else
        if(arr[i] == 0){
            arr[i] = 1;
            diff--;
        }
for(i--; diff != 0; i--){ //make the tail
    if(diff > 0) //if we owe 1's put in on 0's
        if(arr[i] == 0){
            arr[i] = 1;
            diff--;
        }
    if(diff < 0) //if we owe 0's put in on 1's
        if(arr[i] == 1){
            arr[i] = 0;
            diff++;
        }
}

Легко понять, почему это правильно, поэтому я не буду объяснять. Временная сложность: O (arr.length ()) или O (n)

...