Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабы_по_проге_Берлин / Книги / учебное пособие ОАиП.pdf
Скачиваний:
49
Добавлен:
11.02.2015
Размер:
947 Кб
Скачать

{s3->l=s1->l;

s1->l=ss->l;

ss->l=s1;

 

}

 

ss=ss->l;

 

if(!s4) s4=s1;

//новая вершина стека

}

puts("Сортировка стека выполнена"); *s=s4;

}

Построение обратной польской записи

Одной из главных причин, лежащих в основе появления языков программирования высокого уровня, явились вычислительные задачи, требующие больших объёмов рутинных вычислений. Поэтому к языкам программирования предъявлялись требования максимального приближения формы записи вычислений к естественному языку математики. В этой связи одной из первых областей системного программирования сформировалось исследование способов трансляции выражений. Здесь получены многочисленные результаты, однако наибольшее распространение получил метод трансляции с помощью обратной польской записи, которую предложил польский математик Я.Лукашевич.

Арифметическое выражение вида: (A+B)*(C+D)-E

в форме обратной польской записи будет иметь вид: AB+CD+*E-

Характерные особенности этого выражения состоят в следовании символов операций за символами операндов и в отсутствии скобок.

Обратная польская запись обладает рядом замечательных свойств, которые превращают ее в идеальный промежуточный язык при трансляции. Вопервых, вычисление выражения, записанного в обратной польской записи, может проводиться путем однократного просмотра, что является весьма удобным при генерации объектного кода программ. Во-вторых, получение обратной польской записи из исходного выражения может осуществляться весьма просто на основе простого алгоритма, предложенного Дейкстрой. Для этого вводится понятие стекового приоритета операций(табл. 10.):

Таблица 10.

Операция

Приоритет

(

0

)

1

+ -

2

* /

3

Просматривается исходная строка символов слева направо, операнды переписываются в выходную строку, а знаки операций заносятся в стек на

основе следующих соображений:

а) если стек пуст, то операция из исходной строки переписывается в стек; б) операция выталкивает из стека все операции с большим или равным

приоритетом в выходную строку; в) если очередной символ из исходной строки есть открывающая скобка,

то он проталкивается в стек; г) закрывающая круглая скобка выталкивает все операции из стека до

ближайшей открывающей скобки, сами скобки в выходную строку не переписываются, а уничтожают друг друга.

Рассмотрим текст программы, выполняющей рассмотренные выше

действия.

 

 

#include<stdio.h>

 

 

#include<stdlib.h>

 

 

#include<conio.h>

 

 

struct st

// Описание элемента стека

{ char c;

 

 

st *next;

 

 

};

 

 

st *push(st *,char);

 

// занесение в стек

char pop(st **);

 

// чтение из стека

int PRIOR(char);

 

// возвращает приоритет операции

void main(void)

 

 

{

 

 

st *OPR=NULL;

 

// стек операций пуст

char in[80],out[80];

// входная и выходная строки

int k,point;

 

 

do

 

 

{puts("Введите выражение(в конце '='):"); fflush(stdin);

gets(in); // ввод арифметического выражения k=point=0;

while(in[k]!='\0' && in[k]!='=') // пока не дойдем до '='

{ if(in[k]==')')

// если очередной символ - ')'

{ while((OPR->c)!='(')

// то удаляем из стека в

 

out[point++]=pop(&OPR);

// выходную строку все знаки операций

 

 

// до открывающей скобки

}

pop(&OPR); // Удаляем из стека открывающую скобку

 

 

if(in[k]>='a' && in[k]<='z')

// если символ - буква ,то

out[point++]=in[k];

// заносим её в выходную строку

if(in[k]=='(')

// если очередной символ - '(' ,то

OPR=push(OPR,'(');

// заносим её в стек

if(in[k]=='+' || in[k]=='-' || in[k]=='/' || in[k]=='*')

{

// Если следующий символ - знак операции ,то все на-

//ходящиеся в стеке операции с большим или равным

//приоритетом переписываются в выходную строку while((OPR!=NULL)&&(PRIOR(OPR->c)>=PRIOR(in[k]))) out[point++]=pop(&OPR);

OPR=push(OPR,in[k]); // запись в стек новой операцию

}

 

 

k++;

// переход к следующему символу входной строки

}

 

 

while(OPR!=NULL)

// после рассмотрения всего выражения

out[point++]=pop(&OPR); // перезапись операции

out[point]='\0';

// из стека в выходную строку

printf("\n%s\n",out);

// и печатаем её

fflush(stdin); puts("\nПовторить(y/n)?");

} while(getch()!='n');

}

//push записывает в стек символ a, возвращает

//указатель на новую вершину стека

st *push(st *head,char a)

{st *PTR;

if(!(PTR=(st*) malloc(sizeof(*PTR))))

{puts("Нет памяти"); exit(-1);} PTR->c=a; //

PTR->next=head;

//

return PTR;

// PTR -новая вершина стека

}

//pop удаляет символ с вершины стека. Возвращает

//удаляемый символ. Изменяет указатель на вершину стека char pop(st **head)

{st *PTR; char a;

if(!(*head)) return '\0';//Если стек пуст, возвращаем \0

PTR=*head;

// в PTR - адрес вершины стека

a=PTR->c;

 

*head=PTR->next;

// Изменяем адрес вершины стека

free(PTR);

// Освобождение памяти

return a;

// Возврат символа с вершины стека

}

// Функция PRIOR возвращает приоритет арифм. операции int PRIOR(char a)

{switch(a)

{case '*':case '/':return 3; case '-':case '+':return 2; case '(':return 1;

} return 0;

}

Односвязный линейный список, очередь

Односвязный список (очередь) - такая упорядоченная структура данных, которые могут удаляться с одного ее конца (начало очереди ), а добавляются в другой ее конец (конец очереди).

Очередь организована по принципу FIFO - ”первый вошел - первый вышел”. Для очереди определены следующие операции:

-проверка очереди на пустоту;

-добавление нового элемента в конец (хвост) очереди;

-удаление элемента из начала (головы) очереди;

-поиск и модификация элемента в очереди.

-упорядочивание элементов очереди.

Ниже приводится текст программы, иллюстрирующий работу с однонаправленной очередью.

#include <stdio.h> #include <alloc.h> #include <conio.h> #include <string.h> struct zap

{char inf[50]; zap *nx;

};

void add(zap **); void del(zap **);

void del_any(zap **,char *); void see(zap *);

void sort(zap **);

main()

{zap *h,*t; char l,*st;

st=(char *)malloc(10); h=NULL;

clrscr();

while(1)

{ puts("вид операции: 1-создать очередь");

puts("

2-вывод содержимого очереди");

puts("

3-удаление элемента из очереди");

puts("

4-удаление любого элемента из очереди");

puts("

5-сортировка очереди");

puts("

0-окончить");

fflush(stdin);

 

switch(getch())

{case '1': add(&h); break; case '2': see(h); break;

case '3': if(h) del(&h); break; case '4': if(h)

{fflush(stdin);

puts("Введите информацию для удаления "); gets(st);

del_any(&h,st); } break;

case '5': if (h) sort(&h); break; case '0': return;

default: printf("Ошибка, повторите \n");

}

}

}

// функция создания очереди void add(zap **h)

{zap *n;

puts("Создание очереди \n"); do

{if(!(n=(zap *) calloc(1,sizeof(zap))))

{puts("Нет свободной памяти");

return;

}

puts("Введите информацию в inf"); scanf("%s",n->inf);

if (!*h)

// очередь еще не создана

*h=n;

// хвост очереди

else

 

{ n->nx=*h;

// очередной элемент очереди

*h=n;

// передвигаем указатель на хвост

}

puts("Продолжить (y/n): "); fflush(stdin);

} while(getch()=='y');

}

// функция вывода содержимого очереди void see(zap *h)

{ puts("Вывод содержимого очереди \n"); if (!h)

{puts("Очередь пуста"); return;

}

do

{printf("%s\n",h->inf); h=h->nx;

}while(h);

return;

}

// функция удаления первого элемента очереди void del(zap **h)

{ zap *f,*pr;

 

if (!(*h)->nx)

// в очереди только один элемент

{ free(*h);

 

*h=NULL;

// очередь пуста

return;

 

}

pr=*h; while(pr->nx->nx) pr=pr->nx;

free(pr->nx); // удаление первого элемента из очереди pr->nx=NULL;

return;

}

// функция удаления любого элемента очереди void del_any(zap **h,char *st)

{zap *f,*pr;

if (!(*h)->nx && // в очереди только один элемент

(!strcmp((*h)->inf,st) || *st=='\0'))

{ free(*h);

*h=NULL; // очередь пуста return;

}

pr=*h;

f=pr; // далее f предыдущий к pr элемент while(pr)

{if (!strcmp(pr->inf,st)) // найден элемент со строкой st

{if (pr==*h) {*h=pr->nx; free(pr); f=pr=*h;} else

{ f->nx=pr->nx;

// обходим элемент pr

free(pr);

// удаляем элемент pr очереди

pr=f->nx;

// выбор следующего элемента очереди pr

}

 

}

else {f=pr; pr=pr->nx;} // переход к следующему элементу

}