what I am trying to do, is determine, whether brackets are in correct order. For example ([][[]]<<>>) is vallid, but ][]<<(>>) is not.
I got a working version, but it has terrible efficiency and when it gets 1000+ brackets, its just crazy slow. I was hoping someone might suggest some possible improvements or another way to do it.
Here is my code:
program Codex;
const
C_FNAME = 'zavorky.in';
var TmpChar : char;
leftBrackets, rightBrackets : string;
bracketPos : integer;
i,i2,i3 : integer;
Arr, empty : array [0..10000] of String[2];
tfIn : Text;
result : boolean;
begin
leftBrackets := ' ( [ /* ($ <! << ';
rightBrackets := ' ) ] */ $) !> >> ';
i := 0;
result := true;
Assign(tfIn, C_FNAME);
Reset(tfIn);
{ load data into array }
while not eof(tfIn) do
begin
while not eoln(tfIn) do
begin
read(tfIn, TmpChar);
if (TmpChar <> ' ') then begin
if (TmpChar <> '') then begin
Arr[i] := Arr[i] + TmpChar;
end
end
else
begin
i := i + 1;
end
end;
i2 := -1;
while (i2 < 10000) do begin
i2 := i2 + 1;
{if (i2 = 0) then
writeln('STARTED LOOP!');}
if (Arr[i2] <> '') then begin
bracketPos := Pos(' ' + Arr[i2] + ' ',rightBrackets);
if (bracketPos > 0) then begin
if (i2 > 0) then begin
if(bracketPos = Pos(' ' + Arr[i2-1] + ' ',leftBrackets)) then begin
{write(Arr[i2-1] + ' and ' + Arr[i2] + ' - MATCH ');}
Arr[i2-1] := '';
Arr[i2] := '';
{ reindex our array }
for i3 := i2 to 10000 - 2 do begin
Arr[i3 - 1] := Arr[i3+1];
end;
i2 := -1;
end;
end;
end;
end;
end;
{writeln('RESULT: ');}
For i2:=0 to 10 do begin
if (Arr[i2] <> '') then begin
{write(Arr[i2]);}
result := false;
end;
{else
write('M');}
end;
if (result = true) then begin
writeln('true');
end
else begin
writeln('false');
end;
result := true;
{ move to next row in file }
Arr := empty;
i := 0;
readln(tfIn);
end;
Close(tfIn);
readln;
end.
The input data in the file zavorky.in look for example like this:
<< $) >> << >> ($ $) [ ] <! ( ) !>
( ) /* << /* [ ] */ >> <! !> */
I determine for each row whether it is valid or not. Max number of brackets on a row is 10000.
You read chars from your file. File read in byte-by-byte mode is very slow. You need to optimize the way to read the strings (buffers) instead or load the file in memory first.
Hereunder I propose the other way to process the fetched string.
First I declare the consts that will state the brackets that you might have:
const
OBr: array [1 .. 5{6}] of string = ('(', '[', '/*', '<!', '<<'{, 'begin'});
CBr: array [11 .. 15{16}] of string = (')', ']', '*/', '!>', '>>'{, 'end'});
I decided to do this as now you are not limited to the length of the brackets expression and/or number of brackets' types. Every closing and corresponding opening bracket has index difference equal to 10.
And here is the code for the function:
function ExpressionIsValid(const InputStr: string): boolean;
var
BracketsArray: array of byte;
i, Offset, CurrPos: word;
Stack: array of byte;
begin
result := false;
Setlength(BracketsArray, Length(InputStr) + 1);
for i := 0 to High(BracketsArray) do
BracketsArray[i] := 0; // initialize the pos array
for i := Low(OBr) to High(OBr) do
begin
Offset := 1;
Repeat
CurrPos := Pos(OBr[i], InputStr, Offset);
if CurrPos > 0 then
begin
BracketsArray[CurrPos] := i;
Offset := CurrPos + 1;
end;
Until CurrPos = 0;
end; // insert the positions of the opening brackets
for i := Low(CBr) to High(CBr) do
begin
Offset := 1;
Repeat
CurrPos := Pos(CBr[i], InputStr, Offset);
if CurrPos > 0 then
begin
BracketsArray[CurrPos] := i;
Offset := CurrPos + 1;
end;
Until CurrPos = 0;
end; // insert the positions of the closing brackets
Setlength(Stack, 0); // initialize the stack to push/pop the last bracket
for i := 0 to High(BracketsArray) do
case BracketsArray[i] of
Low(OBr) .. High(OBr):
begin
Setlength(Stack, Length(Stack) + 1);
Stack[High(Stack)] := BracketsArray[i];
end; // there is an opening bracket
Low(CBr) .. High(CBr):
begin
if Length(Stack) = 0 then
exit(false); // we can not begin an expression with Closing bracket
if Stack[High(Stack)] <> BracketsArray[i] - 10 then
exit(false) // here we do check if the previous bracket suits the
// closing bracket
else
Setlength(Stack, Length(Stack) - 1); // remove the last opening
// bracket from stack
end;
end;
if Length(Stack) = 0 then
result := true;
end;
Perhaps, we do an extra work by creating a byte array, but it seems that this method is i) more easy to understand and ii) is flexible as we can change the length of brackets expressions for example use and check begin/end brackets etc.
Appended
As soon as I see that the major problem is in organizing block reading of file I give here an idea of how to do it:
procedure BlckRead;
var
f: file;
pc, pline: { PChar } PAnsiChar;
Ch: { Char } AnsiChar;
LngthLine, LngthPc: word;
begin
AssignFile(f, 'b:\br.txt'); //open the file
Reset(f, 1);
GetMem(pc, FileSize(f) + 1); //initialize memory blocks
inc(pc, FileSize(f)); //null terminate the string
pc^ := #0;
dec(pc, FileSize(f)); //return the pointer to the beginning of the block
GetMem(pline, FileSize(f)); //not optimal, but here is just an idea.
pline^ := #0;//set termination => length=0
BlockRead(f, pc^, FileSize(f)); // read the whole file
//you can optimize that if you wish,
//add exception catchers etc.
LngthLine := 0; // current pointers' offsets
LngthPc := 0;
repeat
repeat
Ch := pc^;
if (Ch <> #$D) and (Ch <> #$A) and (Ch <> #$0) then
begin // if the symbol is not string-terminating then we append it to pc
pline^ := Ch;
inc(pline);
inc(pc);
inc(LngthPc);
inc(LngthLine);
end
else
begin //otherwise we terminate pc with Chr($0);
pline^ := #0;
inc(LngthPc);
if LngthPc < FileSize(f) then
inc(pc);
end;
until (Ch = Chr($D)) or (Ch = Chr($A)) or (Ch = Chr($0)) or
(LngthPc = FileSize(f));
dec(pline, LngthLine);
if LngthLine > 0 then //or do other outputs
Showmessage(pline + #13#10 + Booltostr(ExpressionIsValid(pline), true));
pline^ := #0; //actually can be skipped but you know your file structure better
LngthLine := 0;
until LngthPc = FileSize(f);
FreeMem(pline); //free the blocks and close the file
dec(pc, FileSize(f) - 1);
FreeMem(pc);
CloseFile(f);
end;
You are saving all the data into memory (even couple of times) and then you have a lot of checks. I think you are on the right track but there are much easier steps you could follow.
Make an array of integers (default = 0) with length the number of brackets you have (e.g. ' ( [ /* ($ <! << ' ==> 6)
Now to make sure that you are following the requirements. Read the file line by line and take into account only the first 10000. This could help.
Every time you find an element from the first array (e.g. leftBrackets) add +1 to the value of the coresponding index of the array of step 1. Example would be:
'[' ==> checkArray[1] += 1
Do the same for rightBrackets but this time check if the value is larger than 0. If yes then subtract 1 the same way (e.g. ']' ==> checkArray[1] -= 1) otherwise you just found invalid bracket
I hope this helps and Good luck.
I think the following should work, and will be order O(n), where n is the length of the string. First build two function.
IsLeft(bra : TBracket) can determine if a bracket is a left bracket or a right bracket, so IsLeft('<') = TRUE, IsLeft('>>') = FALSE.
IsMatchingPair(bra, ket : TBracket) can determine if two brackets are of the same 'type', so IsMatchingPair('(',')') =TRUE, but IsMatchingPair('{','>>') = FALSE.
Then build a stack TBracketStack with three functions procedure Push(bra : TBracket), and function Pop : TBracket, and function IsEmpty : boolean.
Now the following algorithm should work (with a little extra code required to ensure you don't fall off the end of the string unexpectedly):
BracketError := FALSE;
while StillBracketsToProcess(BracketString) and not BracketError do
begin
bra := GetNextBracket(BracketString);
if IsLeft(bra) then
Stack.Push(bra)
else
BracketError := Stack.IsEmpty or not IsMatchingPair(Stack.Pop,bra)
end;
Related
In this program when I try to put the code blocks [1] and [2] in procedures they don't work properly when calling them, and when I keep them in the main program only the first one works properly and the second doesn't and when I comment out the first one the second one works as it's supposed...can you please spot the error, I think it's with getting the files names from the user cause when I choose the file's name it works properly
program Linked_lists_files;
type
Node = ^T;
T = record
num : integer;
next : Node;
End;
var
File1 : Text;
N, i, j, cmp, y, x, Num, matrixvalue : integer;
Head, Tail, Head2, Tail2, Head3, Tail3 : Node;
s : string;
matrix : array [1..20, 1..20] of Integer;
// procedures
// [1]
Procedure fillFile();
Begin
write('Input file name to create : ');
readln(s);
assign(File1,s);
rewrite(File1);
Repeat
write('Enter a number : ');
readln(N);
if (N>=0) then
writeln(File1, N);
Until (N<0);
close(File1);
End;
// [2]
Procedure GetFromFile();
Begin
cmp := 0;
write('Enter file name to read from : ');
readln(s);
assign(File1, s);
reset(File1);
while not eof(File1) Do
Begin
readln(File1, N);
if (Head = Nil) then
Begin
new(Head);
Tail := Head;
End
Else
Begin
new(Tail^.next);
Tail := Tail^.next;
End;
Tail^.num := N;
Tail^.next := Nil;
cmp := cmp + 1;
End;
Close(File1);
Write('Elements of the list : ');
Tail := Head;
if (Head<>nil) then
Begin
while(Tail <> nil) Do
Begin
write('[',Tail^.num,']', ' ');
Tail := Tail^.next;
End;
End
Else
Writeln('[!] The list is empty');
writeln;
writeln('Number of elements in the list : ', cmp);
End;
// [3]
Procedure SaveFromFile();
Begin
Head := Nil;
write('Enter file name to read from : '); readln(s);
writeln('[+] Fill in your list');
Repeat
write('+ Enter an integer : ');
read(y);
if (y>=0) then
Begin
if (Head = Nil) then
Begin
new(Head);
Tail := Head;
End
Else
Begin
new(Tail^.next);
Tail := Tail^.next;
End;
Tail^.num := y;
Tail^.next := Nil;
End;
Until y<0;
assign(File1, s);
rewrite(File1);
Tail := Head;
while(Tail <> nil) Do
Begin
Num := Tail^.num;
Tail := Tail^.next;
Writeln(File1, Num);
End;
Close(File1);
Writeln('[+] Elements of the lists have been successfully added to the new file');
End;
// [4]
Procedure SquareMatrix();
Begin
cmp := 0;
x := 0;
writeln('[+] Fill in your list');
Repeat
write('+ Enter an integer : ');
read(y);
if (y>=0) then
Begin
if (Head3 = Nil) then
Begin
new(Head3);
Tail3 := Head3;
End
Else
Begin
new(Tail3^.next);
Tail3 := Tail3^.next;
End;
Tail3^.num := y;
Tail3^.next := Nil;
cmp := cmp + 1;
End;
Until y<0;
while (cmp<>1) Do
Begin
if (cmp mod 2 <> 0) and (cmp <> 1) then
x := x + 1;
cmp := cmp div 2;
End;
if (x>0) then
writeln('[-] False')
Else
writeln('[+]True');
End;
// [5]
Procedure ElementsOfSM();
Begin
cmp := 0;
x := 0;
writeln('[+] Fill in your list');
Repeat
write('+ Enter an integer : ');
read(y);
if (y>=0) then
Begin
if (Head = Nil) then
Begin
new(Head);
Tail := Head;
End
Else
Begin
new(Tail^.next);
Tail := Tail^.next;
End;
Tail^.num := y;
Tail^.next := Nil;
cmp := cmp + 1;
End;
Until y<0;
Tail := Head;
i := 1;
j := 1;
while(Tail <> nil) Do
Begin
matrixvalue := Tail^.num;
matrix[i,j] := matrixvalue;
Tail := Tail^.next;
j := j + 1;
if (j = sqrt(cmp)+1) then
Begin
i := i + 1;
j := 1;
End;
End;
for i:=1 to cmp Do
for j:=1 to cmp Do
Begin
if (matrix[i,j]<>0) then
writeln('[',matrix[i,j],']',' : ','[',i,',',j,']');
End;
End;
// [6]
Procedure Element();
Begin
write('Enter the number of the line : ');
read(i);
write('Enter the number of the column : ');
read(j);
write('The element corresponding to ','[',i,',',j,'] is : ','[',matrix[i,j],']');
writeln;
End;
// [7]
Procedure WriteP();
Begin
write('Enter the number of the line : ');
read(i);
write('Enter the number of the column : ');
read(j);
write('Enter the value you want to pass in : ');
read(N);
matrix[i,j] := N;
writeln('The new matrix');
for i:=1 to cmp Do
for j:=1 to cmp Do
Begin
if (matrix[i,j]<>0) then
writeln('[',matrix[i,j],']',' : ','[',i,',',j,']');
End;
writeln;
End;
// [8]
Procedure Content();
Begin
write('Enter the number of the line : ');
read(i);
write('Enter the number of the column : ');
read(j);
writeln('The value stored inn this cell is : ','[', matrix[i,j],']');
End;
// Start of main program
Begin
Head := Nil;
Repeat
writeln('*********** MENU ***********');
writeln('[1] fillFile');
writeln('[2] GetFromFile');
writeln('[3] SaveFromFile');
writeln('[4] SquareMatrix');
writeln('[5] ElementsOfSM');
writeln('[6] Element');
writeln('[7] WriteP');
writeln('[8] Content');
writeln('*********** End ***********');
write('Choose one : ');
read(N);
case N of
1 : fillFile();
2 : GetFromFile();
3 : SaveFromFile();
4 : SquareMatrix();
5 : ElementsOfSM();
6 : Element();
7 : WriteP();
8 : Content();
End;
Until (N<>1) and (N<>2) and (N<>3) and (N<>4) and (N<>5) and (N<>6) and (N<>7) and (N<>8) and (N<>9);
End.
The problem you describe is being caused by the known behaviour of the Read statement; basically, the second (and subsequent) times you call it, it returns immediately, without waiting for any keyboard input and without reading anything.
This happen because FPC is closely based on Object Pacal in the commercial Delphi development package, and in Delphi's case, this is the officially documented behaviour.
From the Delphi (v7) online help:
Delphi syntax:
Text files:
procedure Read( [ var F: Text; ] V1 [, V2,...,Vn ] );
Description
The Read procedure can be used in Delphi code in the following ways.
[...]
With a type string variable:
Read reads all characters up to, but not including, the next end-of-line
marker or until Eof(F) becomes true; it does not skip to the next line after reading. If the resulting string is longer than the maximum length of the string variable, it is truncated.
After the first Read, each subsequent Read sees the end-of-line marker and returns a zero-length string (emphasis added).
Use multiple Readln calls to read successive string values.
Fortunately, the solution is simple, use readln, instead of read, as in
readln(s);
Update Make sure you replace all instances of read by readln, as you have left a number of them unchanged, as #TomBrunberg has commented.
After that, run your code again and select 1 from the menu and you will find that fillFile executes, but the program terminates on the until ... line. And that's because it is a very bad idea to use the same global variable, in this case N for several different purposes throughout the program. So, you should edit your code further (and carefully) so that as far as possible it only uses global variables for global purposes. Turn all all the other variables into local variables, preferably with different names than the global ones. If after that you are still having problems, submit a new question focused on that.
I'm learning algorithms and I'm trying to make an algorithm that extracts numbers lets say n in [1..100] from a string. Hopefully I get an easier algorithm.
I tried the following :
procedure ReadQuery(var t : tab); // t is an array of Integer.
var
x,v,e : Integer;
inputs : String;
begin
//readln(inputs);
inputs:='1 2 3';
j:= 1;
// make sure that there is one space between two integers
repeat
x:= pos(' ', inputs); // position of the space
delete(inputs, x, 1)
until (x = 0);
x:= pos(' ', inputs); // position of the space
while x <> 0 do
begin
x:= pos(' ', inputs); //(1) '1_2_3' (2) '2_3'
val(copy(inputs, 1, x-1), v, e); // v = value | e = error pos
t[j]:=v;
delete(inputs, 1, x); //(1) '2_3' (2) '3'
j:=j+1; //(1) j = 2 (2) j = 3
//writeln(v);
end;
//j:=j+1; // <--- The mistake were simply here.
val(inputs, v, e);
t[j]:=v;
//writeln(v);
end;
I get this result ( resolved ) :
1
2
0
3
expected :
1
2
3
PS : I'm not very advanced, so excuse me for reducing you to basics.
Thanks for everyone who is trying to share knowledge.
Your code is rather inefficient and it also doesn't work for strings containing numbers in general.
A standard and performant approach would be like this:
type
TIntArr = array of Integer;
function GetNumbers(const S: string): TIntArr;
const
AllocStep = 1024;
Digits = ['0'..'9'];
var
i: Integer;
InNumber: Boolean;
NumStartPos: Integer;
NumCount: Integer;
procedure Add(Value: Integer);
begin
if NumCount = Length(Result) then
SetLength(Result, Length(Result) + AllocStep);
Result[NumCount] := Value;
Inc(NumCount);
end;
begin
InNumber := False;
NumCount := 0;
for i := 1 to S.Length do
if not InNumber then
begin
if S[i] in Digits then
begin
NumStartPos := i;
InNumber := True;
end;
end
else
begin
if not (S[i] in Digits) then
begin
Add(StrToInt(Copy(S, NumStartPos, i - NumStartPos)));
InNumber := False;
end;
end;
if InNumber then
Add(StrToInt(Copy(S, NumStartPos)));
SetLength(Result, NumCount);
end;
This code is intentionally written in a somewhat old-fashioned Pascal way. If you are using a modern version of Delphi, you wouldn't write it like this. (Instead, you'd use a TList<Integer> and make a few other adjustments.)
Try with the following inputs:
521 cats, 432 dogs, and 1487 rabbits
1 2 3 4 5000 star 6000
alpha1beta2gamma3delta
a1024b2048cdef32
a1b2c3
32h50s
5020
012 123!
horses
(empty string)
Make sure you fully understand the algorithm! Run it on paper a few times, line by line.
Imagine - there's a house with 80 flats. It has 4 floors and 5 blocks. Each block has 4 flats.
User is asked to input flat number and Pascal program is supposed to calculate and output flat number. This must be calculated using some kind of formula. The only tip I have is that I have to use div and mod operations.
This is how the house looks like -
So far, I've created program, that loops through all 80 flats and after each 16 flats increases block value and after each 4 blocks increases stair.
This is my code:
program project1;
var
i, floors, blocks, flats, flat, block, floor, blockCounter, floorCounter : integer;
begin
floors := 4;
blocks := 5;
flats := 80;
while true do
begin
write('Flat number: ');
read(flat);
block := 1;
floor := 1;
blockCounter := 0;
floorCounter := 0;
for i := 1 to 80 do
begin
blockCounter := blockCounter + 1;
floorCounter := floorCounter + 1;
if (floorCounter = 4) then
begin
floorCounter := 0;
floor := floor + 1;
end;
if (blockCounter > 16) then
begin
block := block + 1;
blockCounter := 0;
floorCounter := 0;
floor := 1;
end;
if (i = flat) then
begin
writeln('Flat nr. ', flat, ' is in ', floor, '. floor and in ', block, '. block!');
end;
end;
end;
end.
Is there anyone who can help me with this?
I've finally solved my problem myself.
I finally undersood how div works, so I was able to solve this.
program Maja;
var dzivoklis, kapnutelpa, stavs : integer;
begin
while true do
begin
write('Ievadi dzivokla numuru: ');
read(dzivoklis);
kapnutelpa := ((dzivoklis - 1) div 16) + 1;
stavs := (((dzivoklis - 1) mod 16) div 4) + 1;
writeln('Kapnutelpa: ', kapnutelpa);
writeln('Stavs: ', stavs);
writeln();
end;
end.
When I collect input from a user, how can I check to see if it's an IP address?
An IP Address (assuming you mean IPv4) is actually an integer, but it is usually written as four numbers separated by a .. Each of those numbers represent a byte value of the integer, so each of the numbers should be a number between 0 and 255 (incl).
function CheckIP(Input: String): Cardinal;
var
IP: Cardinal;
i : Integer;
Part: Integer;
PartValue: Cardinal;
PartValid: Boolean;
begin
Part := 3;
PartValue := 0;
PartValid := False;
IP := 0;
{ When a '.' is encountered, the previous part is processed. Force processing }
{ the last part by adding a '.' to the input. }
Input := Input + '.';
for i := 1 to Length(Input) do
begin
{ Check next character }
if Input[i] = '.' then
begin
if PartValue <= 255 then
begin
if PartValid then
begin
{ A valid part is encountered. Put it in the result. }
IP := IP or (PartValue shl (Part * 8));
{ Stop processing if this is the last '.' we put in ourselves. }
if i = Length(Input) then
Break;
{ Else reset the temporary values. }
PartValid := False;
PartValue := 0;
Dec(Part);
end
else
RaiseException('Empty part');
end
else
RaiseException('Part not within 0..255');
end
else if ((Input[i] >= '0') and (Input[i] <= '9')) then
begin
{ A digit is found. Add it to the current part. }
PartValue := PartValue * 10 + Cardinal((Ord(Input[i]) - Ord('0')));
PartValid := True;
end
else
begin
{ Any other character raises an exception }
RaiseException('Invalid character');
end;
{ If part < 0, we processed too many dots. }
if Part < 0 then
RaiseException('Too many dots');
end;
{ Check if we found enough parts. }
if Part > 0 then
RaiseException('Address most consist of 4 numbers');
{ If Part is not valid after the loop, the input ended in a dot. }
if not PartValid then
RaiseException('IP cannot end in a dot');
{ Return the calculated IP address as a cardinal. }
Result := IP;
end;
I modified the code and now it you can use it with Inno setup:
//Validate an IPv4 address
function ValidateIP(
Input: String
): Boolean;
var
InputTemp : String;
IP: Cardinal;
i : Integer;
Part: Integer;
PartValue: Cardinal;
PartValid: Boolean;
begin
InputTemp := Input;
Result := True;
Part := 3;
PartValue := 0;
PartValid := False;
IP := 0;
// When a '.' is encountered, the previous part is processed. Force processing
// the last part by adding a '.' to the input.
Input := Input + '.';
for i := 1 to Length(Input) do
begin
// Check next character
if Input[i] = '.' then
begin
if PartValue <= 255 then
begin
if PartValid then
begin
// A valid part is encountered. Put it in the result.
IP := IP or (PartValue shl (Part * 8));
// Stop processing if this is the last '.' we put in ourselves.
if i = Length(Input) then
Break;
// Else reset the temporary values.
PartValid := False;
PartValue := 0;
Dec(Part);
end
else
Result := False;
end
else
Result := False;
end
else if ( (((Ord(Input[i]) - Ord('0'))) >= 0) and ((Ord(Input[i]) - Ord('0')) <= 9) ) then
begin
// A digit is found. Add it to the current part.
PartValue := PartValue * 10 + Cardinal((Ord(Input[i]) - Ord('0')));
PartValid := True;
end
else
begin
// Any other character
Result := False;
end;
// If part < 0, we processed too many dots.
if Part < 0 then
Result := False;
end;
// Check if we found enough parts.
if Part > 0 then
Result := False;
// If Part is not valid after the loop, the input ended in a dot.
if not PartValid then
Result := False;
end;
I have written a recursive Tree Function in pascal ( or delphi ) but i had an 'Out of Memory' message when I ran it.
I need to turn the Calculate recursive function in this code to non-recursive function, can you tell me how please :
program testing(input, output);
type
ptr = ^tr;
tr = record
age: byte;
left, right: ptr;
end;
var
topper: ptr;
total, day: longint;
procedure mycreate(var t: ptr);
var
temp:ptr;
begin
new(temp);
temp^.age := 1;
temp^.left := nil;
temp^.right := nil;
t := temp;
end;
procedure gooneday(var t: ptr);
begin
if t^.age <> 5 then
begin
if t^.age = 2 then
mycreate(t^.left)
else if t^.age = 3 then
mycreate(t^.right);
t^.age := t^.age + 1;
total := total + 1;
end;
end;
procedure calculate(var crnt: ptr);
begin
if crnt <> nil then
begin
gooneday(crnt);
calculate(crnt^.left);
calculate(crnt^.right);
end;
end;
begin
total := 0;
mycreate(topper);
day := 0;
while total < 1000000000000 do
begin
total := 0;
day := day + 1;
calculate(topper);
end;
writeln(day);
writeln(total);
end.
Recursive functions use a stack to keep the state of the recursion.
When converting to a loop, you must actually create an explicit stack. You must push and pop elements off the stack within the loop.