Как вы сортируете элементы при добавлении их в список (C )?

#c #sorting

#c #сортировка

Вопрос:

Я пытаюсь сортировать слова при добавлении их в список на C . Я должен использовать списки, и я не могу использовать функцию «sort ()».

У меня есть текстовый файл с несколькими словами (каждое слово находится на новой строке).

До сих пор я выяснил, как собирать слова и добавлять их в список:

 fstream myfile(fileName);

if(!myfile) { // Test if file open
    cout<<"Error opening file"<< endl;
    return false;

}

while (getline(myfile, line)){ //loops through and gets sayings
    l.push_back(line);
}
 

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

Заранее спасибо!

Подробная информация:

Я полагаю, что для этого я должен использовать итератор.

Я знаю, как использовать итератор для отображения списка:

 for (list<string>::iterator it=l.begin(); it != l.end();   it)
cout << *it << endl;
 

Как я могу использовать это для сравнения значений перед их добавлением? Я пытался использовать итератор, чтобы получить первую букву слова, используя (*it)[0] , но это недопустимый синтаксис.

Комментарии:

1. Может быть, использовать std::multiset (или std::set )? Или это что-то, что вам тоже не позволено делать?

2. Что я хочу сделать, это проверить первую букву слова, а затем поместить ее в соответствующую позицию в списке, — Как только проверка первой буквы считается «сортировкой»?

3.Я должен использовать списки, и я не могу использовать функцию «sort ()». std::list Поставляется с sort() функцией. Почему вы не можете использовать его, если вы уже используете std::list ?? Я видел некоторые действительно сумасшедшие требования, предъявляемые учителями, но это, должно быть, одно из самых безумных, о которых я когда-либо слышал.

4. не push_back делайте этого. Для каждого слова перебирайте список, пока не найдете первое слово с первой буквой первая буква после слов первая буква, а затем вставьте слово перед словом, которое вы только что нашли.

5. @user4581301 это достойно сожаления. И это еще более неприятно, когда я думаю, что это может быть ожидаемое решение / лучшее, что вы можете сделать с требованиями, как указано в OP.

Ответ №1:

Я бы добавил итератор

 std::list<string> mylist;
std::list<string>::iterator it; //now I can move through the list using this kind of like an index

for (it=mylist.begin(); it!=mylist.end();   it)
{
    if( line.compare(*it) >= 0) //If the line belongs before what *it is pointing to
    {
        mylist.insert(it,line);
        break;
    }
}
 

узнайте больше о string::compare в http://www.cplusplus.com/reference/string/string/compare /

узнайте больше о вставке в список на http://www.cplusplus.com/reference/list/list/insert /

Комментарии:

1. Я едва только поцарапал поверхность с C , но только что познакомился с итераторами от одноклассника. Все, что я вижу здесь, имеет смысл, кроме одной детали, которая является line.compare( it) почему » означает? Я хочу думать, что это указатель, но тогда для меня не имеет смысла, почему мы должны использовать указатель

2. @BrettReinhard — итератор фактически является указателем, поэтому вы используете * его для доступа (чтения или записи) к элементу.

3. @rcgldr спасибо, что прояснили это. Итак, по существу ли это ссылка на адрес, аналогичный тому, как вы передаете массив?

4. @BrettReinhard — не совсем. Обычно внутренний формат std::list представляет собой двусвязный список, поэтому обычно вы не можете индексировать (при условии, что нет разумной перегрузки оператора, std::list не имеет итераторов произвольного доступа). Итак, он продвигается по следующему указателю и — выполняет резервное копирование по предыдущему указателю. std::list функции: begin() возвращает итератор к первому элементу, back() возвращает итератор к последнему элементу, end() возвращает итератор сразу после последнего элемента.

5. @BrettReinhard — верно, есть накладные расходы на связь между узлами. Последовательные узлы в списке могут быть случайным образом разбросаны по памяти, что негативно сказывается на кешировании и делает сканирование относительно медленным. Сортировку лучше всего выполнять с помощью сортировки слиянием снизу вверх с небольшим массивом указателей на узлы, как показано в примере wiki .

Ответ №2:

Предполагая, что вы можете использовать std::set или std::multiset :

 multiset<string> l;

while (getline(myfile, line)){ //loops through and gets sayings
    l.insert(line);
}
 

Это добавит все слова и отсортирует их автоматически. Основное различие между multiset и set заключается в том, что первое допускает дублирование, а второе — нет.

Затем вы можете выполнить итерацию l с for помощью цикла:

 for(string constamp; s : l) {
    cout << s << endl;
}