std::stable_sort против std::sort

https://leetcode.com/problems/largest-number/

Когда я решал вышеуказанную проблему, я столкнулся со случаем, когда std::sort() выдавало мне ошибку времени выполнения, но заменив его на std::stable_sort(), тогда ошибки времени выполнения не было. Почему?

Линия выделена стрелкой справа

Код:

class Solution {
public:
    string reverse(string str)
    {
        int n=str.length();
        for(int i=0;i<n/2;i++)
        {
            swap(str[i],str[n-i-1]);
        }
        return str;
    }

    static bool comp(string s1,string s2)
    {
        int min_val=min(s1.length(),s2.length());
        int i=0;
        bool flag=false;
        for(;i<min_val;i++)
        {
            if((s1[i]-'0')==(s2[i]-'0'))
            {
                flag=true;
                continue;
            }

            return (s1[i]-'0')>(s2[i]-'0');
        }

        if(flag==true && s1.length()==s2.length())
        {
            return s1==s2;
        }

        string s1_temp=s1;
        string s2_temp=s2;
        s1_temp+=s2;
        s2_temp+=s1;

        return s1_temp>s2_temp;
    }

    string largestNumber(vector<int>& nums)
    {
        string str="";
        vector<string> inp;

        for(int i=0;i<nums.size();i++)
        {
            string temp="";
            long long int num=nums[i];
            if(num!=0)
            {
                while(num!=0)
                {
                    temp+=((num%10)+'0');
                    num/=10;
                }
            }
            else
            {
                temp+=(num+'0');
            }

            inp.push_back(reverse(temp));
        }

        stable_sort(inp.begin(),inp.end(),comp); // <-- This Line

        string res="";

        for(int i=0;i<inp.size();i++)
        {
            res+=inp[i];
        }
        cout<<"yes"<<endl;
        if(res[0]=='0')
        {
            return "0";
        }

        return res;
    }
};

Прецедент:

[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

Может ли кто-нибудь объяснить мне причину, почему это произошло?


person Vikram Keswani    schedule 27.05.2020    source источник
comment
В чем ошибка обычной сортировки?   -  person Jan Schultke    schedule 27.05.2020
comment
Зачем вам нужна пользовательская функция сравнения? Вы не можете полностью исключить comp?   -  person Jan Schultke    schedule 27.05.2020
comment
Пожалуйста, отредактируйте и покажите минимально воспроизводимый пример.   -  person Jabberwocky    schedule 27.05.2020
comment
** Далее была ошибка времени выполнения **: Строка 431: Char 55: ошибка времени выполнения: выражение индекса указателя с базой 0xbebebebebebebebebe переполнено до 0x7d7d7d7d7d7d7d7c (basic_string.h)   -  person Vikram Keswani    schedule 27.05.2020
comment
@VikramKeswani вам нужно показать минимально воспроизводимый пример.   -  person Jabberwocky    schedule 27.05.2020
comment
@Jabberwocky Я поделился ссылкой на проблему. Если вы запустите этот код, он запустится.   -  person Vikram Keswani    schedule 27.05.2020
comment
Ваш код неполный. Где main? Где твои #include?   -  person Jabberwocky    schedule 27.05.2020
comment
leetcode.com/problems/largest-number Я решал проблему с leetcode, основной предусмотрена функция. @Бессмыслица   -  person Vikram Keswani    schedule 27.05.2020
comment
ОК, я понимаю, такая отладка очень болезненна. Используйте отладчик на своем компьютере, если вы действительно хотите изучить C++.   -  person Jabberwocky    schedule 27.05.2020
comment
Компаратор для std::sort должен возвращать false, когда значения равны, иначе у вас будет неопределенное поведение.   -  person Alan Birtles    schedule 27.05.2020
comment
не проблема, но (s1[i]-'0')==(s2[i]-'0') такое же, как s1[i]==s2[i] и то же самое для <   -  person 463035818_is_not_a_number    schedule 27.05.2020


Ответы (1)


На самом деле это очень интересный баг! Я не проверял, является ли это конкретной проблемой leetcode, но запустив этот код с sort() в leetcode, мы получим следующую ошибку:

Line 431: Char 55: runtime error: pointer index expression with base 0xbebebebebebebebe overflowed to 0x7d7d7d7d7d7d7d7c (basic_string.h)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/basic_string.h:440:55

что, кажется, предполагает, что у нас по какой-то причине не хватает памяти. Тот факт, что этот код работает с stable_sort(), но не с sort(), предполагает, что это может быть как-то связано с тем фактом, что "stable_sort сохраняет относительный порядок элементов с эквивалентными значениями" (http://www.cplusplus.com/reference/algorithm/stable_sort/).

Строка кода, где это актуально, находится здесь

if(flag==true && s1.length()==s2.length())
{
    return s1==s2;
}

И действительно, если мы изменим это на

if(flag==true && s1.length()==s2.length())
{
    return s1!=s2;
}

что не влияет на результаты, потому что если в этот момент flag == true и обе строки имеют одинаковую длину, то они обе эквивалентны, и перестановка позиций строки не влияет на результат.

НО мы обходим ошибку. @Vikram Keswani Надеюсь, это решит вашу проблему. Лично я бы просто заменил код в функции comp() на return s1 > s2;, который должен обеспечить то же поведение, что и код, который у вас есть.

p.s. Я оставлю кусочки головоломки здесь, но если кто-то более опытный (или когда я найду больше времени) захочет глубже исследовать эту загадочную проблему с памятью, это было бы здорово.

Между прочим, минимальная длина ввода, необходимая для воспроизведения этой ошибки в leetcode, составляет [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], что равно 17 0 (странное число).

person Desmond Cheong    schedule 27.05.2020
comment
Да, это ответ. std::sort требует от компаратора выполнения определенных требований. В частности, это должен быть строго слабый порядок, и он должен выполнять comp(a,a)==false. Другими словами, элемент должен не сравниваться с самим собой. Функция OP не выполняет этого (comp("0", "0") возвращает true). Ваше исправление переворачивает это и делает компаратор совместимым с требованиями. - person Frodyne; 27.05.2020