Помощь - Поиск - Пользователи - Календарь
Полная версия: Задача на очередь
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
mirtan
Всем привет. Задача следующая.
Сформировать очередь елементами которой есть цифры и арифметические знаки. Нужно вывести результат.

Пробовал сделать, но у меня почему-то выводится самый последний символ в очереди вместо результата. Скорей всего ошибка детская, но в теме немного не разобрался ://

Вот текст программы:
Program lab13z;       
Const zn=['+','-','*','/'];
Type zv=^pointer; {описание переменных}
pointer=record
boolkey:boolean;
arsing:char;
arcint:integer;
next:zv;
end;
Var scher,lcher:zv;
symb:char;
cfr:integer;
a,b:integer;

Procedure vcherc(zv1:zv;cfr1:integer); {процедура вставки ЧИСЛА в очередь}
Var q:zv;
Begin
new(q);
q^.arcint:=cfr1;
zv1^.next:=q;
zv1:=zv1^.next;
end;

Procedure vchers(zv1:zv;simv:char); {Процедура вставки СИМВОЛА в очередь}
Var q:zv;
Begin
new(q);
q^.arsing:=simv;
zv1^.next:=q;
zv1:=zv1^.next;
end;

Begin {формирование очереди}
new(scher);
scher^.next:=nil;
lcher:=scher;
writeln('Введите очередь');
repeat
read(symb);
if symb in ['0'..'9'] then
Begin
cfr:=ord(symb)-48+cfr*10;
vcherc(lcher,cfr);
cfr:=0;
end;
if symb in zn then
vchers(lcher,symb)
until symb='=';
scher:=scher^.next;
a:=scher^.arcint;
scher:=scher^.next;
while (scher<>nil) do
Begin
symb:=scher^.arsing;
scher:=scher^.next;
b:=scher^.arcint;
scher:=scher^.next;
case symb of
'+':a:=a+b;
'-':a:=a-b;
'*':a:=a*b;
'/':a:=a div b;
end;
end; {Cкорей всего неправильно вывожу результат =/}
write(a);
Readln;
readln;
end.


Зарание спасибо за помощь.
volvo
Попробуй сразу после того, как ты "заполнил" очередь, ее напечатать (т.е., напечатать символы/цифры, присутствующие в очереди). Больше ничего делать не надо, просто напечатать. Тогда тебе станет понятно, что заполняешь ты очередь неверно.

Для начала: что такое очередь, тебе известно? Что ты имеешь в виду под термином "очередь"? Структуру FIFO (First In - First Out/Первым вошел - Первым выйдешь)? Или что-то другое?

По какому алгоритму ты заполняешь очередь? Опиши его словами, а не кодом на Паскале, пожалуйста. И поверь, я просто так ничего не спрашиваю. Потом поймешь, почему я задаю такие вопросы. Если будешь на них отвечать, разумеется, а не просто ждать, пока кто-нибудь исправит программу.

Только скажи сразу, чего ты хочешь. Хочешь разобраться (понять, что у тебя не так, и исправить) самостоятельно - пожалуйста, я помогу, надеюсь - не только я, остальные тоже с удовольствием помогут. Если надо исправить за тебя, то на мою помощь можешь не рассчитывать.
mirtan
Очередь я представляю как одна из разновидностей линейного списка, все елементы которого добавляются в конец, а считываются с начала списка. Да именно под абревиатурой FIFO.

Я себе представляю это так:
1) создается новый динамический обьект;
2) указатель равняем nil; так как следующего обьекта пока что вроде нету.

Вводим данные в очередь символы.

1) Если является цифрой от 0 до 9, то проделывая cfr:=ord(symb)-48+cfr*10 мы переводим в число, если у нас идут несколько цифр подряд. Вставляем в очередь и после этого приравниваем к 0, чтобы можна было перепроверять последующие цифры.
2) Если мы имеем другой символ - просто вставляем его в очередь. Повторяем операцию, пока не встречаем символ =.
3) А вот дальше я не совсем понимаю принцып. Вроде как сперва берем елемент а, после него идет символ. С помощью кейса вводим операции для каждого символа. Ну и потом берем елемент б с которым будем проводить операцию. Результат присваиваем а и выводим его на экран. Собственно тут какойто бред выходит.

Нет, код мне писать не нужно)) Если вдруг на экзамене попадется. Хочу разобратся.
volvo
Цитата
1) Если является цифрой от 0 до 9, то проделывая cfr:=ord(symb)-48+cfr*10 мы переводим в число, если у нас идут несколько цифр подряд. Вставляем в очередь и после этого приравниваем к 0, чтобы можна было перепроверять последующие цифры.
А теперь посмотри, что ты делаешь на самом деле:
Цитата
repeat
read(symb); // Взял очередной символ. Допустим ...
if symb in ['0'..'9'] then // Если это ЦИФРА - то:
Begin
cfr:=ord(symb)-48+cfr*10; // преобразуешь ее в число
vcherc(lcher,cfr); // Засовываешь это однозначное число 0 .. 9 в очередь
cfr:=0; // И обнуляешь свою переменную-"накопитель"
end;
if symb in zn then
vchers(lcher,symb)
until symb='=';
Понимаешь, в чем ошибка? Если уж ты взял символ, который лежит в интервале '0' .. '9', то тебе надо там организовать цикл, который будет выполняться, пока очередной символ не будет выпадать из этого интервала. И только потом, по окончании цикла, когда ты действительно соберешь число, а не переведешь одну цифру из Char в Integer, будешь добавлять это число в очередь. Исправляй...

Теперь о добавлении:
Цитата
Procedure vcherc(zv1:zv;cfr1:integer); {процедура вставки ЧИСЛА в очередь}
Var q:zv;
Begin
new(q);
q^.arcint:=cfr1;
zv1^.next:=q;
zv1:=zv1^.next;
end;
Это неправильная процедура. Изменения переменной zv1 не передаются в вызывающую программу. Потому что ты работаешь с копией этой переменной, передаешь параметр по значению. Чтобы вернуть новое значение zv1 из процедуры, тебе надо передавать первый параметр по ссылке:
Procedure vcherc(VAR zv1:zv;cfr1:integer);


Опять же, это делается не совсем так, как ты показал. Не надо заранее выделять память под лишний элемент (то что ты делаешь в 34-ой строке кода). Ты это делаешь по одной простой причине: тебе надо быть уверенным, что scher не NIL, иначе программа твоя начнет вылетать при попытке сделать NIL^.next, правда?

Все проще:
Procedure PutInteger(var head, tail: zv; value: integer);
var q: zv;
begin
new(q); // Выделил память под новый элемент
q^.next := nil; q^.arcint := value; // заполнил поля НОВОГО ЭЛЕМЕНТА

if head = nil then head := q // очередь пуста? Значит первый элемент будет начальным...
else tail^.next := q; // Ах, не пуста? Уже были элементы? Прекрасно ,"прикрепляемся" к последнему

tail := q; // и запоминаем только что добавленный элемент. Теперь ОН - последний
end;

// Вызывать так:
scher := nil; lcher := nil;
...
PutInteger(scher, lcher, cfr);
Вот и все. Теперь добавление в очередь будет работать корректно, и тебе останется только исправить только сам алгоритм вычислений...

С алгоритмом вычисления значения, кстати, тоже не все так просто: 2+3*4= чему?Сначала надо вычислить 3*4 по правилам арифметики, правда? Или тебе надо вычисление без учета приоритетов операций? Ты это не уточнил, поэтому на данный момент (по умолчанию принято вычисление с учетом приоритетов) твой алгоритм неверен.
mirtan
1) Тоесть считывать число нужно так? Пока символ является цифрой - переводить его?

While symb in ['0'..'9'] do
Begin
cfr:=ord(symb)-48+cfr*10;
vcherc(lcher,cfr); /
cfr:=0;
end;


2) C процедурой вставки я всё понял, спасибо большое что обьяснил.
3) Вычисления должно производится по порядку, тоесть как есть, без учёта законов арифметики.
Я представляю себе такой алгоритм:
Запоминаем первое число, присваиваем ему а. Видим символ, после которого 100% будет еще одно число, пускай b. В зависимости от значения символа, через кейс вводим операции, результат которой будет вносится опять же в а. Потом берем уже ЭТО а, и продолжаем дальше двигатся по циклу.

Допустим: 1)2+3-5+13=
а + b
2)2+3-5+13=
a - b
volvo
Цитата
Тоесть считывать число нужно так? Пока символ является цифрой - переводить его?
Нет... Тебе надо добавлять только результат. То есть, в цикле изменяешь cfr, а добавляешь полученное число - уже после цикла, когда symb не попадает в интервал '0' .. '9'. Ты же опять пытаешься добавлять по одной цифре в очередь...

Цитата
Я представляю себе такой алгоритм:
Ну, все правильно, теперь попробуй это реализовать smile.gif
mirtan
Цитата
Нет... Тебе надо добавлять только результат. То есть, в цикле изменяешь cfr, а добавляешь полученное число - уже после цикла, когда symb не попадает в интервал '0' .. '9'. Ты же опять пытаешься добавлять по одной цифре в очередь...


Понял. Спасибо тебе огромное за помощь smile.gif.
С алгоритмом вычисления я уже разберусь smile.gif.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.