Сортировка по четным и нечетным числам

Я хотел бы знать, можно ли сортировать число по четному или нечетному с помощью функции std::sort.

У меня есть следующие коды, но я не уверен, как их реализовать в std::sort

inline bool isEven(const Point n) {
return n.getX()%2==0;
}

Это правильно

vector<Point> c;
std::sort(c.begin(),c.end(),isEven)

Пожалуйста посоветуй.


person M.A    schedule 16.11.2012    source источник
comment
Вы хотите сортировать только по X? Ваш код не компилируется, вы передаете n, затем используете num   -  person emartel    schedule 16.11.2012
comment
функция сравнения сравнивает одну вещь с другой, то есть две вещи   -  person Cheers and hth. - Alf    schedule 16.11.2012
comment
Кроме того, чтобы проверить, является ли число нечетным, используйте оператор & с 1 (value & 1) вместо выполнения операции по модулю (%).   -  person emartel    schedule 16.11.2012
comment
@emartel Почему? Единственная причина, которую я вижу, это обфускация.   -  person James Kanze    schedule 16.11.2012
comment
@JamesKanze, должно быть, вопрос привычки, но я не считаю, что побитовое И запутывает. Теоретически & 1 должно быть оптимальнее, чем % 2. Несмотря на то, что Visual Studio будет генерировать для обоих mov byte ptr [isOdd],1, я не думаю, что каждый компилятор будет это делать. Также, поскольку речь идет о сортировке, скорость этой операции следует считать критичной.   -  person emartel    schedule 16.11.2012
comment
@emartel как реализовать & 1   -  person M.A    schedule 16.11.2012
comment
@ user1571494 value % 2 будет 0 для четного и 1 для нечетного, простая замена % 2 на & 1 как в value & 1 будет 0 для четного и 1 для нечетного   -  person emartel    schedule 16.11.2012
comment
@emartel Вы хотите знать, четное ли число. Определение даже состоит в том, что оно делится на 2. Использование побитовых операторов для этого лжет о ваших намерениях. И, конечно же, сегодня каждый компилятор будет генерировать один и тот же код для двух операций, так что это не имеет большого значения. (На самом деле, в некоторых случаях ясность вашего намерения поможет оптимизировать компилятор. Я определенно сталкивался со случаем, когда h * 127 был быстрее, чем (h << 7) - h, на машине, не имеющей аппаратного разделения.)   -  person James Kanze    schedule 16.11.2012


Ответы (6)


Насколько я понимаю из вашего вопроса, вы хотите разделить числа odd и even. В этом случае std::partition сделает именно это.

Если вы хотите отсортировать по возрастанию значений И разделить числа odd и even, я бы использовал что-то похожее на этот фрагмент кода (тем не менее, вам нужно будет выяснить, какой компонент вашего Point вы хотите отсортировать)

bool sortByEven(const int& left, const int& right)
{
    if(left & 1 && right & 1) // both are odd
    {
        return left < right;
    }
    else if(left & 1) // left is odd
    {
        return false;
    }
    else if(right & 1) // right is odd
    {
        return true;
    }

    // both are even
    return left < right;
}

Эту функцию можно использовать с std::sort, вот краткий пример:

std::vector<int> numbers;
numbers.push_back(-1);
numbers.push_back(5);
numbers.push_back(12);
numbers.push_back(7);
numbers.push_back(-31);
numbers.push_back(-20);
numbers.push_back(0);
numbers.push_back(41);
numbers.push_back(16);

std::sort(numbers.begin(), numbers.end(), sortByEven);

Вы получите следующий результат:

-20 0 12 16 -31 -1 5 7 41

Для других типов просто измените параметр int или сделайте его параметром template.

person emartel    schedule 16.11.2012

Для этого вы должны использовать std::partition вместо std::sort

vector<Point> c;
std::partition(c.begin(),c.end(),isEven)

При сортировке обычно требуется, чтобы сортировка основывалась на относительном порядке любых двух элементов. В этом случае вы просто хотите разделить свой ввод на основе неотъемлемого свойства ваших элементов. Оба случая можно свести к другому, но прямой подход всегда немного проще.

person ltjax    schedule 16.11.2012
comment
будет ли он сортировать элементы с четным значением вверху и нечетными значениями внизу. - person M.A; 16.11.2012
comment
Это поместит все четные элементы перед нечетными, но вы можете просто инвертировать предикат или использовать обратные итераторы, если хотите наоборот. - person ltjax; 16.11.2012
comment
Чем метод isEven такой же, как я набрал выше, или это метод С++ - person M.A; 16.11.2012
comment
Функция, которую вы указали выше, будет работать. Я не знаю, что вы подразумеваете под методом С++. - person ltjax; 16.11.2012

Если вы посмотрите на ссылку для std::sort, вы увидите, что функция, которую он использует для compare должен принимать два аргумента для сравнения. Так что ваш код вообще не будет работать.

Вместо этого я рекомендую вам перебирать вектор, сортируя четные значения в один временный вектор, а нечетные значения в другой временный вектор. Затем вы очищаете фактический вектор и добавляете два временных вектора в нужном вам порядке.

person Some programmer dude    schedule 16.11.2012

Вы можете написать функцию сравнения, например

bool evenOddLess( Point const& a, Point const& b )
{ return (isEven( a ) < isEven( b )); }

Затем вы можете использовать это как третий аргумент для std::sort.

person Cheers and hth. - Alf    schedule 16.11.2012

В C# это еще проще:

 class Program 
    {
        static void Main()
        {
          int[] numbers = { 1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14 };

         //using delegate
          Array.Sort (numbers, (x, y) => x % 2 == y % 2 ? 0 : x % 2 == 1 ? -1 : 1);

          Array.ForEach(numbers, x => Console.Write(x));
          Console.WriteLine("");

         //using custom comparer
          CustomComparer comparer = new CustomComparer();
          Array.Sort(numbers, comparer);
          Array.ForEach(numbers, x => Console.Write(x));
          Console.WriteLine("");

          //using lambda
          int[] items = numbers.OrderBy(x => x % 2 == 0).ThenBy(x => x % 2).ToArray();

          Console.WriteLine("");
          Array.ForEach(items, x => Console.Write(x));
        }

        public int Compare(int x, int y)
        {
            return x % 2 == y % 2 ? 0 : x % 2 == 1 ? -1 : 1;
        }
    }

    public class CustomComparer : IComparer<int>
    {
        int IComparer<int>.Compare(int x, int y)
        {
            return x % 2 == y % 2 ? 0 : x % 2 == 1 ? -1 : 1;
        }
    }
person komizo    schedule 20.12.2012

Загвоздка в том, что есть две функции, которые вы можете использовать.

template< class BidirectionalIterator, class UnaryPredicate >
BidirectionalIterator partition( BidirectionalIterator first, BidirectionalIterator last, UnaryPredicate p );

template< class BidirectionalIterator, class UnaryPredicate >
BidirectionalIterator stable_partition( BidirectionalIterator first, BidirectionalIterator last, UnaryPredicate p );

Функции partition() и stable_partition() реорганизовать элементы коллекции таким образом, чтобы все элементы, для которых предикат p возвращает true, будет предшествовать всем тем, для которых p возвращает false. Это означает, что элементы будут разделены на два диапазона:

• [во-первых, return_value)

• [возвращаемое_значение, последнее)

где return_value — это итератор, возвращаемый любой из функций. Последовательность элементов в результирующих группах такова, где partition() и stable_partition() различаются.

partition() не гарантирует какой-либо конкретный порядок в диапазонах.

stable_partition() сохранит относительный порядок элементов до разделения. Это означает, что если есть два элемента a и b, и a предшествует b, и если они оба принадлежат к одной и той же группе после разделения, элемент a все равно будет предшествовать элементу b.

Вот пример кода:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

bool IsOdd(int i) {
    return (i & 1); //use !(i & 1); if you want to place even elements first in the vector
}

int main() {
    vector<int> v;
    // set some values and shuffle them:
    for (int i = 1; i<10; ++i)
        v.push_back(i);
    random_shuffle(v.begin(), v.end());

    cout << "All elements:";
    for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
        cout << ' ' << *it;
    cout << endl;

    //sort the vector
    cout << "Sorted vector:";
    sort(v.begin(), v.end());
    for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
        cout << ' ' << *it;
    cout << endl;

    //change to partition and see the difference
    vector<int>::iterator bound = stable_partition(v.begin(), v.end(), IsOdd);

    // print content:
    cout << "odd elements:";
    for (std::vector<int>::iterator it = v.begin(); it != bound; ++it)
        cout << ' ' << *it;
    cout << endl;

    cout << "even elements:";
    for (vector<int>::iterator it = bound; it != v.end(); ++it)
        cout << ' ' << *it;
    cout << endl;

    cout << "Sorted odd-even vector:";
    for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
        cout << ' ' << *it;
    cout << endl;

    return 0;
}

Выход:

All elements: 5 6 2 1 9 4 7 8 3
Sorted vector: 1 2 3 4 5 6 7 8 9
odd elements: 1 3 5 7 9
even elements: 2 4 6 8
Sorted odd-even vector: 1 3 5 7 9 2 4 6 8

Я надеюсь, что это поможет для понимания.

person BugShotGG    schedule 26.02.2016