Programming Taskbook

Russian

E-mail:

Password:

User registration   Restore password

1000 training tasks on programming

©  M. E. Abramyan, 1998–2010

 

Examples | Pascal | Dynamic structures

PrevNext


Processing of dynamic structures

Solutions of tasks connected with processing of dynamic data structures (including adding a node, removing a node, processing of doubly linked and circular dynamic structures) are described on this page.

Analyzing an existing dynamic structure: Dynamic2

In the "Dynamic" task group we should use two new data types: pointers of PNode type and dynamic structures implemented by linked chains of records of TNode type. The PNode and TNode types are not standard Pascal types; they are defined in the Programming Taskbook library.

Let's get acquainted with features of the new data types by solving the following task:

Dynamic2°. An address P1 of a record of TNode type is given. The record is linked by its Next field with the next record of the same type, that record is linked with the next one, and so on, until the last record whose Next field equals nil (as a result, we obtain a chain of linked records). Output the value of the Data field for each chain component, the chain length (that is, the amount of its components) and the address of the last chain component.

Creating a template and acquaintance with the task

To create a template of the required task one should use PT4Load tool:

{$D+,I+,L+,Q+,R+,S+}
program Dynamic2;
uses PT4;

begin
  Task('Dynamic2');
end.

When the program is launched you will see the Programming Taskbook window:

This window contains new kinds of input data: pointers and dynamic structures.

A dynamic structure is displayed in two screen lines: the first line contains names of pointers that refer to components (nodes) of the structure, the second one contains values of nodes (that is, their Data fields). All data are displayed with light-cyan color to distinguish them from standard input-output data and comments. Here is a sample of the dynamic structure data:

 P1
 97 - 94 - 10 - 14 - 25 >nil

This structure consists of 5 nodes. The Data field of the first node equals 97; the first node is linked by the Next field with the second node whose Data field equals 94, and so on. The Next field of the fifth node equals nil, so this node is the last chain node:

All dynamic structures displayed in the input data panel were created when the task was initialized, and their nodes are stored in the dynamic memory (named the heap). To access the node we need to know its address. Therefore a pointer that refers the first node of the input dynamic structure is also given as an input data item.

This pointer has name P 1 and is displayed in the input data panel as follows:

P1 = ptr

The "P1=" text is a comment and has light-grey color. The "ptr" text means that this data item is a non-empty pointer that refers some node of input or output dynamic structure (an empty pointer is denoted as "nil"). All pointers should be input by the GetP procedure.

After creating some dynamic structure the student program must send addresses of one or more nodes of the output structure to Programming Taskbook (using the PutP procedure). After receiving these addresses Programming Taskbook can check correctness of the task solution.

Start of solving

Let's return to the Dynamic2 task. This task does not require to create a new data structure or to change the existing one; it is sufficient to analyse the given structure, that is, to output values of its nodes, to find its length, and output a pointer to the last node of the structure.

The algorithm shown below outputs all required data except the pointer to the last node:

var
  n: integer;
  p1: PNode;
begin
  Task('Dynamic2');
  GetP(p1);
  n := 0;
  while p1 <> nil do
  begin
    PutN(p1^.Data);
    Inc(n);
    p1 := p1^.Next;
  end;
  PutN(n);
end.

When the program will be started we shall see that all numeric data are output correctly. But the pointer to the last node is not output, therefore we shall see the following error message: "Some data are not output".

Add the following operator at the end of the program:

PutP(p1);

Now all required data will be output. But a resulting value of the pointer will be equal to nil because the p1 variable contains empty pointer when the "while" loop was finished. Therefore we shall see the error message "Wrong solution".

Correct solution

To get a correct result we should declare an additional pointer variable. This variable named p2 will store an address of node that precedes the node refered by the p1 pointer. As a result the p2 variable will contain the last node address when the loop will be finished:

var
  n: integer;
  p1, p2: PNode;
begin
  Task('Dynamic2');
  GetP(p1);
  n := 0;
  while p1 <> nil do
  begin
    PutN(p1^.Data);
    Inc(n);
    p2 := p1;
    p1 := p1^.Next;
  end;
  PutN(n);
  PutP(p2);
end.

After 3 test runnings we shall receive a message that the task is solved.


Adding a node to a dynamic structure: Dynamic3

Dynamic3°. An integer D and a pointer P1 to the top of a nonempty stack are given. Push a component with the value D onto the stack and output the address P2 of a new top of the stack.

Acquaintance with the task

After launching the program we will see dots that mark the first node of resulting stack:

Such dots mark nodes that must be created by student's program (unlike the other nodes that are created by Programming Taskbook).

Start of solving

In the first version of solution we shall output a pointer to the top of the given stack without any changing of this stack:

var
  d: integer;
  p1: PNode;
begin
  Task('Dynamic3');
  GetN(d);
  GetP(p1);
  PutP(p1);
end.

Of course this solution is not correct, and after launching the program the resulting stack will be displayed as follows (provided that the input stack contains 4 nodes with values 12, 24, 74, and 49):

 P2
(12)-(24)-(74)-(49)>nil

The parentheses mark nodes that are created by Programming Taskbook but are located at wrong positions of the resulting dynamic structure. Indeed, in our case the node with value 12 must be the second node in the resulting stack, and so on.

Correct solution

To get a correct algorithm of the Dynamic3 task we should allocate memory for a new node using the New procedure and then assign required values to the Data and Next fields of this node. In particular, the Next field must link the new node with the top of the given stack:

var
  d: integer;
  p1, p2: PNode;
begin
  Task('Dynamic3');
  GetN(d);
  GetP(p1);
  New(p2);
  p2^.Data := d;
  p2^.Next := p1;
  PutP(p2);
end.

After 5 test runnings we shall receive a message that the task is solved.


Removing a node from a dynamic data structure: Dynamic5

Dynamic5°. A pointer P1 to the top of a nonempty stack is given. Pop the top component off the stack and output its value D and the address P2 of a new top of the stack. If the stack will be empty after popping the component then P2 must be equal to nil. After popping the component release the memory allocated for this component.

Acquaintance with the task

When solving tasks devoted to removing of nodes one should not only "disconnect" the required nodes from the given dynamic structure but also completely destroy them by the Dispose procedure. All such nodes of given dynamic structure are marked by color that is more dark than an "usual" nodes (look at the node with the value 25 on the picture):

Start of solving

We begin with the wrong algorithm that does not destroy the first node of the given stack:

var
  p1: PNode;
begin
  Task('Dynamic5');
  GetP(p1);
  PutN(p1^.Data);
  PutP(p1^.Next);
end.

Although all output results will coincide with the control ones (that is, the "Example of right solution" and "Results obtained" tabs will be contain identical data) the status bar will display the following error message "Allocated dynamic memory is not released", and the component that must be removed will be marked by red color in the input data panel.

Correct solution

To get a correct solution it is enough to add the Dispose procedure call at the end of the program:

  Dispose(p1);

After 5 test runnings we shall receive a message that the task is solved.


Doubly linked dynamic structures: Dynamic30

Dynamic30°. A pointer P1 to the beginning of a chain of records is given; records have TNode type and are linked by their Next fields. Using the Prev field of the TNode record, transform the given (singly linked) chain into the doubly linked chain whose components are linked not only with the next ones (by the Next field) but also with the previous ones (by the Prev field). The Prev field of the first chain component must be equal to nil. Output the address of the last component of the resulting chain.

Acquaintance with the task

After launching the program we will see that the input and output dynamic structures are displayed in different manner. The input chain of nodes will be displayed as all other dynamic structures in the previous tasks, for example:

 P1
 35 - 11 - 36 - 39 - 56 >nil

The output chain of nodes will be displayed as follows:

                         P2
nil< 35 = 11 = 36 = 39 = 56 >nil

Note that the "nil<" precedes the first node and all nodes are linked by the "=" character (instead of the "–" one). It means that the output dynamic structure is doubly linked one:

Task solution

To transform the initial single linked structure into the doubly linked one it is enough to assign a required value to the Prev field of each node:

var
  p1, p2: PNode;
begin
  Task('Dynamic30');
  p2 := nil;
  GetP(p1);
  while p1 <> nil do
  begin
    p1^.Prev := p2;
    p2 := p1;
    p1 := p1^.Next;
  end;
  PutP(p2);
end.

After 5 test runnings we shall receive a message that the task is solved.


Circular dynamic structures: Dynamic55

Dynamic55°. A pointer P1 to the first component of a nonempty doubly linked list is given. Transform this list to the circular one by assigning the address of the first component to the Next field of the last component and the address of the last component to the Prev field of the first component. Output the address of the component that has been the last component of the given list.

Acquaintance with the task

After launching the program we will see that the input and output dynamic structures are displayed in a slightly different manner, for example:

     P1
nil< 19 = 94 = 51 = 41 = 55 >nil

                         P2
<< = 19 = 94 = 51 = 41 = 55 = >>

The "<<=" and "=>>" text means that the output chain of nodes is a circular double linked one:

Task solution

To solve the Dynamic55 task one should find the last node and link it with the first one:

var
  p1, p2: PNode;
begin
  Task('Dynamic55');
  GetP(p1);
  p2 := p1;
  while p2^.Next <> nil do
    p2 := p2^.Next;
  p2^.Next := p1;
  PutP(p2);
end.

In this program we "forgot" to link the first node with the last one by the Prev field of the first node. Therefore when the program will be started we will see the "–" character after the last node of the output list, for example:

               P2
nil< 38 = 24 = 91 - >>

To get a correct algorithm it is enough to add the following statement before the PutP procedure call:

  p1^.Prev := p2;

After 3 test runnings we shall receive a message that the task is solved.


PrevNext

 

 

Designed by
M. E. Abramyan and V. N. Braguilevsky

Last revised:
02.05.2010