Я раскрываю все скрытые комментарии с правильными решениями к позавчерашней задачке. Если хотите все еще решать ее самостоятельно, не заглядывайте в комментарии. Спасибо всем, кто решал. Первый, кто нашел оптимальное решение за O(N) времени и O(1) памяти -
ilyaraz.
Вот еще одна программистская задачка. Я когда-то знал ее решение и забыл, недавно с удовольствием решил снова. Эта задачка довольно хорошо известна, и в частности часто преподается на курсах продвинутых структур данных, и упоминается в учебниках. Так что многие наверняка ее знают - если вы знаете решение, то не пишите в комментариях. Для тех, кто не знает, это отличное упражнение для ума, по-моему.
Задача: требуется воплотить массив с дефолтным значением для всех элементов, т.е. структуру данных с тремя операциями: get(i), set(i, value) и setdefault(value). Любой вызов get() с индексом, который до сих пор ни разу не передавался set(), должен возвращать последнее выставленное дефолтное значение (или 0, если такого не было). Сложность в том, что все три операции: get, set и setdefault, должны занимать O(1) времени. При этом нельзя рассчитывать на то, что отведенная нам память имеет какой-либо специальный вид, например, заполнена нулями. Любая используемая память изначально содержит случайные байты, которые мы никак не можем контролировать.
Вот еще одна программистская задачка. Я когда-то знал ее решение и забыл, недавно с удовольствием решил снова. Эта задачка довольно хорошо известна, и в частности часто преподается на курсах продвинутых структур данных, и упоминается в учебниках. Так что многие наверняка ее знают - если вы знаете решение, то не пишите в комментариях. Для тех, кто не знает, это отличное упражнение для ума, по-моему.
Задача: требуется воплотить массив с дефолтным значением для всех элементов, т.е. структуру данных с тремя операциями: get(i), set(i, value) и setdefault(value). Любой вызов get() с индексом, который до сих пор ни разу не передавался set(), должен возвращать последнее выставленное дефолтное значение (или 0, если такого не было). Сложность в том, что все три операции: get, set и setdefault, должны занимать O(1) времени. При этом нельзя рассчитывать на то, что отведенная нам память имеет какой-либо специальный вид, например, заполнена нулями. Любая используемая память изначально содержит случайные байты, которые мы никак не можем контролировать.
no subject
Date: 2011-01-07 10:27 pm (UTC)А вот как эта функция реализована на самом деле (http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strpbrk.c;h=620cfab7f9616ef45e7e059481f2f5232ae27e1e;hb=16c2895feabae0962e0eba2b9164c6a83014bfe4#l30). Ой.
no subject
Date: 2011-01-09 09:20 pm (UTC)no subject
Date: 2011-01-10 09:07 am (UTC)Может быть, хитрая реализация и позволит получить какой-то небольшой выигрыш в скорости, но для этого придется как-то выделять 512 байт, а как? Из кучи слишком медленно. Для стека это нетривиальный размер. TLS? Э... нет, лучше уж наивная n*m реализация.
no subject
Date: 2011-01-10 11:07 am (UTC)no subject
Date: 2011-01-10 11:37 am (UTC)Полкилобайта тут, полкилобайта там, а контроллеры с пятью ножками и полутора регистрами кто поддерживать будет? Шутка.
«с битовой маской на 32 байта»
Я не уверен, что это оправдано в смысле производительности. Надо как-нибудь измерить на досуге.
На самом деле не в этом даже дело. Я нашел-таки в гугле вызовы strpbrk. В большинстве случаев там действительно несколько символов, редко — десяток, но это практически всегда константа, и чаще всего литерал. То есть там нужна битовая маска на 32 байта, которая заполняется один раз (возможно, во время компиляции) и больше не трогается. Можно и на 256 байт, и использовать разные ее биты для разных вызовов strpbrk, по типу функций/макросов «is*()» из ctype.h. Это точно будет быстрее всего.