C ++ сортировка вектора или связанного списка - PullRequest
4 голосов
/ 01 декабря 2008

У меня есть входной файл, который я хочу отсортировать на основе метки времени, которая является подстрокой каждой записи. Я хочу хранить несколько атрибутов

В данный момент в списке около 1000 записей. Но я хочу, чтобы на всякий случай его можно было немного увеличить.

Когда я сделал это со связанным списком, выполнив поиск по всему списку для вставки, это заняло около 20 секунд. Теперь, просто заполнение вектора и вывод в файл занимает 4 секунды (это звучит слишком долго)?

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

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

Буду признателен за любые ссылки или примеры о простейшем способе сделать это с довольно приличной производительностью. Я застрял на том, как реализовать эти сортировки с объектами, потому что я новичок в C ++:)

Вот как выглядит мой новый код (пока нет сортировки):

class CFileInfo  
{  
    public:  
    std::string m_PackLine;  
    std::string m_FileDateTime;  
    int m_NumDownloads;  
};  
void main()  
{  
    CFileInfo packInfo;  
    vector<CFileInfo> unsortedFiles;  
    vector<CFileInfo>::iterator Iter;  
    packInfo.m_PackLine = "Sample Line 1";  
    packInfo.m_FileDateTime = "06/22/2008 04:34";  
    packInfo.m_NumDownloads = 0;  
    unsortedFiles.push_back(packInfo);  
    packInfo.m_PackLine = "Sample Line 2";  
    packInfo.m_FileDateTime = "12/05/2007 14:54";  
    packInfo.m_NumDownloads = 1;  
    unsortedFiles.push_back(packInfo);  
    for (Iter = unsortedFiles.begin(); Iter != unsortedFiles.end(); ++Iter )   
    {  
        cout << " " << (*Iter).m_PackLine;  
    }  
}  

Ответы [ 5 ]

9 голосов
/ 01 декабря 2008

Я не уверен, что правильно понял ваш вопрос, ваша проблема в определении функтора сортировки? Сортировка STL обычно реализуется как интроспективная сортировка, что очень хорошо для большинства случаев.

struct sort_functor
{
    bool operator()(const CFileInfo & a, const CFileInfo & b) const
    {

        // may be a little bit more subtle depending on what your strings look like
        return a.m_FileDateTime < b.m_FileDateTime;
    }
}

std::sort(unsortedFiles.begin(), unsortedFile.end(), sort_functor());

или используя boost :: lambda

std::sort(unsortedFiles.begin(), 
    unsortedFile.end(),
    bind(&CFileInfo::m_FileDateTime, _1) < bind(&CFileInfo::m_FileDateTime, _2));

Была ли это необходимая информация?

5 голосов
/ 02 декабря 2008

Сортировка связанного списка по своей природе будет либо O (N ^ 2), либо задействует внешнее хранилище с произвольным доступом.

Векторы имеют хранилище с произвольным доступом. Как и массивы. Сортировка может быть O (NlogN).

При 1000 элементах вы начнете видеть разницу между O (N ^ 2) и O (NlogN). На 1 000 000 элементов вы обязательно заметите разницу!

В очень особых ситуациях можно получить сортировку O (N). (Например: сортировка колоды игральных карт. Мы можем создать функцию (карту), которая отображает каждую карту в ее отсортированном положении.)

Но в целом O (NlogN) так же хорош, как и получает. Так что вы могли бы также использовать sort () STL!
Просто добавьте # include


Все, что вам нужно добавить, это оператор <(). Или сортировочный функтор. </p>

Но одно предложение: ради бога, если вы собираетесь отсортировать дату, либо закодируйте ее как длинное целое, представляющее секунды с момента эпохи (mktime?), Или, по крайней мере, используйте "год / месяц / день-час: минута: секунда. Фракция" формат. (И УБЕДИТЕСЬ, что все 2 (или 4) цифры с ведущими нулями!) Сравнение «6/22 / 2008-4: 34» и «12/5 / 2007-14: 54» потребует анализа! Сравнивать "2008/06 / 22-04: 34" с "2007/12 / 05-14: 54" гораздо проще. (Хотя все еще намного менее эффективно, чем сравнение двух целых чисел!)


Рич написал: другие ответы, похоже, больше входят в синтаксис, чего мне действительно не хватает.

Ok. С базовым типом int мы имеем:

#define PRINT(DATA,N) for(int i=0; i<N; i++) { cout << (i>0?", ":"") << DATA[i]; } cout << endl;

int
main()  
{
    // Creating and Sorting a stack-based array.
  int d [10] = { 1, 4, 0, 2, 8, 6, 3, 5, 9, 7 };
  PRINT(d,10);
  sort( d, d+10 );
  PRINT(d,10);

  cout << endl;

    // Creating a vector.
  int eData [10] = { 1, 4, 0, 2, 8, 6, 3, 5, 9, 7 };
  vector<int> e;
  for(int i=0; i<10; i++ )
    e.push_back( eData[i] );

    // Sorting a vector.
  PRINT(e,10);
  sort(e.begin(), e.end());
  PRINT(e,10);
}

С вашим собственным типом мы имеем:

class Data
{  
public:  
  string m_PackLine;  
  string m_FileDateTime;  
  int    m_NumberDownloads;

    /* Lets simplify creating Data elements down below. */
  Data( const string & thePackLine  = "",
        const string & theDateTime  = "",
        int            theDownloads = 0 )
      : m_PackLine        ( thePackLine  ),
        m_FileDateTime    ( theDateTime  ),
        m_NumberDownloads ( theDownloads )
    { }

    /* Can't use constructor with arrays */
  void set( const string & thePackLine,
            const string & theDateTime,
            int            theDownloads = 0 )
    {
      m_PackLine        = thePackLine;
      m_FileDateTime    = theDateTime;
      m_NumberDownloads = theDownloads;
    }

    /* Lets simplify printing out down below. */ 
  ostream & operator<<( ostream & theOstream ) const
    {
      theOstream << "PackLine=\"" << m_PackLine
                 << "\"   fileDateTime=\"" << m_FileDateTime
                 << "\"   downloads=" << m_NumberDownloads;
      return theOstream;
    }


    /*
     * This is IT!  All you need to add to use sort()!
     *  Note:  Sort is just on m_FileDateTime.  Everything else is superfluous.
     *  Note:  Assumes "YEAR/MONTH/DAY HOUR:MINUTE" format.
     */
  bool operator< ( const Data & theOtherData ) const
    { return m_FileDateTime < theOtherData.m_FileDateTime; }

};

    /* Rest of simplifying printing out down below. */ 
ostream & operator<<( ostream & theOstream, const Data & theData )
  { return theData.operator<<( theOstream ); }


    /* Printing out data set. */
#define PRINT(DATA,N) for(int i=0; i<N; i++) { cout << "[" << i << "]  " << DATA[i] << endl; }  cout << endl;

int
main()
{  
    // Creating a stack-based array.
  Data d [10];
  d[0].set( "Line 1", "2008/01/01 04:34", 1 );
  d[1].set( "Line 4", "2008/01/04 04:34", 4 );
  d[2].set( "Line 0", "2008/01/00 04:34", 0 );
  d[3].set( "Line 2", "2008/01/02 04:34", 2 );
  d[4].set( "Line 8", "2008/01/08 04:34", 8 );
  d[5].set( "Line 6", "2008/01/06 04:34", 6 );
  d[6].set( "Line 3", "2008/01/03 04:34", 3 );
  d[7].set( "Line 5", "2008/01/05 04:34", 5 );
  d[8].set( "Line 9", "2008/01/09 04:34", 9 );
  d[9].set( "Line 7", "2008/01/07 04:34", 7 );

    // Sorting a stack-based array.
  PRINT(d,10);
  sort( d, d+10 );
  PRINT(d,10);

  cout << endl;

    // Creating a vector.
  vector<Data> e;
  e.push_back( Data( "Line 1", "2008/01/01 04:34", 1 ) );
  e.push_back( Data( "Line 4", "2008/01/04 04:34", 4 ) );
  e.push_back( Data( "Line 0", "2008/01/00 04:34", 0 ) );
  e.push_back( Data( "Line 2", "2008/01/02 04:34", 2 ) );
  e.push_back( Data( "Line 8", "2008/01/08 04:34", 8 ) );
  e.push_back( Data( "Line 6", "2008/01/06 04:34", 6 ) );
  e.push_back( Data( "Line 3", "2008/01/03 04:34", 3 ) );
  e.push_back( Data( "Line 5", "2008/01/05 04:34", 5 ) );
  e.push_back( Data( "Line 9", "2008/01/09 04:34", 9 ) );
  e.push_back( Data( "Line 7", "2008/01/07 04:34", 7 ) );

    // Sorting a vector.
  PRINT(e,10);
  sort(e.begin(), e.end());
  PRINT(e,10);
}
2 голосов
/ 01 декабря 2008

Используйте std :: sort в заголовке алгоритма:

Если вы определяете оператор <для CFileInfo, он должен работать без проблем. </p>

В качестве альтернативы, определите функтор, выполняющий сравнение, и передайте его в качестве отдельного аргумента в функцию сортировки.

2 голосов
/ 01 декабря 2008

У stl есть алгоритм сортировки в заголовке

 <algorithm>

Вот ссылка на руководство SGI.

0 голосов
/ 04 декабря 2008

Rich - Чтобы ответить на более свежий вопрос (а не на исходный вопрос), вероятно, лучше / проще всего просто разобрать дату с помощью sscanf (). В идеале вы хотите сохранить его численно для начала.

С помощью строки "ГГГГ / ММ / ДД-ЧЧ: ММ" вы можете просто сравнить строки. Все строки имеют одинаковую длину, и вы переходите от наибольшего приращения времени к наименьшему приращению времени при чтении слева направо.

Но сравнение строк очень неэффективно!

Обычно даты хранятся в виде значений time_t (целых), измеренных в секундах с начала эпохи (00:00:00 UTC, 1 января 1970 года).

mktime () или timegm () (если у вас есть timegm) создадут значение time_t из "struct tm" , которую вы предоставите.

Пример кода:

#define SHOW(X)  cout << # X " = " << (X)

int
main()
{
  const string s = "2008/12/03 12:48";
  struct tm    datetime;
  time_t       t;

  memset( & datetime, 0, sizeof(datetime) );

  if ( 5 != sscanf( s.c_str(), "%d/%d/%d %d:%d",
                    & datetime.tm_year,
                    & datetime.tm_mon,
                    & datetime.tm_mday,
                    & datetime.tm_hour,
                    & datetime.tm_min  ) )
  {
    cout << "FAILED to parse:  \"" << s << "\"" << endl;
    exit(-1);
  }

    /* tm_year - The number of years since 1900. */
  datetime.tm_year -= 1900;

    /* tm_mon - The number of months since January, in the range 0 to 11. */
  datetime.tm_mon --;

    /* tm_mday - The day of the month, in the range 1 to 31. */
    /* tm_hour - The number of hours past midnight, in the range 0 to 23. */
    /* tm_min - The number of minutes after the hour, in the range 0 to 59. */
  // No change.

  /* If using mktime, you may need these to force UTC time:
   *   setenv("TZ","",1);
   *   tzset();
   */

  t = mktime( & datetime );

  SHOW( t ) << endl;
  SHOW( asctime( & datetime ) );
  SHOW( ctime( & t ) );
}

Теперь даны два значения времени (даты), например, time_t t1, t2 , вы можете сравнить их с t1 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...