Чтение онлайн

на главную - закладки

Жанры

Программист-прагматик. Путь от подмастерья к мастеру
Шрифт:

Ответ: Программа printTree использует приблизительно 1000 байт стекового пространства для буферной переменной. Для движения вниз по древовидной схеме она рекурсивно вызывает саму себя, и каждый вложенный вызов добавляет еще 1000 байт к стеку. Она также вызывает саму себя, когда добирается до вершин, но заканчивает работу сразу, как только обнаружит, что переданный указатель обнулен. Если глубина дерева равна D, то максимальный объем, необходимый стеку, составляет (грубо) 1000 x(D+ 1).

Сбалансированное двоичное дерево содержит вдвое больше элементов на каждом уровне. Дерево глубиной D содержит 1+2+4+8 +… +2^(D-1), или 2^D – 1 элементов. Следовательно, дереву, состоящему из миллиона элементов, будет необходимо [lg(1000001], или 20 уровней.

Поэтому мы рассчитываем, что наша подпрограмма будет использовать примерно 21000 байт стекового пространства.

Упражнение 36 из раздела "Скорость алгоритма"

Ответ: На ум приходит несколько процедур оптимизации. Программа printTree вызывает саму себя на вершинах дерева лишь для того, чтобы закончить работу при отсутствии потомков. Этот вызов увеличивает максимальную глубину стека примерно на 1000 байт. Можно также исключить рекурсию хвоста (второй рекурсивный вызов), хотя это и не будет затрагивать использование стека в наихудшем случае.

while (node) {

if (node->left) printTree(node->left);

getNodeAsString(node, buffer);

puts(buffer);

node = node->right;

}

Но самая большая выгода возникает при назначении одного-единственного буфера, доступ к которому осуществляется при всех обращениях к printTree. Если передать этот буфер в виде параметра для рекурсивных обращений, то будет назначено всего 1000 байт вне зависимости от глубины рекурсии.

void printTreePrivate(const Node *node, char *buffer) {

if (node) {

printTreePrivate(node->!eft, buffer);

getNodeAsStringfnode, buffer);

puts(buffer);

printTreePrivate(node->right, buffer);

}

}

void newPrintTree(const Node *node) {

char buffer[1000];

printTreePrivate(node, buffer);

)

Упражнение 37 из раздела "Скорость алгоритма"

Ответ: Это можно сделать двумя путями. Один из них заключается в том, чтобы перевернуть проблему с ног на голову. Если в массиве есть лишь один элемент, мы не осуществляем итерации в цикле. Каждая дополнительная итерация удваивает размер массива, в котором можно осуществлять поиск. Отсюда общая формула размера массива: n = 2^m, где m – число итераций. Если прологарифмировать обе части с основанием 2, получим выражение lg(n) = lg(2^m), которое из определения логарифма превращается в lg(n) =m.

Упражнение 38 из раздела "Реорганизация"

Ответ: Здесь мы могли бы предложить весьма умеренную реструктуризацию: убедитесь, что каждый тест выполняется лишь один раз, и сделайте все вычисления стандартными. Если выражение 2*basis (…)* 1.05 появляется в других местах программы, то, вероятно, его стоит сделать функцией. В данном случае мы этого делать не стали.

Мы добавили массив rate_lookup, инициализированный таким образом, что элементам, отличным от Texas, Ohio и Maine, присвоено значение 1. Этот подход облегчает добавление значений для других штатов в будущем. В зависимости от ожидаемой схемы использования мы могли бы сделать поле points также средством поиска в массиве.

rate = rate_lookup[state];

amt = base * rate;

calc = 2*basis(amt) + extra(amt)*1.05;

if (state == OHIO)

points = 2;

Упражнение 39 из раздела "Реорганизация"

Ответ: Когда вы видите, что кто-либо использует перечислимые типы (или эквивалентные им в языке Java), для того чтобы провести различие между вариантами некоего типа, во многих случаях вы можете улучшить программу за счет создания подклассов:

public class Shape {

private double size;

public Shape(double size) {

this.size = size;

}

public double getSize {return size;)

}

public class Square extends Shape {

public Square(double size) {

super(size);

}

public double area {

double size = getSize;

return size*size;

}

)

public class Circle extends Shape {

public Circle(double size) {

super(size);

}

public double area {

double size = getSize;

return Math.PI*size*size/4.0;

}

}

// efc…

Упражнение 40 из раздела "Реорганизация"

Ответ: Этот случай интересен. На первый взгляд, кажется разумным, что у окна должна быть ширина и высота. Однако стоит подумать о будущем. Представим, что мы хотим обеспечить поддержку окон произвольной формы (что будет весьма трудно, если класс Window обладает всей информацией о прямоугольниках и их свойствах).

Мы бы предложили абстрагировать форму окна из самого класса Window.

public abstract class Shape {

//...

public abstract boolean overlaps (Shape s);

public abstract int getArea;

}

public class Window {

private Shape shape;

public Window(Shape shape) {

this.shape = shape;

...

}

public void setShape(Shape shape) {

this.shape = shape;

...

}

public boolean overlaps(Window w) {

return shape.overlaps(w.shape);

}

public int getArea {

return shape.getArea;

}

}

Заметим, что в этом подходе мы предпочли делегирование созданию подклассов: окно не является «разновидностью» формы – окно «имеет» форму. Оно использует форму для выполнения своей работы. Вы убедитесь, что во многих случаях делегирование оказывается полезным для реорганизации.

Мы могли бы расширить этот пример, внедрив интерфейс Java, указывающий на методы, которые должны поддерживаться неким классом для поддержания функций формы. Эта удачная идея означает, что, когда вы расширяете принцип формы, компилятор предупредит вас о классах, которые вы затронули. Мы рекомендуем использовать интерфейсы подобным способом при делегировании всех функций какого-либо другого класса.

Поделиться:
Популярные книги

Личник

Валериев Игорь
3. Ермак
Фантастика:
альтернативная история
6.33
рейтинг книги
Личник

В лапах зверя

Зайцева Мария
1. Звериные повадки Симоновых
Любовные романы:
остросюжетные любовные романы
эро литература
5.00
рейтинг книги
В лапах зверя

Бояръ-Аниме. Газлайтер. Том 33

Володин Григорий Григорьевич
33. История Телепата
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Бояръ-Аниме. Газлайтер. Том 33

Портрет дьявола: Собрание мистических рассказов

Скотт Вальтер
Проза:
классическая проза
8.09
рейтинг книги
Портрет дьявола: Собрание мистических рассказов

Славка с улицы Герцена

Крапивин Владислав Петрович
Детские:
детская проза
детские приключения
7.00
рейтинг книги
Славка с улицы Герцена

Простолюдин

Рокотов Алексей
1. Путь князя
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Простолюдин

Перекрестки миров. Том 2

Джек из тени
2. Майор Барон
Фантастика:
боевая фантастика
рпг
фантастика: прочее
попаданцы
5.00
рейтинг книги
Перекрестки миров. Том 2

Хозяин теней 2

Демина Карина
2. Громов
Фантастика:
аниме
попаданцы
фэнтези
7.00
рейтинг книги
Хозяин теней 2

Белые погоны

Лисина Александра
3. Гибрид
Фантастика:
фэнтези
попаданцы
технофэнтези
аниме
5.00
рейтинг книги
Белые погоны

Несгибаемый граф. Тетралогия

Яманов Александр
Нет пророка в своем отечестве
Фантастика:
альтернативная история
фэнтези
5.00
рейтинг книги
Несгибаемый граф. Тетралогия

Чужак из ниоткуда 2

Евтушенко Алексей Анатольевич
2. Чужак из ниоткуда
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Чужак из ниоткуда 2

Некромант

Щепетнов Евгений Владимирович
4. Петр Синельников
Фантастика:
боевая фантастика
6.20
рейтинг книги
Некромант

Почем цветочек аленький?

Луганцева Татьяна Игоревна
Женщина-цунами
Детективы:
иронические детективы
7.88
рейтинг книги
Почем цветочек аленький?

Алые перья стрел

Крапивин Владислав Петрович
Детские:
детские приключения
8.58
рейтинг книги
Алые перья стрел