Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Быстрый доступ к элементу.
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
Jenya7
Я получаю пакеты данных. Эти пакеты я должен хранить в RAM. Глубина хранения не определена но пока что это 512 пакетов.
То есть в RAM я создал массив 512 пакетов.
У каждого пакета есть два поля ID - ID1/ID2. Значения инденцификационных полей варьируются ID1=0-10000, ID2=0-255.
Мне приходит команда - добавь пакет 700/12, удали пакет 700/12, редактируй пакет 700/12. Команда приходит довольно часто - худший случай - каждую милисекунду поэтому время поиска элемента критично.
Проблема в быстром поиске пакета. Сделать хэш таблицу ID1-ID2 <=> индекс - громадная таблица получиться.
Сейчас к чему я пришел - самое оптимальное связанный список.
И тут я вспомнил работу с SQL базами данных - это ж просто праздник какой то. Добавляй, удаляй, редактируй записи сколько влезет и очень быстро.
В принципе это может быть non-SQL база данных - у меня всего одна таблица.
Есть реализация базы данных для эмбедед? кто нибудь видел такое? может даже реализовывал?

P.S. Погуглил эту тему. Вроде как советуют SQLLite. Но я не нашел примеров SQLLite для эмбеддед в С.
jcxz
Цитата(Jenya7 @ Oct 22 2017, 11:54) *
Проблема в быстром поиске пакета. Сделать хэш таблицу ID1-ID2 <=> индекс - громадная таблица получиться.

Сделайте таблицу преобразования ID1/ID2 -> индекс пакета в массиве. ID1/ID2 в таблицу добавляйте отсортированными по возрастанию.
Тогда поиск можно делать методом последовательного приближения: в худшем случае будет около 9 шагов цикла поиска.

Цитата(Jenya7 @ Oct 22 2017, 11:54) *
Есть реализация базы данных для эмбедед? кто нибудь видел такое? может даже реализовывал?

Бред. Любая "библиотека" для такой задачи будет однозначно тормознее специализированного решения. А уж всякие SQL-и сюда тащить - верх глупости.
Ну если конечно руки не совсем уж кривые....
Rst7
QUOTE
И тут я вспомнил работу с SQL базами данных - это ж просто праздник какой то. Добавляй, удаляй, редактируй записи сколько влезет и очень быстро.


Это только кажется. Поиск - да, быстрый, ибо при правильном применении индексов он логарифмический. Т.е. в Вашем случае на поиск нужного элемента будет всего 9 сравнений. А вот добавление/удаление может затянуться, ибо надо перебалансировать дерево.

В Вашем случае SQL - это сильно избыточно. Реализуйте это сами, там всего-то на полстраницы кода. Ключевое слово для гугля - "бинарное дерево поиск добавление удаление элемента". Хотя лично я бы возможно поступил чуть по-другому. Вместо дерева имел бы сортированный массив (ключ + указатель на пакет) и тупо добавлял/удалял из него элементы через memmove. Потому что даже большой memmove (в данной ситуации худший случай будет 511*(sizeof(int)+sizeof(*pkt))=2кБайт) может оказаться куда быстрее перебалансирования дерева.
Jenya7
Цитата(jcxz @ Oct 22 2017, 14:09) *
Сделайте таблицу преобразования ID1/ID2 -> индекс пакета в массиве. ID1/ID2 в таблицу добавляйте отсортированными по возрастанию.
Тогда поиск можно делать методом последовательного приближения: в худшем случае будет около 9 шагов цикла поиска.


Бред. Любая "библиотека" для такой задачи будет однозначно тормознее специализированного решения. А уж всякие SQL-и сюда тащить - верх глупости.
Ну если конечно руки не совсем уж кривые....

переберите все сочитания 0-10000 и 0-255. Уж не помню, факториал по моему дает результат но таблица получиться громадная.

Цитата(Rst7 @ Oct 22 2017, 14:14) *
Это только кажется. Поиск - да, быстрый, ибо при правильном применении индексов он логарифмический. Т.е. в Вашем случае на поиск нужного элемента будет всего 9 сравнений. А вот добавление/удаление может затянуться, ибо надо перебалансировать дерево.

В Вашем случае SQL - это сильно избыточно. Реализуйте это сами, там всего-то на полстраницы кода. Ключевое слово для гугля - "бинарное дерево поиск добавление удаление элемента". Хотя лично я бы возможно поступил чуть по-другому. Вместо дерева имел бы сортированный массив (ключ + указатель на пакет) и тупо добавлял/удалял из него элементы через memmove. Потому что даже большой memmove (в данной ситуации худший случай будет 511*(sizeof(int)+sizeof(*pkt))=2кБайт) может оказаться куда быстрее перебалансирования дерева.

ключ + указатель на пакет - это легко сказать. а как создать?
Rst7
QUOTE
переберите все сочитания 0-10000 и 0-255. Уж не помню, факториал по моему дает результат но таблица получиться громадная.


Вы не поняли. Не надо хранить таблицу размером 10000*256. Нужен лишь всего массив структур {int key; PKT *p;} размером в 512 элементов. Если этот массив хранить по возрастанию key (или убыванию), то поиск элемента в нем потребует только 9 сравнений. key - это id1*256+id2, если что.

QUOTE
а как создать?


Для Ваших целей в качестве ключа вполне пойдет линейная комбинация id1 и id2. Т.к. диапазон id2 у Вас 0...255, то самый простой способ - key=id1*256+id2. Это с запасом лезет в 32хбитный int.
jcxz
Цитата(Rst7 @ Oct 22 2017, 12:14) *
Потому что даже большой memmove (в данной ситуации худший случай будет 511*(sizeof(int)+sizeof(*pkt))=2кБайт) может оказаться куда быстрее перебалансирования дерева.

1. Зачем хранить указатели на пакеты? Вместо них лучше индексы. Тогда один элемент таблицы поиска можно ужать до 32 бит:
log(10000)/log(2)+8+9 = 31бит
2. При каждом добавлении нового пакета, будет удаляться из массива один из пришедших ранее.
Алгоритм выбора удаляемого элемента ТС не привёл, предположим что это - самый старый из записанных пакетов.
Тогда добавление нового элемента - это просто кольцевой буфер пакетов в массиве хранения пакетов.
Плюс - необходим ещё один массив для обратного преобразования "индекс пакета" -> ID1/ID2 (для поиска позиции удаляемого пакета в таблице поиска).
А операция memmove() для таблицы поиска будет выполняться для участка: от добавляемого элемента до удаляемого элемента.

Цитата(Jenya7 @ Oct 22 2017, 12:20) *
переберите все сочитания 0-10000 и 0-255. Уж не помню, факториал по моему дает результат но таблица получиться громадная.

Зачем? wacko.gif
Jenya7
Цитата(Rst7 @ Oct 22 2017, 14:28) *
Вы не поняли. Не надо хранить таблицу размером 10000*256. Нужен лишь всего массив структур {int key; PKT *p;} размером в 512 элементов. Если этот массив хранить по возрастанию key (или убыванию), то поиск элемента в нем потребует только 9 сравнений. key - это id1*256+id2, если что.



Для Ваших целей в качестве ключа вполне пойдет линейная комбинация id1 и id2. Т.к. диапазон id2 у Вас 0...255, то самый простой способ - key=id1*256+id2. Это с запасом лезет в 32хбитный int.

ааа. то есть сортировать массив по ключу и делать бинарный поиск?
Rst7
QUOTE
1. Зачем хранить указатели на пакеты? Вместо них лучше индексы. Тогда один элемент таблицы поиска можно ужать до 32 бит:
log(10000)/log(2)+8+9 = 31бит


В данном случае это O(1).

QUOTE
ааа. то есть сортировать массив по ключу и делать бинарный поиск?


Конечно.
Jenya7
Цитата(jcxz @ Oct 22 2017, 14:33) *
1. Зачем хранить указатели на пакеты? Вместо них лучше индексы. Тогда один элемент таблицы поиска можно ужать до 32 бит:
log(10000)/log(2)+8+9 = 31бит
2. При каждом добавлении нового пакета, будет удаляться из массива один из пришедших ранее.
Алгоритм выбора удаляемого элемента ТС не привёл, предположим что это - самый старый из записанных пакетов.
Тогда добавление нового элемента - это просто кольцевой буфер пакетов в массиве хранения пакетов.
Плюс - необходим ещё один массив для обратного преобразования "индекс пакета" -> ID1/ID2 (для поиска позиции удаляемого пакета в таблице поиска).
А операция memmove() для таблицы поиска будет выполняться для участка: от добавляемого элемента до удаляемого элемента.


Зачем? wacko.gif

допустим мы создали ID из двух полей. Я получил команду - редактируй элемент с этим ID. Я все равно в должен перебрать все элементы и найти искомый ID.
jcxz
Цитата(Jenya7 @ Oct 22 2017, 12:48) *
допустим мы создали ID из двух полей. Я получил команду - редактируй элемент с этим ID. Я все равно в должен перебрать все элементы и найти искомый ID.

Нет. Вам тут уже несколько раз сказали: максимум потребуется 9 шагов цикла поиска.
Гуглите "поиск методом последовательного приближения" или "бинарный поиск".
Jenya7
Цитата(Rst7 @ Oct 22 2017, 14:36) *
В данном случае это O(1).

Конечно.

Допустим у меня массив с ID 3 5 7 13 25 178 1355. Пришел ID 18. Я должен вставить его в свободное место и потом сортировать весь массив? А при удалении элемента сдвинуть все элементы влево?
Это займет много время.
Rst7
QUOTE
Допустим у меня массив с ID 3 5 7 13 25 178 1355. Пришел ID 18. Я должен вставить его в свободное место и потом сортировать весь массив? А при удалении элемента сдвинуть все элементы влево?
Это займет много время.


В данном случае за 3 сравнения (бинарным поиском) Вы находите место для вставки элемента с ID 18 (между 13 и 25). После чего Вам его просто нужно вставить (копирование трех элементов плюс запись нового). Массив остается отсортированным.
jcxz
Цитата(Jenya7 @ Oct 22 2017, 12:52) *
Допустим у меня массив с ID 3 5 7 13 25 178 1355. Пришел ID 18. Я должен вставить его в свободное место и потом сортировать весь массив? А при удалении элемента сдвинуть все элементы влево?

Не в свободное место, а раздвинув существующие. И не все надо сдвигать, а от позиции нового пришедшего, до позиции удаляемого.

Цитата(Rst7 @ Oct 22 2017, 12:59) *
В данном случае за 3 сравнения (бинарным поиском) Вы находите место для вставки элемента с ID 18 (между 13 и 25). После чего Вам его просто нужно вставить (копирование трех элементов плюс запись нового). Массив остается отсортированным.

Исходить надо из случая заполненности всего массива (имеются все 512 кадров). И при старте делать инициализацию, заполнив первоначально массив недопустимыми индексами (с ID1 > 10000 например).
Rst7
QUOTE
Исходить надо из случая заполненности всего массива (имеется все 512 кадров). И при старте делать инициализацию, заполнив первоначально массив недопустимыми индексами (с ID1 > 10000 например).


В данном случае я показываю на примере ТСа. "Допустим у меня массив".
k155la3
Цитата(Jenya7 @ Oct 22 2017, 12:48) *
. . .Я все равно в должен перебрать все элементы и найти искомый ID.

Укладывайте пакеты при приеме в связный упорядоченный (сортировка по требуемому полю) список.
При "укладке" одновременно ведите индексный файл, но не "в сплошную" а по блокам в списке (10-20 пакетов в блоке)
чтобы размер этого индекса был приемлем.
Грубый поиск - по индексному файлу / массиву.
Точный - внутри блока по списку.

Jenya7
Цитата(Rst7 @ Oct 22 2017, 14:59) *
В данном случае за 3 сравнения (бинарным поиском) Вы находите место для вставки элемента с ID 18 (между 13 и 25). После чего Вам его просто нужно вставить (копирование трех элементов плюс запись нового). Массив остается отсортированным.

копирование трех элементов плюс запись нового не получиться - таки надо раздвинуть.

Цитата(jcxz @ Oct 22 2017, 15:04) *
Не в свободное место, а раздвинув существующие. И не все надо сдвигать, а от позиции нового пришедшего, до позиции удаляемого.


Исходить надо из случая заполненности всего массива (имеется все 512 кадров). И при старте делать инициализацию, заполнив первоначально массив недопустимыми индексами (с ID1 > 10000 например).

то есть сдвинуть все элементы вправо от искомого. а при удалении все элементы влево от искомого.

наверно это все равно будет быстрее чем с несортированным массивом.
Rst7
А вообще-то для полной универсальности топикстартеру надо сюда - https://ru.wikipedia.org/wiki/%D0%9A%D1%80%...%B5%D0%B2%D0%BE

QUOTE
копирование трех элементов плюс запись нового не получиться - таки надо раздвинуть.


Вы прикалываетесь? В конкретно данном случае раздвижка и есть копирование трех элементов.
Jenya7
Цитата(Rst7 @ Oct 22 2017, 15:09) *
А вообще-то для полной универсальности топикстартеру надо сюда - https://ru.wikipedia.org/wiki/%D0%9A%D1%80%...%B5%D0%B2%D0%BE



Вы прикалываетесь? В конкретно данном случае раздвижка и есть копирование трех элементов.

это как? допустим есть элементы 3 5 7 9. я хочу вставить 6. он встанет на место 7. а семь куда встанет?
jcxz
Цитата(Jenya7 @ Oct 22 2017, 13:07) *
то есть сдвинуть все элементы вправо от искомого. а при удалении все элементы влево от искомого.

Я уже несколько раз написал - это можно сделать за одну операцию memmove(): сдвиг элементов в массиве поиска от добавляемого до удаляемого. Всего одна memmove.
Jenya7
Цитата(jcxz @ Oct 22 2017, 15:18) *
Я уже несколько раз написал - это можно сделать за одну операцию memmove(): сдвиг элементов в массиве поиска от добавляемого до удаляемого. Всего одна memmove.

но сама функция memmove внутри наверняка сдвигает N элементов. чудес не бывает.
k155la3
Цитата(jcxz @ Oct 22 2017, 13:18) *
. . . . это можно сделать за одну операцию memmove(): сдвиг элементов в массиве поиска от добавляемого до удаляемого. Всего одна memmove.

Это зависит от платформы ? - в смысле содержимого memmove() - аппаратная или программная реализация пересылки ?
Jenya7
Цитата(k155la3 @ Oct 22 2017, 15:32) *
Это зависит от платформы ? - в смысле содержимого memmove() - аппаратная или программная реализация пересылки ?

memmove() применяется к массиву в РАМ. Тут уж какя бы ни была платформа а функция должна взять каждый элемент и сдвинуть.
Rst7
QUOTE (Jenya7 @ Oct 22 2017, 13:16) *
это как? допустим есть элементы 3 5 7 9. я хочу вставить 6. он встанет на место 7. а семь куда встанет?


Еще раз.


CODE
#define N (5)

int a[N];

a[0]=3;
a[1]=5;
a[2]=7;
a[3]=9;

i=2; //В эту позицию надо вставить элемент

memmove(a+(i+1),a+i,sizeof(int)*(N-1-i)); //Сдвиг элементов 2,3 на позиции 3,4 - копирование a[2],a[3] в a[3],a[4]
a[i]=6;


После этого массив имеет вид 3,5,6,7,9.

memmove в большинстве случаев - это быстро. Но надо проверять, что конкретная библиотечная реализация действительно оптимальна.
Jenya7
Цитата(Rst7 @ Oct 22 2017, 15:47) *
Еще раз.


Код
#define N (5)

int a[N];

a[0]=3;
a[1]=5;
a[2]=7;
a[3]=9;

i=2; //В эту позицию надо вставить элемент

memmove(a+(i+1),a+i,sizeof(int)*(N-1-i)); //Сдвиг элементов 2,3 на позиции 3,4 - копирование a[2],a[3] в a[3],a[4]
a[i]=6;


После этого массив имеет вид 3,5,6,7,9.

memmove в большинстве случаев - это быстро. Но надо проверять, что конкретная библиотечная реализация действительно оптимальна.

да но внутри функции memmove - она все равно сдвинет N элементов. она ж не волшебница.
а я понял. ну вот в этом вопрос - насколько это оптимально. получим ли мы выйгрыш в результате всех этих телодвижений.

Вставка элемента - допустим случай *как всегда* - memmove не оптимальна - сдвиг N элементов. Удаление - сдвиг N элементов. Это сопоставимо с перебором элементов в форе.
Идем дальше. Массив пустой. Пришел первый элемент 100. Пришел элемент 90 - сдвинь вправо, вставь элемент. Пришел элемент 80 - сдвинь вправо, вставь элемент.
И так далее.
И все таки это будет быстрее простого перебора?

Посмотрел красно-черное дерево. пишут конечно красиво. маслом. вопрос так ли он быстЁр как кажется.
Rst7
QUOTE
а я понял. ну вот в этом вопрос - насколько это оптимально. получим ли мы выйгрыш в результате всех этих телодвижений.


Ну смотрите. Поиск будет занимать 9 сравнений. Считайте, что это бесплатно. Теперь memmove. Ну при хорошей реализации для ARM он примерно два байта за такт процессора пересылает (ну чуть меньше, чем два, но сейчас это пофиг). Итого максимум будет 8*512=4к/2=2000 тактов. Ну пусть будет среднепотолочная тактовая в 100МГц, т.е. 20мкс. Да даже, если и один байт на такт, все равно 40мкс. Много или мало - решать Вам.

QUOTE
Это сопоставимо с перебором элементов в форе.


memmove куда быстрее, чем перебор элементов в цикле.
jcxz
Цитата(k155la3 @ Oct 22 2017, 13:32) *
Это зависит от платформы ? - в смысле содержимого memmove() - аппаратная или программная реализация пересылки ?

Я говорю о том, что не нужно дважды вызывать memmove(): сначала для удаления старой записи из массива поиска (и сжатия массива), а потом для раздвижки этого массива и вставки нового значения. Достаточно одного вызова memmove() для диапазона элементов от удаляемого до вставляемого.

Цитата(Jenya7 @ Oct 22 2017, 13:39) *
memmove() применяется к массиву в РАМ. Тут уж какя бы ни была платформа а функция должна взять каждый элемент и сдвинуть.

Если разговор о платформе Cortex-M и IAR, то внутри библиотечной memcpy() (и думаю что и memmove() тоже), копирование может идти с использованием нескольких регистров процессора (читается-пишется сразу по несколько 32-битных слов). См. дизасм.

Цитата(Rst7 @ Oct 22 2017, 13:59) *
Ну смотрите. Поиск будет занимать 9 сравнений. Считайте, что это бесплатно. Теперь memmove. Ну при хорошей реализации для ARM он примерно два байта за такт процессора пересылает (ну чуть меньше, чем два, но сейчас это пофиг).

Да ладно! Какой компилятор? IAR-овский memcpy() может использовать до 4х или даже 8и регистров (точно не помню) процессора для копирования.
Посчитайте сколько это байт. Конечно он предварительно смотрит на размер пересылки и, в зависимости от него, выбирает тот или иной цикл копирования.
Побайтно будет для ОЧЕНЬ маленьких размеров.
Rst7
QUOTE
Да ладно! Какой компилятор? IAR-овский memcpy() может использовать до 4х или даже 8и регистров (точно не помню) процессора для копирования.
Посчитайте сколько это байт. Конечно он предварительно смотрит на размер пересылки и, в зависимости от него, выбирает тот или иной цикл копирования.
Побайтно будет для ОЧЕНЬ маленьких размеров.


Вы не поняли. Комбинация из LDM и STM занимает 1+N+1+N тактов, где N - количество регистров, по 4 байта на регистр. Грубо говоря 2N тактов на 4N байт. Итого за один такт пересылается 2 байта. На самом деле ситуация хуже из-за накладных расходов.
Jenya7
Rst7, jcxz.
Большое вам спасибо. Сделаю так.
Вообще это пишется под Colibri PXA320 на vxWorks. Тактовая там 104 мега, что удивительно, может удвою на PLL, не знаю, еще не смотрел. Но что хорошо много РАМ. Поэтому думал замутить базу данных раз место позволяет, но вижу мы и так хорошо справляемся. sm.gif
jcxz
Цитата(Rst7 @ Oct 22 2017, 14:22) *
Итого за один такт пересылается 2 байта. На самом деле ситуация хуже из-за накладных расходов.

Ок. Итого в случае ТСа:
имеем среднюю длину пересылки внутри массива поиска при добавлении нового кадра == 512*4/2 байт.
Или 512*4/2/2=512 тактов. Ну немного больше (из-за тактов декодирования LDM/STM, счётчиков цикла и команд перехода), пускай даже в 1.5 раза. Но всё равно это == несколько мкс на современном CM3/4.
Rst7
QUOTE (Jenya7 @ Oct 22 2017, 13:49) *
Посмотрел красно-черное дерево. пишут конечно красиво. маслом. вопрос так ли он быстЁр как кажется.


Ну если реализация вменяема - то быстро. Худшие результаты там гарантированы, они все O(log n). Другое дело, что для небольших массивов (ну как у Вас, 512 элементов) всякие накладные расходы на дерево могут превысить по времени хорошо оптимизированный бинарный поиск плюс memmove.
Jenya7
Цитата(Rst7 @ Oct 22 2017, 16:33) *
Ну если реализация вменяема - то быстро. Худшие результаты там гарантированы, они все O(log n). Другое дело, что для небольших массивов (ну как у Вас, 512 элементов) всякие накладные расходы на дерево могут превысить по времени хорошо оптимизированный бинарный поиск плюс memmove.

я понял. 512 может превратиться в пару тысяч, это еще TBD. вы говорите на больших размерах можно подумать о красно-черном дереве?
Rst7
QUOTE
вы говорите на больших размерах можно подумать о красно-черном дереве?


Даже не можно, а нужно. Ну вот мне кажется, что как раз 512 - вот это близко к пределу, за которым дерево будет выгоднее.
Jenya7
Цитата(Rst7 @ Oct 22 2017, 16:41) *
Даже не можно, а нужно. Ну вот мне кажется, что как раз 512 - вот это близко к пределу, за которым дерево будет выгоднее.

спасибо. так и сделаю.
Jenya7
хотел уточнить такой вопрос
для вставки
Код
memmove(a+(i+1), a+i, sizeof(int)*(N-1-i));

тогда для удаления так?
Код
memmove(a+i, a+(i+1), sizeof(int)*(N-1-i));

и потом почему sizeof(int)? у меня массив чаров. наверно надо sizeof(char)

и вот еще такой вопрос
в примерах выше мы предполагаем, что а это линейный массив.
но у меня он определен так
Код
typedef struct А_S
{
    int id;
    char message[128];
}А;

А а[512];


получается я должен добавить отступ?
Код
memmove( a+(i*sizeof(A)+1),  a+(i*sizeof(A)),  sizeof(int)*(N-1-i));
Rst7
QUOTE
получается я должен добавить отступ?


Нет. Надо так
CODE
memmove( a+(i+1),  a+i,  sizeof(A)*(N-1-i));
Jenya7
Цитата(Rst7 @ Oct 23 2017, 19:16) *
Нет. Надо так
Код
memmove( a+(i+1),  a+i,  sizeof(A)*(N-1-i));

понял. спасибо.

ммм...и все таки. допустим есть три злемента N элеметов
a[0].id = 3;
a[1].id = 7;
a[2].id = 11;
пришел пакет с id = 10 - его надо вставить на индекс 2. но а+2 не будет адресом элемента a[2].
Rst7
QUOTE
но а+2 не будет адресом элемента a[2].


Что значит не будет? Вы бы почитали про адресную арифметику в Си, для начала.

&(a[2])==a+2, если что.
Jenya7
Цитата(Rst7 @ Oct 23 2017, 20:04) *
Что значит не будет? Вы бы почитали про адресную арифметику в Си, для начала.

&(a[2])==a+2, если что.

ой. что то я туплю. вы правы.

ну вот я тут накропал. уж не знаю...
Код
#define MESSAGE_ARR_SIZE 128

typedef struct TEST_MESSAGE_S
{
    int id;
    char data[20];
}TEST_MESSAGE;

TEST_MESSAGE messages[MESSAGE_ARR_SIZE8];

int found;
int glob_pos;

int BinarySearch(TEST_MESSAGE a[], int pos, int key, int *found)
{
    int first = 0;
    int last = pos;
    int mid;
    
    if (pos == 0)  //empty array
    {
        *found = 0;
        return 0;
    }
    else if (a[0].id > key)
    {
        *found = 0;
        return 0;
    }
    else if (a[pos - 1].id < key)
    {
        *found = 0;
        return pos;
    }
    
    while (first < last)
    {
        mid = first + (last - first) / 2;

        if (key <= a[mid].id)
            last = mid;
        else
            first = mid + 1;
    }

    if (a[last].id == key)
    {
        *found = 1;
        return last;
    }
    else
    {
                *found = 0;
        return last;
    }
}

void InsertElement(int id, char msg[])
{
    int idx;
    
    idx = BinarySearch(messages, glob_pos, id, &found);
    
    if (found)  //command NEW but the element exists - issue UPDATE
    {
        UpdateElement(idx, msg);
    }
    else //element not found - add one
    {
        memmove(messages+(idx+1), messages+idx, sizeof(TEST_MESSAGE)*glob_pos-1-idx);
        messages[idx].id = id;
        memcpy(messages[idx].data,  msg, sizeof(msg);

        
       if (glob_pos < MESSAGE_ARR_SIZE)
           glob_pos++;
    }
}

void DeleteElement(int id)
{
     int idx;
    
    idx = BinarySearch(messages, glob_pos, id, &found);
    
    if (found)
    {
       memmove(messages+idx, messages+(idx+1), sizeof(TEST_MESSAGE)*glob_pos-1-idx);
      
       if (glob_pos > 0)
           glob_pos--;
    }
}
XVR
Советую отделить id от data и хранить id+индекс в массив data в отсортированном массиве, а сами data в отдельном кольцевом буфере (или пуле). Тогда при вставках/удалениях не надо будет по 20 лишних байтов на элемент таскать вперед назад

Jenya7
Цитата(XVR @ Oct 24 2017, 02:16) *
Советую отделить id от data и хранить id+индекс в массив data в отсортированном массиве, а сами data в отдельном кольцевом буфере (или пуле). Тогда при вставках/удалениях не надо будет по 20 лишних байтов на элемент таскать вперед назад

в data я копирую пришедший пакет. а id просто чтоб знать какой пакет пришел. у пришедшего пакета тоже есть id. я их сравниваю.
индекс пакета в массиве может поменяться при вставке или удалении.
но id в принципе я зря таскаю вперед назад.
ViKo
Высказываю идею. Пока пакетов меньше 1024 (чисто психологический порог), я бы искал нужный индекс простым перебором. А в свободное время сортировал бы пакеты. И тогда при поиске можно было бы искать с начала или конца, в зависимости от номера пакета. Находились быстрее бы.
А можно искать не от начала или конца, а сразу прыгать в предполагаемую позицию, и от нее плясать в обе стороны.
Jenya7
Результаты такие. При добавлении элемента я вылетал с исключением
Цитата
Memory access error: Trying to write outside mapped memory at address 0x2000a000 when PC is 0x8001ef4. Check your memory configuration.

я поменял
Код
memmove(messages+(idx+1), messages+idx, sizeof(TEST_MESSAGE)*glob_pos-1-idx);

на
Код
memmove(messages+(idx+1), messages+idx, sizeof(TEST_MESSAGE)*glob_pos-idx);

то есть иместо sizeof(TEST_MESSAGE)*glob_pos-1-idx) - sizeof(TEST_MESSAGE)*glob_pos-idx)
и элементы начали добавляться.
но что странно. я инициализирую пришедший пакет - байт0 - ИД, байт1 - команда (1=вставка), и для проверки границ байт18 = 7, байт19 = 8.
После вставки я вижу байт0 = ИД, байт1 = 1 а байт18, байт19 - нули. Это memmove нам воду мутит или у меня где то ошибка?

Цитата(ViKo @ Oct 24 2017, 12:43) *
Высказываю идею. Пока пакетов меньше 1024 (чисто психологический порог), я бы искал нужный индекс простым перебором. А в свободное время сортировал бы пакеты. И тогда при поиске можно было бы искать с начала или конца, в зависимости от номера пакета. Находились быстрее бы.

так я при поиске заодно и сортирую вставкой.
skripach
Цитата(Jenya7 @ Oct 22 2017, 11:54) *
массив 512 пакетов.
худший случай - каждую милисекунду поэтому время поиска элемента критично.

У вас там PIC 12 или at89c2081 ? За одну миллисекунду можно до канадской границы успеть добежать. laughing.gif
ViKo
Цитата(Jenya7 @ Oct 24 2017, 10:44) *
так я при поиске заодно и сортирую вставкой.

Получается и поиск и сортировка. Одно из них лишнее. rolleyes.gif
Я предлагаю сортировать в свободное от досуга время. Если такое имеется.
Jenya7
Нашел проблемку. Функция вставки в причесанном варианте выглядит так
Код
void InsertElement(int id, char *msg)
{
    int idx;
    int size;
    
    idx = BinarySearch(messages, glob_pos, id, &found);
    
    if (found)  //command NEW but the element exists - issue UPDATE
    {
        UpdateElement(idx, msg);
    }
    else //element not found - add one
    {
        memmove(messages+(idx+1), messages+idx, sizeof(TEST_MESSAGE)*(glob_pos-idx));   //glob_pos-1-idx
        
        messages[idx].id = id;

        size = sizeof(msg);
        memcpy(messages[idx].data, msg, size);
        
      if (glob_pos < MESSAGE_ARR_SIZE)
        glob_pos++;
    }
}

sizeof(msg) вычисляется как 4. sizeof не принимает указатель? это что размер указателя? но почему тогда 4?

а. ну да. что это я.
Rst7
Ну правильно вот так

CODE
memcpy(messages[idx].data, msg, sizeof(messages[0].data));


Но все же, это все не совсем то, о чем говорили все предыдущие посты. Вы носите весь массив вместе с данными для вставки/удаления, а надо только указатели.
Jenya7
Цитата(Rst7 @ Oct 24 2017, 15:09) *
Ну правильно вот так

Код
memcpy(messages[idx].data, msg, sizeof(messages[0].data));


Но все же, это все не совсем то, о чем говорили все предыдущие посты. Вы носите весь массив вместе с данными для вставки/удаления, а надо только указатели.

не совсем понимаю. memmove переносит из адреса в адрес поэлементно. или я что то не понимаю?
Rst7
QUOTE
не совсем понимаю. memmove переносит из адреса в адрес поэлементно. или я что то не понимаю?


Вы переносите структуру размером int+char[20], что для 32хбитной архитектуры будет 24 байта. И таких может быть аж столько, сколько размер массива. На самом деле надо переносить структуру int+pkt*, что есть всего 8 байт, в 3 раза меньше. Но для этого еще надо организовать очередь пустых элементов (для добавления нового/удаления). Очередь эту вполне можно организовать прямо на месте тел сообщений.

Должно быть как-то так
CODE
#define MESSAGE_ARR_SIZE 128

typedef struct TEST_MESSAGE
{
union
{
char data[20];
struct TEST_MESSAGE *next;
};
}TEST_MESSAGE;


typedef struct
{
int id;
TEST_MESSAGE *p;
}TEST_MESSAGE_P;

TEST_MESSAGE *MsgFreeQ;

TEST_MESSAGE messages[MESSAGE_ARR_SIZE];
TEST_MESSAGE_P msg_p[MESSAGE_ARR_SIZE];


int found;
int glob_pos;

int BinarySearch(TEST_MESSAGE_P *a, int pos, int key, int *found)
{
int first = 0;
int last = pos;
int mid;

if (pos == 0) //empty array
{
*found = 0;
return 0;
}
else if (a[0].id > key)
{
*found = 0;
return 0;
}
else if (a[pos - 1].id < key)
{
*found = 0;
return pos;
}

while (first < last)
{
mid = first + (last - first) / 2;

if (key <= a[mid].id)
last = mid;
else
first = mid + 1;
}

if (a[last].id == key)
{
*found = 1;
return last;
}
else
{
*found = 0;
return last;
}
}

TEST_MESSAGE *AllocMessage(void)
{
TEST_MESSAGE *p=MsgFreeQ;
if (p) MsgFreeQ=p->next;
return p;
}


void FreeMessage(TEST_MESSAGE *p)
{
p->next=MsgFreeQ;
MsgFreeQ=p;
}

void InitMessageQ()
{
for(unsigned int i=0; i<MESSAGE_ARR_SIZE; i++)
{
FreeMessage(messages+i);
}
}

void InsertElement(int id, char msg[])
{
int idx;

idx = BinarySearch(msg_p, glob_pos, id, &found);

if (found) //command NEW but the element exists - issue UPDATE
{
UpdateElement(idx, msg);
}
else //element not found - add one
{
TEST_MESSAGE *nm=AllocMessage();
if (nm)
{
memmove(msg_p+(idx+1), msg_p+idx, sizeof(TEST_MESSAGE_P)*(glob_pos-1-idx));
msg_p[idx].id = id;
msg_p[idx].p=nm;
memcpy(nm->data, msg, sizeof(nm->data));
if (glob_pos < MESSAGE_ARR_SIZE) glob_pos++;
}
}
}

void DeleteElement(int id)
{
int idx;

idx = BinarySearch(msg_p, glob_pos, id, &found);

if (found)
{
FreeMessage(msg_p[idx]->p);
memmove(msg_p+idx, msg_p+(idx+1), sizeof(TEST_MESSAGE_P)*(glob_pos-1-idx));

if (glob_pos > 0)
glob_pos--;
}
}


Обратите внимание, что есть процедура InitMessageQ, ее надо вызвать в самом начале.
Jenya7
Цитата(Rst7 @ Oct 24 2017, 16:33) *
Вы переносите структуру размером int+char[20], что для 32хбитной архитектуры будет 24 байта. И таких может быть аж столько, сколько размер массива. На самом деле надо переносить структуру int+pkt*, что есть всего 8 байт, в 3 раза меньше. Но для этого еще надо организовать очередь пустых элементов (для добавления нового/удаления). Очередь эту вполне можно организовать прямо на месте тел сообщений.

ммм...а можете показать как. я не понимаю на что будет указывать pkt*.
Rst7
QUOTE
ммм...а можете показать как. я не понимаю на что будет указывать pkt*.


Обновите страничку, в предыдущем посте я уже Вам код написал.

На самом деле есть одно узкое место. Зависит от того, что Вам нужно делать при переполнении буфера пакетов. Я имею в виду функцию InsertElement. Возможно, она должна выглядеть чуть по другому
CODE
void InsertElement(int id, char msg[])
{
    int idx;
    
    idx = BinarySearch(msg_p, glob_pos, id, &found);
    
    if (found)  //command NEW but the element exists - issue UPDATE
    {
        UpdateElement(idx, msg);
    }
    else //element not found - add one
    {
        TEST_MESSAGE *nm=AllocMessage();
        if (!nm) nm=msg_p[MESSAGE_ARR_SIZE-1].p; //Если не удалось аллоцировать новый элемент - заменяем последний
        memmove(msg_p+(idx+1), msg_p+idx, sizeof(TEST_MESSAGE_P)*(glob_pos-1-idx));
        msg_p[idx].id = id;
        msg_p[idx].p=nm;
        memcpy(nm->data,  msg, sizeof(nm->data));
        if (glob_pos < MESSAGE_ARR_SIZE) glob_pos++;
    }
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.