S>Очевидно что e это внешняя по отношению к списку переменная.
Очевидно что е изначально это указатель на первый элемент списка.
А вашу фразу я не понял.
Здравствуйте, Muxa, Вы писали:
S>>Очевидно что e это внешняя по отношению к списку переменная. M>Очевидно что е изначально это указатель на первый элемент списка. M>А вашу фразу я не понял.
Очевидно что e изначально не относится к списку и e занимает дополнительную память, отличную от 0-я байт. Это противоречит вашему требованию, которое я процитировал в предыдущем сообщении.
S>Очевидно что e изначально не относится к списку и e занимает дополнительную память, отличную от 0-я байт.
... слово "дополнительно" везде выше в этой ветке какбэ намекаэ.
Здравствуйте, Muxa, Вы писали:
S>>Очевидно что e изначально не относится к списку и e занимает дополнительную память, отличную от 0-я байт. M>... слово "дополнительно" везде выше в этой ветке какбэ намекаэ.
Ну да, намекаэ на то, что эта дополнительная память не относится к памяти, отведенной под элементы списка.
Пройти по списку совсем без дополнительной памяти можно, но это будет деструктивное прохождение, т.к. как минимум одним элементом придется пожертвовать
S>Пройти по списку совсем без дополнительной памяти можно, но это будет деструктивное прохождение, т.к. как минимум одним элементом придется пожертвовать
да это понятно. у меня была идея "как бы сохранять" путь назад при помощи xor'ов где-либо (в next или value), что бы была возможность восстановить и "вернуться назад" по списку. но что-то ничего путного не придумалось.
Здравствуйте, Muxa, Вы писали:
M>это значит не используя дополнитольно ни одного байта (костантного значения дополнительной памяти). M>т.е. имея только список и работая тольо с ним.
Какие тогда операции над списком доступны?
У нас есть единственный регистр, в котором хранится адрес головного элемента.
И, видимо, есть процессор с набором инструкций, обходящихся ровно одним (вот этим самым) регистром.
Что это за инструкции?
// модель процессораint mem[];
int reg;
// операндыint& dst(bool m, bool r, int offset)
{
return m ? mem[ (r?reg:0)+offset ] : reg;
}
int src(bool m, bool r, int offset, int addend)
{
return m ? mem[(r?reg:0)+offset]+addend : r ? reg+addend : addend;
}
// возможна какая-нибудь двойная косвенностьint src2(bool r1, int a, bool r2, int b, int c) { return src(true,r2,src(true,r1,a,b),c)); }
// mem[mem[reg*r1+a]+reg*r2+b]+cint dst2(bool r1, int a, bool r2, int b) { return dst(true,r2,src(true,r1,a,b)); }
// mem[mem[reg*r1+a]+reg*r2+b]
// операцииvoid set(int& d, int s) { d = s; }
void add(int& d, int s) { d += s; }
void swap(int& d1, int& d2) { int t=d1; d1=d2; d2=t; }
int test(int s1, int s2) { return s1-s2; } // проверка на знак и ноль
Тогда поиск концевого узла, к примеру, выглядит так
Всё, что мы можем сделать — это исхитриться временно использовать содержимое узлов. И каким-то образом восстанавливать это содержимое...
Был бы хоть один ещё регистр...
К>Всё, что мы можем сделать — это исхитриться временно использовать содержимое узлов. И каким-то образом восстанавливать это содержимое...
все, я починил!
в общем исхитрился но уронить это очень просто. работает — вот и не трожь.
Здравствуйте, Muxa, Вы писали:
К>>Всё, что мы можем сделать — это исхитриться временно использовать содержимое узлов. И каким-то образом восстанавливать это содержимое... M>все, я починил! M>в общем исхитрился но уронить это очень просто. работает — вот и не трожь. M>
M> // первые 4 бита адреса используем для хранения информации необходимой для прохождения списка в обратном порядке
M> do {
M> ((list_elem *)(((int)e->next) & 0x00FFFFFF))->next = ...
M>}
S>Пишешь 4 бита, а используешь целый байт
да, да, да.
только подошел исправить, а тут уже подметили.
кстати, последние 2 бита адреса тоже можно приспособить, адреса-то выровнены по 4 байта.
On 15/08/10 21:18, Muxa wrote:
> все, я починил!
По-моему ты какой-то фигнёй страдаешь.
> }while(e->next != NULL&& ((int)((((list_elem *)(((int)e->next)& 0x00FFFFFF))->next))& 0x00FFFFFF) != NULL);
Вот это не удастся посчитать без промежуточного регистра.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ssp_alex, Вы писали:
_>На собеседовании задали задачку: _>есть односвязанный список, необходимо его очистить эффективно начиная с конца без привлечения доплонительных внешних ресурсов (например дополнительной памяти).
Короче говоря, единственное нормальное решение задачи — инвертировать список, после чего пришибить от начала к концу. O(n) времени O(1) памяти. Любые другие решения являются больными. И вот закидайте меня помидорами — лучшего решения не существует в силу устройства этого вашего мира.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
M>>предложи другой вариант без дополнительной (!!!!!!111!1) памяти. даже без О(1). MS>Товарищ! Твой вариант тоже не отвечает критерию "без O(1)", ибо исполняемый код тоже занимает память.
блин, да вы чо? сговорились все что ли?
>> }while(e->next != NULL&& ((int)((((list_elem *)(((int)e->next)& 0x00FFFFFF))->next))& 0x00FFFFFF) != NULL); .>Вот это не удастся посчитать без промежуточного регистра.
ммм, не вижу куда он (регистр) мог бы разходоваться.
Здравствуйте, Muxa, Вы писали:
>>> }while(e->next != NULL&& ((int)((((list_elem *)(((int)e->next)& 0x00FFFFFF))->next))& 0x00FFFFFF) != NULL); .>>Вот это не удастся посчитать без промежуточного регистра. M>ммм, не вижу куда он (регистр) мог бы разходоваться.
Для хранения результатов логических умножений, как минимум.
S>Для хранения результатов логических умножений, как минимум.
я думая это компилятор лишнего наворачивает.
посмотрим во что скомпилировалась эта строка кода:
Здравствуйте, Muxa, Вы писали:
S>>Для хранения результатов логических умножений, как минимум. M>я думая это компилятор лишнего наворачивает.
O(x) оценивает количество алгоритмических ячеек, а не число регистров на конкретной архитектуре. Потому дело не в компиляторе и не в том, используется ли [ecx]. Для того чтобы воспользоваться результатом логического умножения в абстрактной архитектуре, требуется этот результат получить и сохранить в некоторой ячейке (неважно, регистр, стек или куча).
скажи.
S>Для того чтобы воспользоваться результатом логического умножения в абстрактной архитектуре, требуется этот результат получить и сохранить в некоторой ячейке (неважно, регистр, стек или куча).
но ведь это может быть таже самая ячейка где у нас до этого хранился операнд.
(если операнд далее не нужен, мы можем его спокойно перетереть).
согласен?
скажи.
S>>Для того чтобы воспользоваться результатом логического умножения в абстрактной архитектуре, требуется этот результат получить и сохранить в некоторой ячейке (неважно, регистр, стек или куча). M>но ведь это может быть таже самая ячейка где у нас до этого хранился операнд. M>(если операнд далее не нужен, мы можем его спокойно перетереть). M>согласен?
Ты говоришь о некоторой конкретной архитектуре. А в общем случае ячейка под операнд могла и не выделяться.
Что же касается конкретной архитектуры, то ячейка под операнд — это уже дополнительная память по отношению к списку.
Хорош извращаться. Так академические задачи не решают.