Сортировка вставок: Что я делаю неправильно? - PullRequest
0 голосов
/ 18 мая 2018

Я пытаюсь сделать сортировку вставкой.Песня представляет собой простую структуру, содержащую свойство Artist и Title.Я называю CompareTitle (Song & s1, Song & s2), которое возвращает true, если название песни первой песни предшествует названию второй песни.Кажется, что условие сортировки работает нормально, когда закомментированная часть кода закомментирована.Когда нет, я получаю эту ошибку.Я не уверен, как подойти к нему:

playlist.cc: 192: 22: ошибка: объект типа 'Song' не может быть назначен, потому что его оператор назначения копирования неявно удален * itr = j;

//do insertion sort
for(auto itr = newSongList.begin(); itr != newSongList.end(); ++itr)
{

    for(auto jtr=itr; jtr != newSongList.begin(); --jtr){
        cout << itr->GetTitle() << " " << jtr->GetTitle() << endl;
        // if s1 is not before s2 then swap them
        if(!Song::CompareTitle(*itr, *jtr)){
            cout << "Swap True (" << itr->GetTitle() << "," << jtr->GetTitle() << " )"<< endl;
            Song i = Song(itr->GetTitle(),itr->GetArtist());
            Song j = Song(jtr->GetTitle(), jtr->GetArtist());

            *itr = j;
            *jtr = i;

            cout << "Swap After (" << jtr->GetTitle() << "," << itr->GetTitle() << endl;
        }
    }
}

Ниже приведена структура песни и плейлиста:

#ifndef PLAYLIST_H
#define PLAYLIST_H

#include <functional>   // For std::function
#include <string>
#include <list>

using namespace std;

extern void SongCallback();

class Song {
  public:
    explicit Song(const string& title, const string& artist,
        const function<void()> = &SongCallback);
        const string& GetTitle() const;
        const string& GetArtist() const;
        bool operator==(const Song& s) const;
        bool operator()(const Song& s) const;

        static bool CompareTitle(const Song& s1, const Song& s2);
        static bool CompareArtistTitle(const Song& s1, const Song& s2);

private:
    const string title_;
    const string artist_;
    const function<void()> callback_;
};

class Playlist {
public:
    explicit Playlist() {}
    void AddSong(const string& title, const string& artist);
    unsigned int RemoveSongs(const string& title, const string& artist);
    list<Song> PlaylistSortedByTitle() const;
    list<Song> PlaylistSortedByArtistTitle() const;
    unsigned int NumSongs() const;
    unsigned int NumSongs(const string& artist) const;

private:
    list<Song> songs_;
};

#endif // PLAYLIST_H

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Поскольку у вас есть параметры const title_ и artist_, вы не можете назначать и перезаписывать их, используя assignment operator.

Компилятор также не будет генерировать assignment operator.Поскольку цель assignment operator состоит в том, чтобы изменять элементы после конструирования, не имеет смысла генерировать неявный assignment operator, когда один из членов никогда не может быть изменен.Компилятор отказывается пытаться угадать, что вы от него хотите, и вынуждает вас предоставить свою собственную assignment operator семантику, которую вы хотите.

Я думаю, что вместо этого вы можете манипулировать записями списка, используя list :: insert и list :: erase методы, как я показал ниже для достижения желаемого результата.

for(auto itr = newSongList.begin(); itr != newSongList.end(); ++itr)
{

    for(auto jtr=itr; jtr != newSongList.begin(); --jtr){
        cout << itr->GetTitle() << " " << jtr->GetTitle() << endl;
        // if s1 is not before s2 then swap them
        if(!Song::CompareTitle(*itr, *jtr)){
            cout << "Swap True (" << itr->GetTitle() << "," << jtr->GetTitle() << " )"<< endl;
            Song i = Song(itr->GetTitle(),itr->GetArtist());
            Song j = Song(jtr->GetTitle(), jtr->GetArtist());

            newSongList.insert(itr, j); // extend list by inserting j song before itr song
            newSongList.erase(itr);     // itr is still pointing to original song
            newSongList.insert(jtr, i); // extend list by inserting i song before jtr song
            newSongList.erase(jtr);     // jtr is still pointing to original song

            cout << "Swap After (" << jtr->GetTitle() << "," << itr->GetTitle() << endl;
        }
    }
}
0 голосов
/ 18 мая 2018

Казалось бы, каждый раз, когда вам нужно поменять местами итератор двух элементов, вы вместо этого добавляете элементы в контейнер до того, как itr и jtr.

for(auto itr = newSongList.begin(); itr != newSongList.end(); ++itr)
{

    for(auto jtr=itr; jtr != newSongList.begin(); --jtr){
        cout << itr->GetTitle() << " " << jtr->GetTitle() << endl;
        // if s1 is not before s2 then swap them
        if(!Song::CompareTitle(*itr, *jtr)){
            swap(*itr, *jtr);
        }
    }
}

Здесь вы можете использовать либоstd::swap в качестве функции подкачки или напишите свою собственную функцию для переключения названий и исполнителей песен вместе с любыми другими участниками, которые могут быть добавлены к ним.std::iter_swap также может быть использован в качестве альтернативы.

std::swap по ссылке CPP

std::iter_swap по ссылке CPP

...