Здравствуйте.
Анализируя свой код подробнее, стремясь выяснить, что и как работает, хотел бы получить у уважаемых адептов JASS разъяснение важного для меня вопроса о том, как две конструкции JASS обходятся с памятью.
Есть блок кода, который можно впихнуть в любую бибилотеку или область
globals
    unit array UnitIndexer // Конечно, даже по меркам vJASS, если написать UnitIndexer[размер_массива_ниже_8191], это будет синтаксический сахар, так как массивы в WarCraft III статические и меньше 8192 ячеек в памяти инициализировать не станут.
    integer Indexer_Index = 0
endglobals

function GetUnitIndex takes unit whichUnit returns integer
    // Знаю, что не самая оптимальная реализация, но задача этого кода - показать суть дела.
    local integer i = 0

    loop
        exitwhen i > Indexer_Index
        if UnitIndexer[i] == whichUnit then
            return i
        endif
        set i = i + 1
    endloop

    return -1
endfunction

function IsUnitIndexed takes unit whichUnit returns boolean
    return GetUnitIndex(whichUnit) >= 0
endfunction

function IndexNewUnit takes unit whichUnit returns nothing
    // Не стану показывать проверку на дубликаты и "защиту от дураков", чтобы не усложнять код.
    set UnitIndexer[Indexer_Index] = whichUnit
    set Indexer_Index = Indexer_Index + 1
endfunction
И есть другой блок кода - иной подход к реализации того же самого
globals
    group UnitIndexer = null
endglobals

function IsUnitIndexed takes unit whichUnit returns boolean
    return IsUnitInGroup(whichUnit,UnitIndexer)
endfunction

function IndexNewUnit takes unit whichUnit returns nothing
    if UnitIndexer == null then
        set UnitIndexer = CreateGroup()
    endif
    call GroupAddUnit(UnitIndexer,whichUnit)
endfunction
Какой способ лучше с точки зрения памяти?
С массивами - понятно, создаётся 8191 экземпляр для хранения ссылки на объект unit.
Группа видится мне динамическим массивом, который аллоцирует и деаллоцирует память по необходимости.
Расскажите мне, как на самом деле обстоит дело.
В ожидании ответа,
Singularity, 29.06.2017

Принятый ответ

Странное понимание механики. Не бывает универсального лучшего способа, потому и существуют разные способы для конкретных ситуаций.
А экономить байты и такты процессора, заранее пользуясь интерпретируемым скриптовым языком, это вообще моветон.
Разве массив в WarCraft III не предынициализирует 8192 ячейки памяти (по Вашей формуле, в моём случае он потребляет 8192*4=32768 байт, то есть 32Кб)? Он ведь не динамический.
Нет, он динамический. Исходный размер при создании - 1024. И расширяется на 1024 ячейки по мере доступа вплоть до максимальных 8192.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
30
7 лет назад
Отредактирован Clamp
0
nvc123, с чего бы это?

А, лол, да.

Подправил.
2
28
7 лет назад
2
твой вариант
Foo getFirstOf(Foo given) { 
	if (given.prev != 0) { 
		return getFirstOf(given.prev); 
	} 
	return given; 
} 
легко заменяется на
Foo getFirstOf(Foo given) { 
	Foo temp=given;
	while (temp.prev != 0) { 
			temp=temp.prev; 
	} 
	return temp; 
} 
что довольно легко воспринимается и не является перегруженным
рекурсия нужна в основном в операциях над деревьями и сетями
т.е. там где происходит ветвление
а список как и массив это "прямая дорога" и с ними лучше работать циклами
0
30
7 лет назад
0
nvc123, достаточно убедительно. Буду дома - закину другой кейс, но, скорее всего, уже в блог, чтобы не оффтопить.

Да, а что насчёт метода в самой структуре?
0
28
7 лет назад
0
многие люди в качестве примера того что такое рекурсия показывают факториал или списки т.к. их намного проще понять чем те же деревья
но при этом забывают упомянуть что это пример того что такое рекурсия
а не пример того в каких ситуациях надо использовать рекурсию
и потом есть толпы джуниоров которые не знают в каких ситуациях рекурсия оправдана
Clamp:
Да, а что насчёт метода в самой структуре?
с ним тоже самое
thistype getFirst() { 
	Foo temp=this;
	while (temp.prev != 0) { 
			temp=temp.prev; 
	} 
	return temp; 
} 
0
30
7 лет назад
Отредактирован Clamp
0
в каких ситуациях рекурсия оправдана
Тем не менее, не вижу ощутимого преимущества в решении через цикл, там растёт стак вызовов, здесь (офк не в wc, а в целом) растёт потребление памяти.
многие люди в качестве примера того что такое рекурсия
TBH, никогда не читал статей или примеров про рекурсию. Мне интересна алгоритмика (и то меньше, чем архитектура ПО), но специальность у меня совершенно не "программист", хоть джун, хоть не джун.

Предлагаю завершать офтоп, вечером в блоге закину другой пример, аж интересно.
1
28
7 лет назад
Отредактирован nvc123
1
Тем не менее, не вижу ощутимого преимущества в решении через цикл, там растёт стак вызовов, здесь (офк не в wc, а в целом) растёт потребление памяти.
потребление памяти растёт на фиксированную величину(сложность О(1), тратит 4/8 байт)
а стэк вызова забивается при каждом следующем элементе(сложность О(n), тратит n * 4/8 байт)
и размер стека как правило довольно мал
а если список хранится не в оперативной памяти и содержит несколько миллионов элементов то у тебя не хватит оперативки чтобы держать весь этот стек
а писать свою реализацию потоков хранящую стек вызовов на ж.д. только ради того чтобы работать с рекурсией не самая лучшая идея
главный + рекурсии в возврате на несколько шагов назад что используется в деревьях и подобных структурах (например прошлись по 1 ветки, вернулись к развилке и прошлись по другой)
например подсчитать количество файлов не являющихся папками в папке
class File{
	
	int countNoDirs(){
		return 1;
	}
}

class Dir extends File{ // папка наследуется от файла
	private List<File> files;
	
	int countNoDirs(){ // переопределённый метод
		int count=0;
		for(File f:files){
			count+=f.countNoDirs();
		}
		return count;
	}
}
сделать подобное без рекурсии тот ещё гемор
1
29
7 лет назад
Отредактирован Doc
1
Щас бы использовать рекурсию для прохода по массива в языке без поддержки хвостовой рекурсии и засирать стек вызовов ммм.
Плохо читал, это уже написали оказывается.
Рекурсия это просто использование стека вызовов для хранения стейта, ничего больше. Не нужно её использовать там где проще без нее обойтись.
0
30
7 лет назад
0
языке без поддержки хвостовой рекурсии
Си

для прохода по массива
Тащемта по списку =О
0
29
7 лет назад
0
нет никакой разницы, плиз.
void myForEach(Value[] values, Consumer<Value> action, int index) {
    if (values.length == index) {
        return;
    }

    action.accept(values[index]);
    myForEach(values, action, index + 1);
}
вместо того чтобы хранить index в локалке значение хранится в стеке вместе с values и action.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.