2008-12-01 2 views
4

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

Список в настоящее время составляет около 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; 
    } 
} 
+0

Совет стиля C++: переместите объявление Iter ближе к первому месту, которое вы его используете. Это позволяет избежать большого объема кода, в котором у вас есть неинициализированная переменная. – 2008-12-01 20:41:57

ответ

5

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

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

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

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

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


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

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


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

Ok. С основного типа «ИНТ» мы имеем:

#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); 
} 
+1

С тех пор, когда именно сортируется любимые списки _O (n) _?Быстрая сортировка требует только двунаправленной итерации, так же эффективна в списках с двойным списком (`std :: list` имеет двойную привязку) в качестве контейнеров с произвольным доступом, а при необходимости сортировки слияния требуется дополнительное хранилище, для этого нужны как оригинальные, так и дополнительные для хранения только вперед. – 2013-01-14 07:04:50

2

СТЛ имеет сортировать алгоритм в заголовке

<algorithm> 

Here's ссылку на руководство SGI.

9

Я не уверен, что правильно понял ваш вопрос, является ли ваша проблема определением функтора сортировки? Сорт 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()); 

или с помощью наддува :: лямбда

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

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

2

Использование станд :: сортировки в заголовке алгоритма:

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

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

0

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

С помощью строки "YYYY/MM/DD-HH: MM" вы можете просто сравнить строки. Все строки имеют одинаковую длину, и вы переходите от максимального увеличения времени к минимальному приращению времени, когда читаете слева направо.

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

Обычно даты хранятся как значения времени_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 < t2.

Смежные вопросы