Двойной связанный список и массив в текстовых редакторах

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

Обратите внимание, что когда я имею в виду массивы, я имею в виду массив символов в строке, а не один линейный массив.

Вот как я взвесил все за и против:

Двойные связанные списки:

  • Более быстрая вставка символов и строк
  • Более быстрое свертывание кода

Массивы:

  • Используйте меньше памяти
  • Гораздо более быстрый разбор
  • Более быстрая печать Правильно ли я использовал связанные списки? Или они лучший способ сделать это?

Примечание:

Массивы печатаются быстрее, потому что достаточно одного вызова printw для печати всей строки. В отличие от вызова printw для каждого символа.


person tay10r    schedule 19.06.2013    source источник
comment
Вы уверены, что массивы быстрее для печати? Я думаю, что они будут иметь одинаковую скорость для этого. Кроме того, если вы используете массивы, все символы должны иметь одинаковую длину, тогда как связанный список допускает смешанную длину (странно, когда «i» занимает столько же места, сколько «W»)   -  person David says Reinstate Monica    schedule 19.06.2013
comment
@Blender Спасибо, это полезно.   -  person tay10r    schedule 19.06.2013
comment
@ Dgrin91, да. Массивы (строки) печатаются быстрее, потому что вам нужно вызывать printw только один раз для каждой строки, а не для каждого символа (в списке). Кроме того, массивы также могут изменять размер, и они не обязательно должны иметь одинаковые размеры. Я не совсем уверен, что вы имели в виду.   -  person tay10r    schedule 19.06.2013
comment
Почему бы не использовать (двухсвязный) список строк, где каждый элемент списка представляет собой строку, чтобы вы могли вызывать printw() один раз для каждой строки, как с массивами. Вы также значительно сократите требования к хранилищу; на 64-битной машине двусвязный список из одиночных символов, вероятно, будет использовать 24 байта на символ, что является довольно большим накладным расходом.   -  person Jonathan Leffler    schedule 19.06.2013
comment
@JonathanLeffler, на самом деле я только начал это делать. Это кажется довольно приличным компромиссом (у меня есть подозрение, что это то, что использует nano). Я, вероятно, удалю этот вопрос, потому что думаю, что это мое решение, с которым я буду работать. Кроме того, не стоит ли использовать realloc при каждой вставке/удалении?   -  person tay10r    schedule 19.06.2013
comment
Я бы, вероятно, разработал узлы списка в соответствии со строками struct Line { struct Line *next; struct Line *prev; char *line; size_t line_len; size_t line_max; };, где line_len записывает текущую длину строки, а line_max записывает выделенное пространство. Я бы не стал вызывать realloc(), когда персонаж был удален; Я бы, вероятно, не стал этого делать, если бы не было довольно большого (256 байт?) несоответствия между фактическим и максимальным размером. [...продолжение...]   -  person Jonathan Leffler    schedule 19.06.2013
comment
[...continuation...] Для вставок я бы перераспределял только тогда, когда больше не было места (когда line_len == line_max, но остерегайтесь по одному), и я бы выделял с шагом не менее 16 символов (потому что это, вероятно, минимальное количество, которое malloc() и др. фактически выделяют в любом случае, плюс, когда пользователь вставляет один символ, они часто вставляют несколько). Итак, вы хотите избежать посимвольных изменений в распределении памяти (вызовы realloc()), не опасаясь перераспределения при необходимости.   -  person Jonathan Leffler    schedule 19.06.2013
comment
@JonathanLeffler спасибо, я начну выделять 16 байт за раз   -  person tay10r    schedule 19.06.2013


Ответы (1)


Перенос комментариев в ответ, поскольку больше никто не вмешивается.

Почему бы не использовать (двухсвязный) список строк, где каждый элемент списка является строкой, чтобы вы могли вызывать printw() один раз для каждой строки, как с массивами? Вы также значительно сократите требования к хранилищу; на 64-битной машине двусвязный список из одиночных символов, вероятно, будет использовать 24 байта на символ, что является довольно большим накладным расходом.

Я на самом деле только начал это делать. Это кажется довольно приличным компромиссом (у меня есть подозрение, что это то, что использует nano). Я, вероятно, удалю этот вопрос, потому что думаю, что это мое решение, с которым я буду работать. Кроме того, не стоит ли использовать realloc() при каждой вставке/удалении?

Я бы, вероятно, разработал узлы списка в соответствии со строками:

struct Line
{
    struct Line *next;
    struct Line *prev;
    char        *line;
    size_t       line_len;
    size_t       line_max;
};

где line_len записывается текущая длина строки, а line_max записывается выделенное пространство.

Я бы не стал вызывать realloc(), когда персонаж был удален; Я бы, вероятно, не стал этого делать, если бы не было довольно большого (256 байт?) несоответствия между фактическим и максимальным размером.

Для вставок я бы перераспределял только тогда, когда места больше не было (когда line_len == line_max, но остерегайтесь по одному), и я бы выделял с шагом не менее 16 символов (потому что это, вероятно, минимальное количество, которое malloc() и др. на самом деле все равно выделять, плюс когда пользователь вставляет один символ, он часто вставляет несколько). Итак, вы хотите избежать посимвольных изменений в распределении памяти (вызовы realloc()), не опасаясь перераспределения при необходимости.

person Jonathan Leffler    schedule 19.06.2013
comment
Спасибо. А если бы я портировал на cpp и использовал std::string? Будет ли это использовать намного больше памяти? Я рассматриваю это только потому, что вставка и удаление строк уже выполнены с классом string. И он также может легко изменять размер строки в блоках n-byte. - person tay10r; 19.06.2013