Какой использовать связанный список или статические массивы?

У меня есть структура на C, которая напоминает запись таблицы базы данных. Теперь, когда я запрашиваю таблицу с помощью select, я не знаю, сколько записей я получу. Я хочу сохранить все возвращенные записи из запроса выбора в массиве типа данных моей структуры.

Какой метод лучше?

Метод 1: найти размер массива и выделить

  1. сначала получите количество записей, выполнив select count (*) из таблицы
  2. выделить статический массив
  3. запустите select * from table, а затем сохраните каждую запись в моей структуре в цикле.

Метод 2: используйте односвязный список

while ( records returned )
{
    create new node 
    store the record in node 
}

Какая реализация лучше?

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

Спасибо

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
1 414
7

Ответы 7

Проблема с 'select count (*)' заключается в том, что значение может меняться между вызовами, поэтому ваш «настоящий» выбор будет иметь количество элементов, отличное от ожидаемого количества.

Думаю, лучшее решение - ваша «2». Вместо связанного списка я бы лично выделил массив (при необходимости перераспределив). Это проще в языках, поддерживающих растущие массивы (например, std::vector<myrecord> в C++ и List<myrecord> в C#).

да, я подумал о проблеме ... я упомянул, что значение счетчика может измениться ... если кто-то вставит новую запись ... так что да ... я тоже чувствую, что нет 2 лучше ... спасибо

linkedlist 01.01.2009 19:45

Конечно, вы помещаете счетчик SELECT (*) и «настоящий» SELECT в сериализуемую транзакцию? Таким образом, нет риска, что значение изменится между вызовами.

bortzmeyer 02.01.2009 00:54

Вы забыли вариант 3, он немного сложнее, но может быть лучше всего для вашего конкретного случая. Так обычно делается в C++ std :: vector.

Выделяйте массив любого удобного размера. Когда этот массив будет заполнен, выделите новый массив большего размера от 1,5x до 2x размера заполненного, затем скопируйте заполненный массив в этот. Освободите исходный массив и замените его новым. Вспенить, промыть, повторить.

Этот алгоритм отлично работает на C, я только что упомянул C++ в качестве примера.

Mark Ransom 01.01.2009 19:53

Поместите все в непрозрачную структуру данных и получите доступ к этой структуре только с помощью определенных методов / макросов.

skiphoppy 01.01.2009 20:35

Документация Qt предоставляет умный метод выделения + роста для массивов: doc.trolltech.com/4.4/containers.html#growth-strategies

strager 01.01.2009 21:01

Кроме того, поскольку OP использует C, он может использовать realloc () вместо выделения нового массива и копирования. Это то, что делает стратегии роста Qt эффективными.

strager 01.01.2009 23:07

И забыл вариант №4. Выделите массив фиксированного размера. Когда этот массив заполнится, выделите другой. Вы можете отслеживать массивы, связывая их в связанный список или имея массив более высокого уровня, в котором хранятся указатели на массивы данных. Эта двухуровневая схема отлично подходит, когда вам нужен произвольный доступ, вам просто нужно разбить ваш индекс на две части.

Есть много возможных критических замечаний, которые следует сделать.

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

  2. Вы не даете никаких указаний ни о размере записи, ни о количестве записей, ни о том, насколько динамична находящаяся под ней база данных (то есть может ли какой-либо другой процесс изменить какие-либо данные во время работы вашего). Информация о размерах не очень важна, но есть другой фактор. Если вы составляете какой-то отчет, тогда можно загрузить данные в память; вы не собираетесь изменять базу данных, и данные представляют собой точный снимок. Однако, если другие люди могут изменять записи, в то время как вы изменяете записи, ваше общее решение является основным примером того, как потерять чужие обновления. Это вещь ПЛОХО!

  3. Зачем вам сразу все данные в памяти? Игнорирование ограничений размера, в чем именно преимущество этого по сравнению с обработкой каждой соответствующей записи один раз в правильной последовательности? Видите ли, СУБД прилагает много усилий, чтобы иметь возможность выбирать соответствующие записи (предложения WHERE) и соответствующие данные (списки SELECT) и позволять вам указывать последовательность (предложения ORDER BY), и у них есть лучшие системы сортировки, которые они могут позволить себе (лучше, чем те, которые вы или я, вероятно, произведем).

  4. Остерегайтесь квадратичного поведения, если вы распределяете массив по частям. Каждый раз, когда вы перераспределяете, есть большая вероятность, что старую память придется скопировать в новое место. Это фрагментирует вашу память (старое местоположение будет доступно для повторного использования, но по определению будет слишком маленьким для повторного использования). Марк Рэнсом указывает разумную альтернативу - не самую простую схему в мире в целом (но она избегает квадратичного поведения, о котором я упоминал). Конечно, вы можете (и будете) абстрагироваться от этого с помощью набора подходящих функций.

  5. Массовая загрузка (также упомянутая Марком Рэнсомом) также полезна. Вы можете предварительно выделить массив, в который выполняется массовая выборка, чтобы вам не приходилось выполнять дополнительное копирование. Однако это просто линейное поведение, поэтому оно менее серьезно.

Создайте структуру данных для представления вашего массива или списка. Представьте, что вы используете объектно-ориентированный язык, и создайте аксессоры и конструкторы для всего, что вам нужно. Внутри этой структуры данных сохраните массив и, как говорили другие, когда массив заполнится до предела, выделите новый массив в 2 раза больше и скопируйте в него. Доступ к структуре только через определенные вами процедуры для доступа к ней.

Именно так это делают Java и другие языки. Внутри это даже то, как Perl реализован в C.

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

while(record = get_record()) {
  records++;
  records_array = (record_struct *) realloc(records_array, (sizeof record_struct)*records);
  *records_array[records - 1] = record;
}

Это строго пример - пожалуйста, не используйте realloc () в производстве.

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

Jonathan Leffler 02.01.2009 04:00

Джонатан, ты абсолютно прав. Это проверочный код, и я бы вообще не стал использовать функцию realloc () в продакшене.

Max 02.01.2009 05:49

Связанный список - удобный и простой вариант. Я бы с этим согласился. Если вы предпочитаете растущий массив, вы можете найти реализацию как часть Интерфейсы C и реализации Дэйва Хэнсона, который в качестве бонуса также предоставляет связанные списки.

Мне это кажется дизайнерским решением, которое может измениться по мере развития вашего приложения, поэтому вам обязательно стоит скрыть представление за подходящим API. Если вы еще не знаете, как это сделать, код Hanson предоставит вам несколько хороших примеров.

Другие вопросы по теме