Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Основы программирования. Борисенко

.pdf
Скачиваний:
1534
Добавлен:
09.04.2015
Размер:
9.31 Mб
Скачать

4.4.2. Стек

271

) {

onPush(line);

// Добавить число в стек

}else i f (strcmp(line, "pop") == 0) { onPop();

}else i f (strcmp(line, "clear") == 0) { onClear();

}else i f (strcmp(line, "show") == 0) { onShow();

}else i f (strcmp(line, "quit") == 0) {

 

 

break;

 

//

Завершить работу

 

} else {

 

// Неправильная команда =>

 

}

printHelp(); //

напечатать подсказку

}

 

 

 

 

 

0;

 

 

 

return

 

 

 

}

 

 

 

 

 

static

void

onAdd()

{

 

 

double

y, x;

 

{

 

i f

(st_size() < 2)

 

 

printf("Stack

depth < 2.\n");

}

return;

 

 

 

 

 

 

 

 

y = st_pop();

 

 

 

x = st_pop();

 

 

 

st_push(x + y);

 

 

 

display();

 

 

 

}

 

 

 

 

 

static

void

onSub()

{

 

 

double

y, x;

 

{

 

i f

(st_size() < 2)

 

 

printf("Stack

depth < 2.\n");

}

return;

 

 

 

 

 

 

 

 

y = st_pop();

 

 

 

x

= st_pop();

 

 

 

272

4.4. Простейшие структуры данных. Стек. Очередь

st_push(x - y); display();

}

 

 

 

 

 

 

 

static

 

void

onMul()

{

 

 

 

double

y, x;

 

 

 

 

i f

 

(st_size() < 2) {

<

2.\n");

 

 

printf("Stack

depth

}

 

return;

 

 

 

 

=

st_pop();

 

 

 

 

y

 

 

 

 

x = st_pop();

 

 

 

 

st_push(x * y);

 

 

 

 

display();

 

 

 

 

}

 

 

 

 

 

 

 

static

 

void

onDiv()

{

 

 

 

double

y, x;

 

 

 

 

i f

 

(st_size() < 2) {

 

 

 

 

printf("Stack

depth

<

2.\n");

}

 

return;

 

 

 

 

=

st_pop();

 

 

 

 

y

 

 

 

 

x = st_pop();

 

 

 

 

st_push(x / y);

 

 

 

 

display();

 

 

 

 

}

 

 

 

 

 

 

 

static void onPush(const char* line) { double x = a t o f ( l i n e ) ;

st_push(x);

}

static void onSin() { double x;

i f (st_empty()) { printf("Stack empty.\n");

4.4.2. Стек

273

return;

}

x = st_pop(); st_push(sin(x)); display();

}

static void onCos() { double x;

i f (st_empty()) { printf("Stack empty.\n"); return;

}

x = st_pop(); st_push(cos(x)); display();

}

static void onExp() { double x;

i f (st_empty()) { printf("Stack empty.\n"); return;

}

x = st_pop(); st_push(exp(x)); display();

}

static void onLog() { double x;

i f (st_empty()) { printf("Stack empty.\n"); return;

}

x = st_pop(); st_push(log(x));

274

4.4. Простейшие структуры данных. Стек. Очередь

d i s p l a y ( );

}

 

 

 

 

static

void

onSqrt()

{

 

double

x;

 

 

i f

(st_empty()) {

empty.\n");

 

printf("Stack

}

return;

 

 

(st_top() < 0.0)

{

i f

 

printf("Arg .

of

square root i s negative.\n");

 

return;

 

 

}

x = st_pop();

st_push(sqrt(x)); display();

}

static void onPop() { st_pop();

}

static

void

onClear()

{

s t _ c l e a r ( ) ;

 

}

 

 

 

static

void

display()

{

i f

(!st_empty())

{

}

printf("=/lf\n", st_top());

else

{

empty\n");

}

printf("stack

 

 

 

}

 

 

 

static

void

onShow()

{

int d =

s t _ s i z e ( ) ;

printf("Depth of

stack = /d.", d);

4.4.2. Стек

 

 

 

 

 

 

 

275

i f

(d > 0)

Stack

elements:\n");

 

 

p r i n t f ( "

 

else

 

 

 

 

 

 

 

 

 

printf("\n");

 

 

 

 

 

 

for

(int i = 0; i < d;

 

{

 

 

}

p r i n t f ( "

/ l f \ n " ,

st_elementAt(i));

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

static

void

printHelp()

{

 

 

 

 

p r i n t f (

 

 

 

commands:\n"

 

 

"Stack Calculator

 

 

"

<number>

 

Push

а number i n stack\n"

 

"

+ » - » * » /

 

Ariphmetic

operations\n"

 

"

s i n , cos,

 

Calculate

a function\n"

 

"

exp, log,

 

\n"

 

 

 

 

 

"

sqrt

 

 

\n"

 

the stack

top\n"

 

"

=

 

 

Display

 

"

pop

 

 

Remove

the stack

top\n"

 

"

show

 

Show the

stack\n"

 

 

"

clear

 

Clear

the

stack\n"

);

"

quit

 

 

Terminate

the program\n"

 

 

 

 

 

 

 

 

 

}

// Конец файла "stcalc.cpp"

Пример работы программы "stcalc". Пусть нужно вычислить вы­ ражение

V 3 • 3 + 4 • 4

Запишем выражение, используя обратную польскую запись:

3, 3, *, 4, 4, *, sqrt

(через sqrt обозначается операция извлечения квадратного корня). Последовательно отдаем соответствующие команды стековому каль­ кулятору. При работе программы stcalc получается следующий диа¬ лог:

276

4.4. Простейшие структуры данных. Стек. Очередь

Stack Calculator commands:

<number>

Push а number i n stack

+ , -, *, /

Ariphmetic operations

sin, cos,

Calculate a function

exp, log,

 

sqrt

 

=Display the stack top

pop

Remove the stack top

show

Show the stack

clear

Clear the stack

quit

Terminate the program

3 3 *

 

=9.000000

 

4 4 *

 

=16.000000

 

+

 

=25.000000

 

sqrt

 

=5.000000

 

Обратная польская запись формул оказалась исключительно удобной при работе с компьютерами. Д л я вычислений используется стек, что позволяет работать с выражениями любой степени слож¬ ности. Реализация стекового вычислителя не представляет никакого труда. Имеется также простой алгоритм преобразования выражения из обычной записи, в которой знак операции указывается между ар¬ гументами, в ее обратную польскую запись. Все это привело к тому, что многие компиляторы языков высокого уровня используют обрат¬ ную польскую запись в качестве внутренней формы представления программы. Рассмотрим, к примеру, язык программирования Java. Как всякий объектно-ориентированный язык, он является интерпре­ тируемым, а не компилируемым языком. Это означает, что компи­ лятор Java преобразует исходную Java-программу не в машинные коды, а в промежуточный язык, предназначенный для выполнения (интерпретации) на специальной Java-машине. В случае Java этот промежуточный язык называют байткодом. Компилятор Java поме¬ щает байткод в файл с расширением ".class". Байткод представляет

4.4.2. Стек

277

собой, упрощенно говоря, обратную польскую запись Java-прогаммы, а Java-машина — стековый вычислитель.

Я з ык PostScript

Другой яркий пример использования обратной польской записи — это графический язык PostScript. Он предназначен для печати тек­ стов высокого качества на лазерных принтерах; он является стандар¬ том представления текстов типографского качества, не зависящим от конкретной модели принтера.

То, что PostScript — язык программирования, для многих людей, знакомых с типографским делом, но далеких от программирования, звучит непривычно. Общепринятое мнение, что компьютер работает с числами и в основном что-то вычисляет, не вполне верно. Не менее часто компьютерная программа работает с текстами и с изображени¬ ями. Текст, содержащийся в обычном текстовом файле, можно рас¬ сматривать с двух точек зрения. М о ж н о трактовать его просто как текст статьи или книги. Рассмотрим, однако, процесс печати текста на обычном (не графическом) принтере. Принтер соединен с ком¬ пьютером кабелем, и компьютер просто посылает через этот кабель один за другим символы, составляющие текст. В этом случае букву A , входящую в текст, следует рассматривать как команду, предписы­ вающую принтеру напечатать символ A в текущей точке страницы, используя текущий шрифт. После этого коодинату x текущей точки надо увеличить на ширину буквы A . С этой точки зрения весь текст можно трактовать как программу его собственной печати. В случае обычного текстового файла эта программа весьма примитивна, в ней,

к примеру, нет команд смены шрифтов, изменения текущей

позиции,

рисования линий и т.д. Понятно, что текст типографского

качества

не может быть представлен обычным текстовым файлом.

 

В случае использования языка PostScript файл, пересылаемый на PostScript-принтер, представляет собой программу печати текста. Язык PostScript имеет огромное количество возможностей, и вряд ли найдется много людей, владеющих им. Ч а щ е всего PostScript— программа создается другой программой обработки текста. Напри¬

мер,

PostScript—файл создается TJEX-ОМ для печати на

принтере.

(TgX

— это язык записи текстов, содержащих математические фор¬

мулы, созданный замечательным математиком и теоретиком

програм-

278

 

4.4. Простейшие структуры данных. Стек. Очередь

мирования Дональдом Кнутом, см. книгу [2]. Фактически TJ?X пред¬

ставляет

собой язык программирования. Д а н н а я

книга подготовлена

в ТХ'е

с использованием

макропакета L T E X 2 е . )

Текстовые процес­

соры,

такие, как Adobe Acrobat или M S Word,

также в случае пе­

чати

на

профессиональном

PostScript—принтере

преобразуют текст

в PostScript—программу. (Более точно, такое преобразование осу­ ществляется драйверами операционной системы.) PostScript—файлы очень удобны для распространения: поскольку это файлы в обычном текстовом формате, они будут напечатаны одинаково в любой стране независимо от национальных кодировок, операционных систем, на¬ личия шрифтов и т.п.

PostScript—программа представляет собой обратную польскую за¬ пись в том смысле, что всякая команда записывается после своих ар¬ гументов. При выполнении PostScript—программы используется стек. Рассмотрим для примера несложную программу, рисующую график функции y = sin(x). Вот какая картинка рисуется в результате вы¬ полнения этой программы:

(Подчеркнем особо, что все рисунки, содержащиеся в данном посо¬

бии, реализованы в виде PostScript—программ, написанных

вручную

без использования каких-либо графических редакторов.)

 

Н и ж е приведен полный текст PostScript—программы,

рисующей

график функции. Отметим сразу, что символ процента % использу¬ ется в языке PostScript в качестве комментария:

% Файл "func.ps"

% Рисование графика функции y = f(x)

% Перейти от пунктов (1/72 дюйма) к миллиметрам 2.83 2.83 scale

4.4.2. Стек

279

0.2 setlinewidth

% Установить

толщину

линии

% Нарисовать координатную ось X:

(1, 15)

1

15 moveto

%

переместиться

в точку

60

15

lineto

%

провести

линию

к точке

(60, 15)

 

 

 

%

Рисуем стрелку:

 

57

16

moveto

%

переместиться

в точку

(57, 16)

60

15

lineto

%

провести

линию

к точке

(60, 15)

57

14

lineto

%

провести

линию

к точке

(57, 14)

stroke

%

нарисовать построенные

линии

% Нарисовать координатную ось Y:

(30, 1)

30

1 moveto

%

переместиться

в точку

30

30

lineto

%

провести

линию

к точке

(30, 30)

 

 

 

%

Рисуем стрелку:

 

29

27

moveto

%

переместиться

в точку

(29, 27)

30

30

lineto

%

провести

линию

к точке

(30, 30)

31

27

lineto

%

провести

линию

к точке

(31, 27)

stroke

% нарисовать

построенные линии

%

Определение

функции

- 30)

* 0.2 * 180/Pi) + 15

%

f(x) = 5 * sin((x

%Дано: число x на вершине стека.

%Надо: заменить вершину стека на f ( x ) . /Func {

30 sub 0.2 mul 57.296 mul s i n 5 mul 15 add

}def

%Рисуем график функции

0.3

setlinewidth

% установить толщину

линии

2 2

Func moveto

% переместиться в точку (2, f(2))

2.5

0.5 58 { % цикл для x от 2.5

до 58

шаг 0.5

 

dup

%

удвоить

вершину

стека

 

 

Func

%

заменить

x в вершине стека на f(x)

 

lineto

%

провести

линию

к точке

(x, f(x) )

} fo r

% конец цикла

 

 

280

 

4. 4. Простейшие структуры данных. Стек. Очередь

stroke

% нарисовать построенные линии

/Times-Roman

findfont % загрузить шрифт Times-Roman

4 scalefont

% установить размер шрифта 4 мм

setfont

% установить

текущий шрифт

40

23 moveto

% переместиться в точку

(40, 23)

(y

= s i n x) show % напечатать

текст "y = s i n x"

% Надписи на осях координат

 

(59, 11)

59

11 moveto

% переместиться в точку

(x)

show

% напечатать

текст "x"

 

26

28 moveto

% переместиться в точку

(26, 28)

(y)

show

% напечатать

текст "y"

 

showpage

% напечатать

страницу

 

Разберем подробно некоторые элементы этой программы. В пер­ вой выполняемой строке устанавливается миллиметровая шкала:

2.83 2.83 scale

По умолчанию в языке PostScript единицей измерения является один пункт, или 1/72 дюйма. Всякий программист помнит, что один дюйм равен 25.4 миллиметра. Вычислим отношение одного миллиметра к одному пункту:

1 mm / 1 pt = 1 mm / (1/72)" =

= 1 mm / (25.4/72) mm = 2.834645

Таким образом, увеличивая масштаб в 2.83 раза, мы переходим от

пунктов к миллиметрам. Д л я изменения масштаба мы помещаем

в

стек два числа 2.83, соответствующих изменению масштабов по x

и

у. Затем выполняется команда scale (изменить масштаб). Со стека при этом снимаются два числа, и масштабы по x и по y изменяются.

Разные команды могут иметь различное число аргументов. На¬ пример, вторая строка устанавливает толщину линии.

0.2setlinewidth