|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
Реализация стеков и очередей
Доброго времени суток!
Разбираюсь со стеками и очередями на примере следующей задачи: ”Дан стек, элементами которого являются действительные числа. Сформировать структуру данных очередь, в которую включить значения тех элементов из стека, которые не превосходят uz. Элементы с найденными значениями из стека исключить. А также получить: (uz+r)/(uz+s), где r- сумма всех тех значений элементов, которые не превосходят u, s- сумма значений элементов, больших u.” Реализовать нужно без динамических массивов, только очереди и стеки. Ниже привожу свой код, укажите на ошибки. Я пока не могу понять, почему при первом выводе стека на экран он обнуляется. И потом просто программа вылетает с ошибкой, как я понимаю как раз из за того, что стек стал пустым и последующее обращение к нему приводит к падению программы Код:
program new_stack; {$APPTYPE CONSOLE} uses SysUtils; type Stack =^Еlеm; Еlеm = Record inf : integer; next : Stack; end; Ocher =^och; och = record inf : integer; next : Ocher; end; /////////////////////// Добавляем в стек /////////////////////////////////////// Procedure In_stak(Var Beg:Stack; Sim:integer); Var x:Stack; Begin New(X); X^.inf:=Sim; X^.next:=Beg; Beg:=X; End; //////////////////////////// Достаём верхний элемент стека ///////////////////// procedure Out_stak(Var Beg: Stack; Var Flag: Boolean); Var x: Stack; Begin If Beg= Nil then Flag:= false else Begin Flag:=true; X:=Beg; Beg:=Beg^.next; Dispose(x); End; End; ////////////////////////////////////////////////////////////////////////////////// //////////////////////// Занесение в очередь /////////////////////////////////// Procedure writeO(Var BeginO, EndO : Ocher; c : integer); Var Elem : Ocher; Begin new(Elem); Elem^.inf := c; Elem^.Next := Nil; if BeginO = Nil {проверяем, пуста ли очередь} then BeginO := Elem {ставим указатель начала очереди на первый созданный элемент} else EndO^.Next := Elem; {ставим созданный элемент в конец очереди} EndO := Elem; {переносим указатель конца очереди на последний элемент} End; ///////////////////////////// Чтение из очереди ///////////////////////////////// Procedure readO(Var BeginO : Ocher; Var INF : integer); Var Elem : Ocher; Function FreeO(x1 : Ocher): boolean; Begin FreeO := (x1 = Nil); End; Begin if FreeO(BeginO) then writeln('Очередь пуста') else begin INF := BeginO^.inf; {считываем искомое значение в переменную с} Elem := BeginO; {ставим промежуточный указатель на первый элемент очереди} BeginO := BeginO^.Next;{указатель начала переносим на следующий элемент} dispose(Elem); {освобождаем память, занятую уже ненужным первым элементом} end; End; var MY,MY2:Stack; INF,I,uz,R,S:integer; BeginO, EndO , O:Ocher; IO:Boolean; begin R:=0; S:=0; Randomize; write ('Input Uz :'); readln(uz); MY:=nil; BeginO:=nil; EndO :=nil; for I := 0 to 10 do begin In_stak(MY, random(100)); end; write ('Ishodn stack :'); while MY <> Nil do begin write (My^.inf); write ('-->'); MY:=My^.next; end; readln; while MY <> Nil do Begin Out_stak(My,IO); // из основного стека достали if MY^.inf <uz then begin R:=MY^.inf; writeO( BeginO, EndO , MY^.inf); {помещаем элемент в очередь } end else begin if MY^.inf >=uz then begin S:=MY^.inf; In_stak(MY2, MY^.inf); end; End; MY := MY^.next; End; /////////////// Вывод стека //////////////////////////////////////////////// while MY2 <> nil do begin write (MY2^.inf); MY2:=MY2^.next; end; /////////////// Вывод Очереди //////////////////////////////////////////////// while O <> nil do begin write (O^.inf); O:=O^.next; end; /////////////// Вывод итогового числа //////////////////////////////////////////////// writeln ('Iskomoe chislo :'); write ((uz+r)/(uz+s)) ; readln; end. Последний раз редактировалось kaizer131, 25.02.2010 в 15:13. |
#2
|
|||
|
|||
Цитата:
|
#3
|
|||
|
|||
я то не против применения готовых методов, но это нужно будет сдавать на сессии, да и к тому же сам хочу разобраться в реализации, просто зашёл в тупик при решении
|
#4
|
|||
|
|||
Посмотртите задачник Шеня, книгу С.Окулова Основы программирования там как раз эти темы на pascal с примерами разбираются
|
#5
|
|||
|
|||
Цитата:
В Окулове стеки описанны на 2х страницах , причем одна из них это определения , вы считаете что этого достаточно для понимания этого вопроса? Задачник пока не нашёл... |
#6
|
|||
|
|||
Не смотрел всю программу, но по-моему эта вещь нехорошая:
Код:
Procedure In_stak(Var Beg:Stack; Sim:integer); Var x:Stack; Begin New(X); X^.inf:=Sim; X^.next:=Beg; -> Beg:=X; End; |
#7
|
|||
|
|||
Цитата:
Во первых, x должна быть ссылкой на какой либо тип, в данном случае на элемент стека, во вторых, переменные созданные методом New, не уничтожаются, после выхода из процедуры, к их уничтожению необходим метод Dispose(); А сама процедура явно написано неверено, так как все добавляемые элементы привязываются к первому. А автору вопроса, советую почитать теорию, так как, пока не придет понимания работы стэка и очереди, писать код не имеет смысла. |
#8
|
|||
|
|||
Цитата:
То что при работе со стеком мы можем брать только верхний элемент я знаю. вопрос в том как их не потерять при работе |
#9
|
|||
|
|||
Вот допустим
Код:
Procedure readStack(Var u : EXST; Var i : integer); Var x : EXST; Begin i := u^.Data; {считываем значение поля данных в переменную} x := u; {запоминаем адрес вершины стека} u := u^.Next; {переносим вершину стека на следующий элемент} dispose(x); {освобождаем память, занятую уже ненужным элементом стека} End. Я так понимаю, что при применении такой процедуры мы потеряем элемент стека, но для его сохранения мы можем перед u := u^.Next; {переносим вершину стека на следующий элемент} занести этот элемент во второй стек . Или я не прав ? |
#10
|
||||
|
||||
Цитата:
- На какой Delphi проходит обучение? - Можно ли пользоваться классами? У Тебя в секции type объявлены только элементы стека или очереди ( причем одинаковые ). У самих стеков или очередей должны быть реализованы минимум 3 метода - Push, Pop, Peek. Которые описываются в классах, а в последних версиях Delphi можно и в структурах. |
#11
|
|||
|
|||
Обучение проходит на Delphi 7
но дома делаю на Delphi 2009, просто главное чтоб был работающий exe шник и файл с исходным кодом. По поводу классов точно незнаю , так как ООП еще не проходили (эту тему осваиваю пока самостоятельно) но думаю их применение не запрещенно , главное уметь обьяснить принцип работы. В type обьявленн стек и очередь. Главная моя проблема это в процедуре взятия элемента стека , не могу понять почему они после этого пропадают (даже если в процедуре уберу строку dispose (x)) Главное не использовать массивов для хранения указателей и готовых решений типа TStack и TQueue |
#12
|
||||
|
||||
Будем посмотреть, постараюсь без классов и с минимумом переделок.
Плохо - у Тебя Elem и тип записи и переменная. тип записи обзову TElem. |
#13
|
||||
|
||||
У Тебя по заданию "действительные числа" - а это real а не integer.
меняю и смотрю дальше |
#14
|
|||
|
|||
Цитата:
|
#15
|
||||
|
||||
В общем тоже не ахти - давно с такими примитивами не работал и старался изменения по минимуму - но вроде работает
Код:
program new_stack; {$APPTYPE CONSOLE} uses SysUtils; type PElem = ^TElem; TElem = record // структура элемента inf: real; next: PElem; end; TStack = record first: PElem; end; TOcher = record first: PElem; last: PElem; end; /////////////////////// Добавляем в стек /////////////////////////////////////// procedure Push_stak(var Stack: TStack; Sim: real); var x: PElem; begin New(X); X^.inf := Sim; X^.next := Stack.first; Stack.first := X; end; //////////////////////////// Достаём верхний элемент стека ///////////////////// function Pop_stak(var Stack: TStack; var INF: real): Boolean; var x: PElem; begin if Stack.first = nil then Result := false else begin Result := true; X := Stack.first; Stack.first := X^.next; INF := X^.inf; Dispose(x); end; end; //////////////////////////// Удаляем элемент стека ///////////////////// procedure Remove_stak(var Stack: TStack; Elem: PElem); var x: PElem; begin if Stack.first = Elem then Stack.first := Elem^.next else begin X := Stack.first; while X^.next <> nil do begin if X^.next = Elem then begin X^.next := Elem^.next; break; end; X := X^.next; end; Dispose(Elem); end; end; ////////////////////////////////////////////////////////////////////////////////// //////////////////////// Занесение в очередь /////////////////////////////////// procedure Push_Ocher(var Ocher: TOcher; c: real); var Elem: PElem; begin new(Elem); Elem^.inf := c; Elem^.Next := nil; if Ocher.first = nil {проверяем, пуста ли очередь} then Ocher.first := Elem {ставим указатель начала очереди на первый созданный элемент} else Ocher.last^.next := Elem; {ставим созданный элемент в конец очереди} Ocher.last := Elem; {переносим указатель конца очереди на последний элемент} end; ///////////////////////////// Чтение из очереди ///////////////////////////////// function Pop_Ocher(var Ocher: TOcher; var INF: real): Boolean; var Elem: PElem; begin if Ocher.first = nil then Result := false // writeln('Очередь пуста') else begin Result := true; Elem := Ocher.first; {ставим промежуточный указатель на первый элемент очереди} INF := Elem^.inf; {считываем искомое значение в переменную с} Ocher.first := Elem^.Next; {указатель начала переносим на следующий элемент} if Elem^.Next = nil then {очередь пуста} Ocher.last := nil; dispose(Elem); {освобождаем память, занятую уже ненужным первым элементом} end; end; var MY: TStack; TmpElem, NextElem: PElem; I: Integer; uz, R, S: real; Ocher: TOcher; begin R := 0; S := 0; Randomize; write('Input Uz :'); readln(uz); MY.first := nil; Ocher.first := nil; Ocher.last := nil; for I := 0 to 10 do begin Push_stak(MY, random(10000) / 100); end; write('Ishodn stack :'); TmpElem := MY.first; while TmpElem <> nil do begin write(Format('%.2f', [TmpElem^.inf])); write('-->'); TmpElem := TmpElem^.next; end; writeln(''); readln; TmpElem := MY.first; while TmpElem <> nil do begin NextElem := TmpElem^.next; if TmpElem^.inf <= uz then // не превосходят, значит <= а было < begin R := R + TmpElem^.inf; Push_Ocher(Ocher, TmpElem^.inf); {помещаем элемент в очередь } Remove_stak(MY, TmpElem); {удаляем из стека} end else // значит больше begin S := S + TmpElem^.inf; end; TmpElem := NextElem; end; /////////////// Вывод стека //////////////////////////////////////////////// write('Stack :'); TmpElem := MY.first; while TmpElem <> nil do begin write(Format('%.2f', [TmpElem^.inf])); write('-->'); TmpElem := TmpElem^.next; end; writeln(''); /////////////// Вывод Очереди //////////////////////////////////////////////// write('Ocher :'); TmpElem := Ocher.first; while TmpElem <> nil do begin write(Format('%.2f', [TmpElem^.inf])); write('-->'); TmpElem := TmpElem^.next; end; writeln(''); /////////////// Вывод итогового числа //////////////////////////////////////////////// write('Iskomoe chislo : '); write((uz + R) / (uz + S)); ///// очищаем while Pop_stak(MY, R) do ; while Pop_Ocher(Ocher, R) do ; readln; end. ( я не очень люблю много коментов - ленивый ) |