Очереди и двойные очереди в луа

Страницы: Пред. 1 ... 22 23 24 25 26
RSS
Очереди и двойные очереди в луа, Пример из книги Р.Е.
 
VPM, С ног на голову, говорите? Ну, давайте поставим на ноги: мой скрипт давно написан, отлажен, работает в боевом режиме прямо сейчас, тикеров у него на два порядка больше, чем у вас, никаких проблем ни с памятью, ни с быстродействием нет от слова "совсем", все глюки системного софта (по крайней мере, все известные мне) купированы, моё "частное решение" реализовано! Ваше же "общедоступное решение" НЕ реализовано и не будет реализовано НИКОГДА.
 
Владимир,  Я Вас поздравляю с отличным решением! Я ушел заниматься своим, а то действительно не соберу. НО ХОЧЕТСЯ ПОДНЯТЬ  новую тему?
 
----- lifo из двусвязной очереди и пример позволят вести себя как стек - обеспечивая LIFO-порядок.
Скрытый текст

Еще одна реализация стека, по сути это тоже самое что и в букваре только реализация в виде класса, просто удобней пользоваться., наследуется без проблем, легко дописать фифо. У себя делаю лифо  для контроля памяти, создавая динамические окна. Выкладываю может кому еще сгодится.
 
Цитата
Nikolay написал:
Открываете пример MA.lua, например расчет SMA, и видите использование массива sum равного длине периода.

Да нет, вроде, в sum хранятся значения по всем свечам:

Код
function F_SMA()
   local sum = {}
   local it = {p=0, l=0}
return function (I, P, VT, ds)
   if I == 1 then
      sum = {}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={p=I, l=it.l+1} end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      sum[Ip] = (sum[Ipp] or 0) + GetValueEX(it.p,VT,ds)
      if it.l >= P then
         return (sum[Ip] - (sum[Ippp] or 0)) / P
      end
   end
return nil
end
end
 
А, разобрался: функция Squeeze возвращает индекс в массиве "по кольцу" в пределах заданного периода.
 
Цитата
VPM написал:
-- Создание LIFO из двусвязанной очереди
table.insert / table.remove делают то же самое, только быстрее.
 
Цитата
VPM написал:
---- lifo из двусвязной очереди и пример позволят вести себя как стек - обеспечивая LIFO-порядок
Можно гораздо проще:
Код
local LIFO = {}
LIFO.__index = LIFO
function LIFO.new()
  return setmetatable({}, LIFO)
end
function LIFO:push(v)
  self[#self+1] = v
end
function LIFO:pop()
  local idx = #self
  if idx == 0 then return nil end
  local v = self[idx]
  self[idx] = nil
  return v
end
 
Если Вы про оптимизацию, то  согласен без спорно быстрее. Но иногда  просто нужен тупой код прямолинейный как стрела, для пользователей типа меня, просто что его можно было прочесть, и успокоится что все выполняется как надо. Здесь ключевое выполняется как надо? А разве нет?
 
Цитата
VPM написал:
Но иногда  просто нужен тупой код прямолинейный как стрела
Прямолинейный для LIFO - это работа с таблицей стандартными методами.
Поскольку у вас добавление и извлечение всегда с конца таблицы, то как функции table.insert / table.remove, так и обычное присваивание последнему элементу в таблице будет работать вполне себе быстро и понятно.
Зачем городить очередь с двумя индексами для LIFO - большая загадка  :shock:
 
Йцукен, Речь шла прежде всего про универсальность, какой еще подход дает возможность, из одного подхода создавать разные очереди? Тут удивляться не чему, одна базовая и делай из нее  под свою задачу что нужно. А если это модуль то и сколько нужно. Возможно инженерия кода и заслуживает замечаний, но речь идет о самом подходе. В Вашем примере меня сильно смущает вот этот момент self[idx] = nil дыр не будет? А если все в порядке, то почему бы нет, все на первый взгляд элегантно?
 
Цитата
VPM написал:
подход дает возможность, из одного подхода создавать разные очереди?
Не, ну если вам нужно одновременно для одной очереди и FIFO и LIFO, тогда да, очередь с двумя индексами более подходящая под эту задачу. Но нужно понимать, что нельзя в таком случае в разных потоках работать с одной стороны очереди. В разных потоках можно только FIFO: в одном потоке положил, в другом вытащил.
Но если используется для конкретной задачи LIFO, то не стоит усложнять. Достаточно классических методов работы с таблицами.

Цитата
VPM написал:
В Вашем примере меня сильно смущает вот этот момент self[idx] = nil дыр не будет?
Каких дыр? Мы вынули последний элемент таблицы, и присвоили ему значение nil. В таком случае оператор # работает корректно.
Но я просто привёл пример, как можно упростить ваш код, если вам "кровь из носу" нужно ООП.
А вообще для LIFO достаточно:
Код
tbl = {}         -- создать таблицу
tbl[#tbl+1] = v     -- добавить в конец таблицы
v = tbl[#tbl]       -- получить последний элемент таблицы
tbl[#tbl]           -- удалить последний элемент таблицы
Но вы это и без меня знаете  :wink:
 
Цитата
Йцукен написал:
Цитата
А вообще для LIFO достаточно:
Код
  tbl  =  {}          -- создать таблицу 
tbl[ # tbl +  1 ]  =  v      -- добавить в конец таблицы 
v  =  tbl[ # tbl]        -- получить последний элемент таблицы 
tbl[ # tbl]            -- удалить последний элемент таблицы   

tbl[ # tbl]            -- удалить последний элемент таблицы Как это удаляет?
=================
Так просто лишь у дилетантов.
---------------------
Посмотрите как реализован стек в VMLua.
==========================
Операции
Некоторые операции, которые можно производить со стеком:
  • Push — добавляет новый элемент в стек. practicum.yandex.ru
  • Pop — удаляет элемент, который находится сверху. practicum.yandex.ru
  • Peek (или Top) — показывает верхний элемент стека, но не убирает его. practicum.yandex.ru
  • Size — возвращает количество элементов, которые находятся в стеке. practicum.yandex.ru
СложностьВременная сложность всех основных операций стека, работающих по принципу LIFO, — O(1). Пространственная сложность — O(n), где n — количество элементов. Skyeng.ru
ПрименениеПринцип LIFO используется в разных областях, например:
  • Программирование — например, когда одна задача вызывает другую и нужно вернуться обратно после завершения. practicum.yandex.ru
  • История действий в браузере — каждый переход по ссылке сохраняется в стек, при нажатии «Назад» происходит pop, и открывается предыдущая страница. practicum.yandex.ru
  • Управление товарными запасами на складе — первыми отгружаются товары, поступившие на склад последними. Новая партия размещается поверх предыдущей, что упрощает процессы погрузки и разгрузки. skladolog.ru
Важно:
в некоторых языках и системах у стека фиксированный объём памяти, например, в низкоуровневых языках (C, C++).
В многопоточных приложениях доступ к стеку нужно контролировать — если два потока используют стек одновременно, могут возникнуть ошибки из-за конфликта при обращении к данным
========================================
Программировать тоже надо учиться.
 
Цитата
Йцукен написал:
tbl[#tbl] -- удалить последний элемент таблицы
Опечатался. Должно быть так:
Код
tbl[#tbl] = nil          -- удалить последний элемент таблицы

Но умные люди и так всё поняли, в отличие от недоделанного бота.
 
nikolz,  Вы правы, это классическая и очень правильная структура. Стек — идеальный выбор для хранения фиксированного числа последних значений (5, 20 и т.д.) благодаря дисциплине LIFO и операциям сложности O(1).

Но, если мы хотим реализовать стек в чистом Lua для QUIK, то не можем использовать встроенный stack, но можем создать его на основе таблицы. По чему ОПП удобно, таблица знает о себе все. Да можно быстрей, но архитектуру выбираем сами под задачу. Ведь так?

Для образного понимания смысла, мне нравятся проводить аналогии. В этом случае, можно сравнить 2 автомобиля. 1. 60 годов, для диагностики неисправностей которого требовался опытный механик. 2. современный авто где без подключения к компьютеру уже не разобраться. Так и использование мета таблиц в луа, это просто современный авто.
 
Цитата
Йцукен написал:
Но нужно понимать, что нельзя в таком случае в разных потоках работать с одной стороны очереди.
Если нужно использовать очередь LIFO в разных потоках, то лучше воспользоваться потокобезопасными функциями table.sinsert / table.sremove
 
Просто пример:

Код
-- Класс Stack (LIFO)
Stack = {}
Stack.__index = Stack

function Stack:new(max_size)
    local o = {
        elements = {},      -- таблица-хранилище
        max_size = max_size or 5,  -- по умолчанию храним 5 элементов
        count = 0
    }
    setmetatable(o, Stack)
    return o
end

-- Добавить элемент наверх (push)
function Stack:push(value)
    table.insert(self.elements, value)
    self.count = self.count + 1
    
    -- Если превышен максимальный размер, удаляем самый старый (снизу)
    if self.count > self.max_size then
        table.remove(self.elements, 1)  -- удаляем первый (самый старый)
        self.count = self.max_size
    end
end

-- Удалить и вернуть верхний элемент (pop)
function Stack:pop()
    if self.count == 0 then return nil end
    local value = table.remove(self.elements)  -- удаляем последний
    self.count = self.count - 1
    return value
end

-- Посмотреть верхний элемент без удаления (peek)
function Stack:peek()
    if self.count == 0 then return nil end
    return self.elements[self.count]
end

-- Получить все элементы в порядке от старого к новому (для отображения)
function Stack:get_all()
    return self.elements
end

-- Получить все элементы в обратном порядке (новые сверху)
function Stack:get_all_reversed()
    local rev = {}
    for i = self.count, 1, -1 do
        table.insert(rev, self.elements[i])
    end
    return rev
end

-- Текущий размер
function Stack:size()
    return self.count
end


Как использовать в скрипте. Вместо отдельных массивов и ручного управления размером создаём стеки:

Код
-- В начале скрипта, после конфигурации
local deltaP_stack = Stack:new(20)   -- для нормализации (20 значений)
local deltaQ_stack = Stack:new(20)

local c_stack = Stack:new(5)         -- для отображения последних 5 значений
local alpha_stack = Stack:new(5)
local signal_stack = Stack:new(5)

-- для отображения исходных данных (опционально)
local deltaP_display_stack = Stack:new(5)
local deltaQ_display_stack = Stack:new(5)
local deltaOI_display_stack = Stack:new(5)
local deltaNB_display_stack = Stack:new(5)
local deltaNA_display_stack = Stack:new(5)
Страницы: Пред. 1 ... 22 23 24 25 26
Читают тему
Наверх