Professional Documents
Culture Documents
Yu. L. Kostyuk
publishing house
2019
Machine Translated by Google
UDC 510.5
BBC 22.18.73
ISBN
The textbook corresponds to the program of the initial course in programming for
university specialties, focused on training specialists in the field of informatics and
computer technology. The book outlines testing methods, labor input studies, and proofs
of properties of algorithms. Simple algorithms from the most important classes are given
and studied: calculation of recurrent sequences; sorting and searching; recursive
calculations, set and graph algorithms, and simple linear algebra algorithms. Particular
attention is paid to the analysis of the effectiveness of algorithms. In the first part of the
lectures, algorithms and programs are written in Pascal, and in the second part of the
lectures, in C. The main elements of these languages are also briefly described. The
manual does not aim to study the whole variety of algorithms; it is only the first step
towards a more thorough and detailed study of them.
UDC 510.5
BBC 22.18.73
Reviewers:
Head of the Department of Automated Control Systems, Tomsk State
University of Control Systems and Radioelectronics, Doctor of Technical
Sciences, Professor A. M. Korikov;
Professor of the Department of Programming, Tomsk State
University, Doctor of Technical Sciences A. Yu. Matrosova
Foreword
The most important thing in the profession of a programmer is the ability to create
good programs. Everything else (knowledge of a programming language, translator,
operating system, ability to work quickly at a computer) is necessary only insofar as it
helps to write good algorithms and thereby develop good programs.
four
Foreword
languages that are further used in programs. At the same time, object-oriented language
tools are not considered at all, which are necessary only when creating large and complex
programs, and which only interfere at the initial stage of learning programming.
When it is required to take into account the features of a particular variant of the
Pascal language, the algorithms are presented based on Turbo Pascal® translators.
or Delphi® by Borland, or freeware translators Free Pascal or Lazarus. Unlike the Pascal
language, the C language (and also C++) is more strictly standardized, so any of the
available translators can be used to implement the programs in question on a computer.
Each lecture is equipped with control questions and tasks for independent work. The
tasks are recommended to the reader to implement on a computer, develop tests for
them and conduct testing.
Feedback, comments and suggestions on the book, please send to the following
address:
634050, Tomsk, Lenin Ave., 36, TSU, Institute of Applied Mathematics
ki and computer science.
E-mail: kostyukÿyÿl@sibmail.com
Machine Translated by Google
Lecture 1
Algorithms and programs. Testing.
Analytical Verification
1.1. Algorithms and programs
A person encounters algorithms everywhere in his daily life: any somewhat
complex action that can be divided into sequentially performed stages is an algorithm.
In everyday life, an intuitive understanding of the algorithm is quite enough: a person,
guided by common sense and his experience, clarifies the details along the way and,
in the end, gets the intended result.
Rice. 1.1
6 Lecture 1
If the executor of the algorithm is a person, then the algorithm may not be
specified very strictly and even not quite completely: a person can invent what
is missing in his description. If the executor is an automatic device, such as a
computer, then the algorithm must be determined absolutely precisely - the
machine cannot guess what the person meant when writing the algorithm if
he omitted something. Algorythms can be defined and written in many ways,
in particular using natural (Russian or English) language. However, it is difficult
to make such a record unambiguous for a human and almost impossible for a
computer. Therefore, to write algorithms, artificial programming languages
have been invented in which all actions are defined absolutely completely and
unambiguously.
Since the computer understands only its own internal (machine) language,
the algorithm must be written in machine language (then its
called a machine program). Creation of a machine program -
complex and painstaking work, since machine language instructions perform
simple actions and are encoded by numbers. Therefore, to implement even a
simple algorithm, a large computer program is required. The invention of
programming languages in the late 1950s finally freed programmers from
digging into machine instructions and led to a real revolution in programming.
Modern programming languages combine rigor and absolute unambiguity with
human comprehensibility. Their practical application became possible
only when special translator programs were created that translate algorithms,
write
Machine Translated by Google
Input data
A computer
Rice. 1.2
eight
Lecture 1
(which are easy to extend), so the programs in the text of this book are
written, as a rule, without descriptions.
It is necessary to distinguish between the concepts of an algorithm and a
program. The algorithm can be written in any way and is not fully defined, as
long as a person is able to understand it. The program must be “understood”
by the computer (or translator). It is said that the algorithm is implemented as
some kind of program. Therefore, one algorithm can correspond to several
different programs (even written in the same programming language).
1.2. Testing
The computer, when executing a translator program, acts according to
strictly formal rules: it is not able to understand the programmer's intention
and understand the idea of the algorithm underlying the analyzed program. It
follows from this that the program being translated should not contain any
syntactic error, i.e. the program must strictly comply with the rules of the
programming language. But since the program is written by a person (and it
is human to make mistakes!), Syntax errors are almost always present.
During the translation process, the translator detects such errors and issues
messages about them. The programmer must analyze the translator's
messages and correct errors. It should be noted that the repair process is not
always easy, especially since reported
Translations of a translator refer to that section of the program text in which
a syntax error was encountered, but not to the original cause of the error.
And even if the program was broadcast successfully, this does not mean at
all that it is flawless: it may well contain semantic, i.e. semantic errors.
In Pascal, when writing a program, reserved service words are used. The first
line is the word "program", then the name of the program. The second line contains
a description of the variables, beginning with the word "var". The type of these
variables is integer (integer), they can have a value from -2147483648 to
+2147483647, they occupy 4 bytes in memory. Curly brackets contain comments
that do not affect
program broadcast. After the word "begin" the program statements are written, they
perform the following actions:
1) the read statement requires entering (from the keyboard) a numerical
value for the variables a and b with a space between them, and at the end -
pressing the "enter" key;
2) an addition operation is applied to the values of the variables a and b , and its
result is assigned to the variable c;
3) the writeln operator displays (in the output window) the inscription 'c=', the
numerical value of the variable c, i.e. the result of the addition, after which it produces
a line feed of the output text.
The word "end" with a dot ends the text of the program.
Input example: 39 -14
output: s=25
End of example.
Machine Translated by Google
ten Lecture 1
Example 1.2. The program for calculating the roots of a quadratic equation
2
aÿx +bÿx+c=0:
All variables are declared with the real type , and can have a positive or negative
value up to approximately 1038. Unlike the integer type, the real type has an
approximate value, about 10 correct decimal digits.
In the considered examples, only one test is given, although in reality this may
not be enough. So, in example 1.2, the value
Machine Translated by Google
variable d may turn out to be negative, and then the calculation of the sqrt
function will crash, the program will not complete and will not display any
result. Therefore, for full-fledged testing, it is necessary to set tests, including
those to detect such situations.
12 Lecture 1
For more reliable testing, both of these methods should be used. Once
an incorrect result is found in any test, the cause of the error must be found
and corrected. This process is called debugging. Finding an error can be
tricky, because you need to find exactly the action in the program that
caused the error. Step-by -step testing is useful for finding a bug - executing
the program in interactive mode, tracking the intermediate values of
variables. This is possible for tests where the number of steps is not too
large.
of the theoretical study (proof) of the properties of programs. In this case, the program is
tested not for one specific set of input values, as in normal testing, but for a set of sets of
input values that satisfy some logical relation.
The idea of the proof is as follows. Any program in the course of its execution uses and
changes the values of variables. For such variables, there are two logical conditions called
precondition and postcondition. It is assumed that the precondition must be true before the
program is executed, and the postcondition must be true after the program is executed .
completion.
2) proof of the truth of the postcondition after the completion of the program under the
assumption of the truth of the precondition before the execution of the program.
Back in the 60s of the twentieth century, it was proved that any algorithm can be written
using only the following actions (operators) in various combinations:
where P(w) is the same condition as P(x), with each occurrence of x replaced by the right
side of the assignment (formula) w.
After performing all the actions in the formula w , the result of the calculations
is assigned to the variable x.
Unlike conventional mathematical notation, formulas are written in a line in programs. If
the formula is long, then you can make transfers,
Machine Translated by Google
fourteen
Lecture 1
but without duplication of operation signs. Variable names can consist of letters and/or
numbers, but must always begin with a letter. Constants
can be integer or real, in the second case, their record must contain a dot separating
the integer part from the fractional part. The type of variables is determined by their
description.
Arithmetic operations are denoted by signs (+, -, *, /) or words (div, mod). Unlike
normal mathematical notation, the multiplication sign "*" cannot be omitted. If both
integer arguments are involved in the operations (+, -, *), then the result type will also
be integer. If at least one of the arguments is real, the result will be real. The result of
the division operation "/" is always real. The div operation calculates the quotient of
the division of integers with the remainder discarded, and the mod operation
The order of calculations in the formula is from left to right, but taking into account
the priorities of operations. Parentheses change the order of evaluation: the operations
inside the parentheses are evaluated first.
Sequence of operators. If A and B are operators for which the following
conditions are satisfied (see Fig. 1.3):
{P} A {Q} and {Q} B {R}
A B
Rice. 1.3
then
{P} A; In {R},
i.e. a postcondition for A is a precondition for B.
A sequence can consist of any number of statements. If the sequence is taken
into “operator brackets” begin and end, then it can be considered as one operator.
Machine Translated by Google
Rice. 1.4
Rice. 1.5
16 Lecture 1
The condition P here does not change during the execution of the loop, it
is called the loop invariant. The loop ends when condition E becomes false, so
if the variables in condition E are not changed in statement A , then the loop
will repeat indefinitely!
The correctness of the considered relations follows from the meaning of
the Pascal language operators. Their application is useful in deriving pre- and
postconditions for the considered operators.
The proof of termination is often obvious if, for example, the program
consists of a sequence of assignments or a for loop. If the variables in the
while loop 's condition change in complex ways, then proving termination can
be tricky. In any case, it is necessary to determine under what condition the
loop will end - this condition will be part of the postcondition.
The proof of the truth of the postcondition after the end of the program, as
a rule, is far from obvious. To carry out such a proof, the following special
methods are used:
1) sequential enumeration of actions to be performed, used for a sequence
of statements in a program, when changes in logical relationships are tracked
in the course of execution of statements;
2) enumeration of variants, used for branching in the program, when the
entire range of values of the variables included in the precondition is divided
into subdomains and the proof is carried out separately for each subdomain;
Example 1.3. Let the precondition x=a, y=b be satisfied for numerical
variables x,y , where a, b are some numerical values. In a condition record, a
comma implies a logical connective "and". It is required to prove that after the
execution of the program:
z:=y; y:=x; x:=z;
Proof is a powerful tool for finding errors in a program. Let us assume that
the program (1.3) is written as two assignments: x:=y; y:=x. Then after the first
assignment: x=b, y=b, nothing has changed after the second one: x=b, y=b. The
last condition does not coincide with the required postcondition, i.e. there is an
error in the program!
Machine Translated by Google
eighteen
Lecture 1
The program in Example 1-2, which calculates the roots of a quadratic equation,
has a serious flaw. If the three numbers introduced define the coefficients of an equation
that has no real roots, then its discriminant will be negative. Then, when calculating the
square root of a negative value, an emergency termination of the calculations will occur.
Example 1.5. The program for calculating the roots of a quadratic equation
2
aÿx +bÿx+c=0 with discriminant check.
Finally, at the stage of inductive inference, we prove that P(n) will be valid
for n = k + 1 > n0. This implies that the statement P(n) is true for any n ÿ n0.
Let us show this for n = M such that M > n0. First we set k = n0. According
to the third stage of the proof, the statement will be true for n = n0 + 1. Applying
the third stage of the proof again for n = n0 + 1, we obtain the validity of the
statement P(n) for n = n0 + 2, etc., until we reach n = M.
Proof.
Basis. For n = 0 the sum Sn = 0, on the other hand, for n = 0 formula (*) is
true.
Assumption. Let formula (*) be true for n ÿ 0.
inductive inference. For n + 1, by formula (*) we obtain
Machine Translated by Google
twenty
Lecture 1
32 3 2
2nnnÿ ÿ 3 2 2( n1)ÿ 3( ÿ 6 n
ÿ ÿ ÿ1) (n
sn ÿ one
ÿ
ÿ ÿ (ÿn one)
one)
.
6
End of example.
Let us illustrate the application of the method of mathematical induction on
the example of a program for calculating factorial.
Example 1.7. Let the precondition nÿ1 be satisfied. It is required to prove
that after executing the program
f:=1; i:=2;
while i<=n do
begin f:=f*i;
i:=i+1
end;
Basis. If n=1, then f=1, i=2, since the loop will never be executed. Thus, the
basis is valid.
Assumption. We assume that for n=k, kÿ1 ,
condition f=1*2*...*k, i=k+1.
inductive inference. The whole difference between executing the
program for n=k+1 and executing it for n=k is that at first the program will
be executed in exactly the same way as with n=k, and then the loop will be
executed one more time for i=k+1 . Since, by assumption, before the last
execution of the loop f=1*2*...*k, then after the last execution of the loop
(after the execution of the operators f:=f*i; i:=i+1) it will be true:
f=1*2*...*k*(k+1)=1*2*...*n, i=k+2=M+1,
Q.E.D.
End of example.
Machine Translated by Google
invariant method. The method of proof using the invariant is as follows. Let the precondition
be written as (P, Q) and the postcondition as (S, Q), i.e., they have a common part Q called the
invariant
volume.
f:=1; i:=2;
while i<=n do
begin f:=f*i;
i:=i+1
end;
f=1*2*...*n, i=n+1.
Proof. Termination is proved in Example 1.7. After performing the assignments in the first line
of the program, the precondition for the loop operator is: n=ÿ1, i=2, f=1. We write the last equality in
the form:
f=1*...*(i-1). We write the postcondition as follows: nÿ1, i=n+1, f=1*...*(i-1). The validity of the equality
i=n+1 follows from the fact that after the end of the execution of the loop i>n, but since the variable i
increases by 1 each time the loop is executed, it cannot be greater than
than n+1. The equality f=1*...*(i-1) is an invariant here. Indeed, by directly checking the statements
in the program, we are convinced that the execution of two actions in the loop body changes the
variables f and i, but leaves the invariant valid. End of example.
Machine Translated by Google
22 Lecture 1
The most important thing in proving by the invariant method is the ability to
formulate the condition in the form of an invariant, which requires some skill. At
the same time, the use of an invariant usually simplifies the proof of the program.
Tests for the program in the previous two examples. Black box tests :
Then the proof for one of the programs with respect to this set of variables is
also valid for the other program. In this case, programs can perform various actions
on other variables that are not included in the set x1, . . . ,
xn.
for i:=a to b do S
and
and
End of example.
The considered example is a special case of the equivalence of the loop operators while and
for. Let us consider a number of other cases of the equivalence
laziness.
Example 1.10. Equivalence of compound statements that differ in the order in which they are
executed. If S1 and S2 are statements that use different variables, then the sequences
End of example.
End of example.
Arrays in Pascal. An array is a numbered collection of variables of the same type. An array
description specifies the type and bounds for the numbers of its elements. For example, description:
defines a one-dimensional array of real type variables numbered from 1 to 100. Any of the array
elements can be used in the same way as a simple real type variable, but for this you need to
specify the index - the number of this element, for example:
the value of the index or index expression must be of integer type and be at least 1 and at most
100.
Machine Translated by Google
24 Lecture 1
The considered examples define static arrays, their sizes are given by constants in
the description and cannot be changed during calculations.
by program.
calculates the minimum value in the integer array A among elements from 1st to nth.
Machine Translated by Google
Proof. Using the equivalence of for and while loops, we can write a
precondition: i=2 and a postcondition: i=n+1. Then the loop invariant will be as
follows:
min= min{A[1],...,A[i-1]},
where the min function denotes the minimum value from the set of arguments.
Black box testing :
with the program from example 1.13. These programs are equivalent with respect
to the variables min and i. As for the variable k, it is easy to prove that the following
invariant holds for it:
k= argmin{A[1],...,A[i-1]},
Machine Translated by Google
26 Lecture 1
where the function argmin denotes the number of the minimum value among
the arguments written in brackets.
The tests for this example can be the same as for example 1.13.
End of example.
The method of equivalents is useful both for proving programs and for developing
them. An experienced programmer, analyzing a problem, tries, first of all, to adapt
the algorithms and programs known to him for solving it, making the necessary
changes to them. If he succeeds, then the new program will be equivalent to the old
program with respect to some variables. This method speeds up the development of
the new program itself, simplifies its proof, and increases its reliability (because the
old program has been tested and investigated before!). But for this, the programmer
must know not only a large number of typical programs, but also the methods of their
proof.
The outer loop iterates over all numbers between 2 and n, while the inner loop
checks each number i to see if it is evenly divisible by any of the numbers less than
i.
Proof for outer loop.
Precondition for outer loop: i=2.
Machine Translated by Google
Postcondition: i=n+1.
Invariant: “all prime numbers from 2 to i-1 have been computed.
Proof for the inner loop.
Precondition for inner loop: j=2,p=0.
Postcondition: j=n,p=0, then the number i is prime,
or: j<n,p=1, then the number i is not prime.
Invariant: "number i is not divisible by numbers from 2 to j-1
and: (the number is not divisible by j,p=0)
or: (number is divisible by j,p=1)”.
End of example.
28 Lecture 1
In addition, when testing a program using the white box method, it is very
effective to insert into it operators for checking pre- and postconditions,
invariants. Such operators, when a condition is violated, should display a text
message that will help you find the error. Subsequently, during the operation
of the finished program, these operators can be commented out.
one program will run faster than another given the same input on the same computer.
Therefore, for each program, it is necessary to calculate the complexity , which is a
function of the dependence of the number of elementary actions on the size of the
input data, for example, on the size of the array n. In this case, it is sufficient to
estimate the labor intensity at
n ÿÿ.
T(n) = A n + B,
since the number of loop executions is directly proportional to n, and the number of
actions inside the loop does not exceed some constant A. As n ÿÿ, B can be neglected.
The real (physical) execution time of the program depends not only on the speed of
the computer, but also on what programming language the program is written,
on what translator it is translated. Therefore, the form of the labor intensity function is
written up to a constant - a factor in front of the function, using the O-large notation,
and then one speaks of the order of growth of the labor intensity function. Therefore,
for the complexity of the program from Example 1.13, instead of T(n) = A n + B , it
suffices to write O(n), here the order of complexity is linear.
thirty Lecture 1
2
n times , i.e. total - n once. As n ÿÿ, the quantities B and C can be
2
brecht. The order of complexity is O(n ) is quadratic.
End of example.
Example 1.17. The complexity of the program from example 1.15 (calculating all prime
numbers in the range from 2 to n) in the worst:
2
T(n) = A n + B n + C,
since the total number of executions of the inner loop does not exceed
amounts:
2
1+2+3+ . . . + (n ÿ 2) = (n ÿ 1) (n ÿ 2) / 2 ÿ n /2.
2
Thus, the order of complexity is O(n ) is quadratic.
End of example.
The program from Example 1.15 can be noticeably sped up if, in the inner loop, we
check the divisibility of the number i not by all numbers less than i, but only by numbers less
than or equal to i , since if the number i is divisible
by j, then it is also divisible by i/j.
Example 1.18. Faster program for calculating all prime numbers in the range from 2 to
n:
for i:=2 to n do
beginj:=2; p:=0; x=sqrt(i);
while (j<=x)and(p=0) do
if i mod j = 0 then p:=1
else j:=j+1;
if p=0 then writeln(i)
end;
since the total number of executions of the inner loop does not exceed:
1 ÿ 2 ÿ 3 ÿ...ÿ n ÿ nÿ n .
When comparing two algorithms (or programs that implement them) with
different speed (or required memory) functions, the best algorithm should be
considered the one whose function grows more slowly. ) is quadratic
2
For example, O(n) is linear complexity, better than O(n
laboriousness. So, with an increase in n by 10 times, the running time of an
algorithm with linear complexity will increase by 10 times, an algorithm with complexity
O(n 3/2) - 31 times, and the algorithm with quadratic complexity - 100 times!
If the algorithms have the same order of complexity , then the algorithm is
better, in which the factor A in front of the complexity function is less.
fear.
32 Lecture 1
16. What is the proof of program properties? What does it mean to prove the termination of a
program?
17. What are precondition and postcondition, how to set them?
18. What is the structure of programs whose properties are proved using a sequential enumeration
of the actions to be performed?
19. What is the structure of the programs, when proving the properties of which we use
Is there a list of options?
20. What is the structure of programs whose properties are proved using the method of
mathematical induction?
21. What is the structure of programs whose properties are proved using the invariant method?
22. What is the structure of programs whose properties are proved using the abstraction
method?
26. An integer two-dimensional array of n rows and m columns is given. Write a program to
calculate the sums of its elements in all columns. Prove its correctness and derive the
complexity.
27. The program from example 1.18 can be further accelerated if, in the inner loop, the divisibility
of the number i is checked not in a row by all numbers that are not greater than ÿi, but only by
previously calculated prime numbers not greater than ÿi. Derive the labor input formula, taking
into account that for large n the number of prime numbers not greater than n tends to n/ln n.
Machine Translated by Google
Lecture 2
Recurrent Algorithms
ÿ xa kk
ÿ
, k ÿ
0,1, ..., p ÿ
one,
ÿ (*)
kk ÿ ( ,
xfkxÿ
ÿ
one
,x k ÿ
2 ,..., xkp _
ÿ ), kppÿ ÿ , one, ...
Example 2.1. The sum of any elements {a1, . . ., an} can be represented as a
recurrent sequence of rank 1:
ÿS 0,
ÿ
0
ÿ
ÿ
SS ai ÿ ÿ ii 1 ÿ
i,
ÿ
12, ..., . n
S:=0;
for i:=1 to n do
S:=S + a(i);
Here a(i) is the formula for calculating the i-th element of the sum.
End of example.
Machine Translated by Google
34 Lecture 2
In some cases, a recurrent sequence may have a limit as n ÿ ÿ. Example 2.2. Infinite
sums (series) are given by the relations:
ÿSf ,one
ÿ
one
ÿ
ÿ SS fk
ÿ ÿ kk 1 ÿ
k , ÿ
2, 3, ...
in which the terms f k tend to zero as k ÿ ÿ. In this case, the terms themselves can also be
specified as a recurrent sequence:
ÿ faone
ÿ
,
ÿ
ÿ fpkfk
k ( , ), k
ÿ
ÿ
one
ÿ
2, 3, ...
Example 2.3. The approximate value of the sin x function can be calculated
using the sum
35 2k1 ÿ
xx ÿ ÿ ÿ ÿ k x
sin xxÿ
ÿ
,
one
...( one)
3! 5! (2 k1)!
ÿ
for which the recurrence relations in Example 2.2 are valid. By dividing the expression for
the kth term of the sum:
k
x 2k1 ÿ
fk
ÿ
one
ÿÿ
( one)
(2k1)!
ÿ
Recurrent Algorithms 35
2 k3 ÿ
k 2
ÿ x
fk ÿ
ÿÿ
( one) ,
(2k3)!
one
ÿ
ffk ÿÿ
k , k ÿ
2, 3, ...
(2kk
ÿ
one
ÿ 1)(2 2)
ÿ ÿ
The program for calculating the sum with a given accuracy eps:
S:=x; f:=x; k:=2;
while abs(f)>=eps do begin
f:=-f*x*x/((2*k-1)*(2*k-2));
S:=S+f;
k:=k+1
end
The termination of the program follows from the fact that fk ÿ 0 as k ÿ ÿ. Here the
invariant is the same as in example 2.2:
f = fk -1, S = Sk-1,
The complexity of the algorithm (the number k of cycle executions) can be
determine from the formula:
x 2k1
ÿ
fk ÿ
ÿÿ ,
(2k1)! ÿ
End of example.
For a sum with alternating terms, as in Example 2.3, the calculated value of the
sum will differ from the true value of the limit by no more than the absolute value of
the first discarded term. If all the terms have the same sign, then to determine how
many terms need to be summed, one has to derive the formula of the so-called "residual
term of the sum." More
Moreover, a sum containing terms of the same sign may not even have a limit (i.e. be
infinite). Here are some more examples of recurrent sequences,
having a limit.
Machine Translated by Google
36 Lecture 2
Example 2.4. Consider the recurrent sequence for calculating the square root of a
given number, which was already known to Heron:
ÿ s0 ÿ
one,
ÿ a ÿ
ÿ
ÿ
sk ÿ
one
sk ÿ , k 1, 2, ...
sk ÿÿ ÿ
ÿ ÿ
2
ÿ
one
ÿ
ÿ
ÿ ÿ ÿ
one
one
ÿ a ÿ one ek2
a ae .
ÿ
sk ÿ ÿ
ae kÿ ÿ ÿ
ÿÿÿ one
ÿÿ
k
2 2
ÿ
aeÿ aeÿ
one
ÿ ÿ
ÿ k ÿ
one
ÿ k ÿ
one
one)
1 (1
2ÿ ÿ ÿ ÿ ÿa ÿ
es ÿ one aÿ a ÿ 0,
2
and then
2
one ek ÿ
one
one
ek ÿÿ
ÿ 0, ek ÿÿek ÿ
one , k ÿ
2, ...
2 ae ÿ k ÿ
one
2
The resulting inequalities assert that, starting from e1, all ek are nonnegative and each
subsequent error is less than the previous one by at least a factor of 2. That is, e1/e2 ÿ 2,
k-1
e1/e3 ÿ 4, …, e1/ek ÿ 2 , where
one ÿ a
k log 2
.
2ÿ
Therefore, lim ÿ e
0k . Moreover, starting from s1 , all sk are decreasing.
k ÿÿ
s:=(1+a)/2; e:=eps;
while e>=eps do begin
s1:=(s+a/s)/2;
e:=s-s1; s:=s1
end
Machine Translated by Google
Recurrent Algorithms 37
The complexity of the program, i.e. the number of iterations of the loop, has
order O(log (1+a)/ÿ).
End of example.
Example 2.5. Let a continuous function y = f (x) be given on the interval [a, b] ,
and the values of the function at the ends of the interval f (a) and f (b) have different
signs. Then, on this interval, the function has at least one root x0 such that f (x0) = 0.
The problem is to calculate the root of the function with a given accuracy ÿ / 2 i.e. it is
required to find such z that ,
the following inequality holds:
| x0 – z| ÿ ÿ / 2 .
The dichotomy method for solving this problem is that each
At the next step, the interval is divided in half and one of the half intervals where the
root can be located is determined. One can construct the following recursive
sequence of pairs of numbers {ui , vi}:
ÿ uavb
ÿ ÿ
0 , 0 ,
ÿ
ÿ u
1iÿ
ÿ
UV
ii ÿ,
1 ÿ ÿ (uv ii 2, for sign ( ) sign ( ( fuv fu )/ i ÿ i
ÿ i )/ 2),
which converges to the desired root. The program calculates its limit x with the given
precision eps/2:
else u:=x;
x:=(u+v)/2
end
The complexity of the program, i.e. the number of cycle executions is determined
by the formula:
ÿ ba
ÿ
ÿ
k ÿ
log ÿ .
2 ÿ
ÿ
ÿ ÿ
End of example.
Machine Translated by Google
38 Lecture 2
one
Pn (x) axax
ÿ
n ÿ n ÿ
one
ÿÿÿÿ10 ÿ
one
ÿÿÿ a )xa
one 0 ,
From this formula, one can obtain the following recurrence relation for computing
a polynomial for a given value of x and coefficient
elements a0, a1, …, an :
ÿ Pa0 ÿ
n ,
ÿ
PP xa ÿi
ÿ i
ÿ
ÿ
one niÿ , i ÿ
12, ..., . n
P:=a[n];
for i:=1 to n do
P:=P*x+a[ni];
in which the coefficients of the polynomial are given as elements of the array a.
End of example.
Example 2.7. From the formula in Example 2.6, you can get another recur
an annuity relation for calculating the digits a0, a1, …, an of a nonnegative integer
Pn for a given value of the base x:
ÿ ai P ÿ
ni
ÿ
mod x ,
ÿ
ÿPP xi div , 0,1, ..., ,n P 0,
ÿ ÿ
ÿ
ni 1 ÿÿ
ni
ÿ
ni ÿ
where the mod operation is the calculation of the remainder of the division, and div
is the division with the remainder discarded. This assumes that the number of digits
Machine Translated by Google
Recurrent Algorithms 39
one
ÿ
one,
ÿ
ÿ fffkÿ ÿ kk 1 2, 3, ...,
ÿ
ÿ
k ÿ, 2
f1:=f2; f2:=f3
end
Let us prove that the De Moivre formula is valid for this recurrent sequence:
ÿÿ n nÿ
one
ÿ
1ÿ 5ÿ ÿÿ 5ÿ one
.
ÿ
f n
ÿ ÿ
ÿÿ
ÿ ÿ ÿ
(*)
5 ÿ ÿ
2 2 ÿ ÿ
ÿ
ÿÿ
ÿ ÿ ÿ ÿ ÿÿ
Proof.
Basis. For n = 0 and n = 1, we check by a simple substitution into the
formula (*).
Assumption. Let formula (*) be true for n ÿ 0.
Machine Translated by Google
40 Lecture 2
n n n n
ÿÿÿÿÿ5
ÿ ÿ
one one
ÿÿ ÿ ÿÿ
one ÿ ÿ ÿÿ ÿÿ ÿÿ ÿ5 ÿ1 ÿÿ ÿÿ 5ÿ ÿÿ ÿÿ 5 ÿ ÿÿ ÿ one
ÿ
ÿ1ÿ
ÿ ÿ ÿÿ ÿÿ ÿÿ 5ÿ 1ÿ ÿ ÿ ÿ ÿ ÿ 5 ÿ ÿÿ ÿ
f n1
ÿ
ÿ ÿÿÿÿ ÿ
2 2 ÿ 5ÿ ÿÿ ÿÿ ÿÿ
ÿÿÿÿ 2 2
ÿÿÿ ÿÿÿ
_ ÿ1n _ ÿ1n
one 1ÿ 5 one 5 ÿ
ÿ
,
2 2
ÿÿÿ
given that:
2
ÿÿÿ one 5 ÿ 1 5
ÿÿ ÿ1ÿÿ .
2 2
ÿÿÿ
mula (*), is called the golden ratio. Note that it is expedient to apply this
formula for sufficiently large n. In this case, calculations must be performed on
real ones, i.e. approximate numbers, and round the result to the nearest
integer. Since the absolute value of the second term in the formula (*) is less
than 0.5, it can be neglected. End of example. Example 2.9. The Euclidean
algorithm that calculates the greatest common divisor gcd(a, b) of two
integers a ÿ 0, b ÿ 0 is based on the following invariant relations:
1) GCD(a, 0) = a;
2) gcd(a, b) = gcd(b, a);
3) gcd(a, b) = gcd(a mod b, b), a ÿ b > 0.
The first two relations are obvious. Let's prove the third. First, note that
the operation r = a mod b is equivalent to repeatedly subtracting b from a until
0 ÿ r < b. Therefore, it suffices to prove that
Recurrent Algorithms 41
abÿ
a b a-b b
But then ÿÿ
, wherein , as well as - both are intact, while
c c c c c
a
me like can be integer only if c = d. It's a contradiction
c
and proves the third relation.
From these relations, one can construct such a sequence of pairs
{xi , yi} such that gcd(xi , yi) = gcd(a, b), max(xi , yi) > max(xi + 1, yi + 1):
ÿ xayb
0
ÿ
, 0
ÿ
,
ÿ
ÿ xi1ÿ
ÿ
xyymod
iii 1 , ÿ
ÿ
y , for i xyii ÿ ÿ 0,
ÿ
ÿ yyxx
1ÿ
ÿ
iiii mod , ÿ one
ÿ
x , for i yxii ÿ ÿ 0.
x:=a; y:=b;
while (x>0)and(y>0) do
if x>=y then x:=x mod y
else y:=y mod x;
if x>0 then no:=x
elsenod:=y
The complexity of the program, i.e. the number of executions of the loop is determined by
the numbers a and b. In this case, the worst case will be if for you
fulfillment of the conditions:
fk ÿ max(a, b) > fk – 1,
where fk , fk – 1 are the numbers of the Fibonacci sequence, when the
operation fk mod fk – 1 is equivalent to the operation fk – fk – 1, and, in addition,
Livo:
max(a, b) = fk , min(a, b) = fk – 1 .
Then k (number of iterations of the loop) will be the maximum possible. Neglecting the
second term in De Moivre's formula and taking the logarithm
left and right sides, we get:
k ÿ flog
ÿ log
ÿ2 log
( 5k()5 ) ÿ
ÿ
2 fk ,
k ÿ ab ÿ ÿ, ab
max( ) log
2
2 log ( 5 max( , )) 1.42 log
ÿ
,
ÿ
42 Lecture 2
Thus, the complexity (in the worst case) of Euclid's algorithm has
the order is O(log max(a, b)).
End of example.
Example 2.10. A program to quickly raise a number x to a positive integer power
p. The result is the number z:
The odd function returns "true" if its argument is an odd integer, and "false"
otherwise. For greater efficiency, this function can be replaced by an expression
consisting of
bitwise operation and on the binary representation of integers and comparing the
result with the number 1:
(s and 1)=1.
The operation s div 2 can be replaced by a bitwise shift operation
th representation of s to the right by 1 bit:
s:=s shr 1;
The termination of the program follows from the fact that before the
execution of the cycle sÿ1, and at each execution of the cycle s decreases (but
remains non-negative, i.e. s=0 after the end of the cycle).
Loop precondition: z=1, s=p, y=x; postcondition: s=0.
s = x p
Invariant: z*y . The correctness of the invariant follows from
wearing:
s s-1 s/2
z*y = (z*y)*y = z*(y*y) ,
Let's count the number of executions of the loop, taking into account that
one or two multiplications z*y and y*y are performed at each execution. At every
Machine Translated by Google
Recurrent Algorithms 43
End of example.
1. Prove the correctness of the program that calculates the sum of the expansion of the function
sin x, by the invariant method.
2. Approximate value of the cos x function:
24xx _ 2n
n x
cos 1 ÿ ÿ ÿ x ... ÿ ÿ ( one) .
2! four!
(2)!n
Write down the recursive relation for the elements of the sum and the program for calculating cos
x for a given value of x with a given accuracy ÿ.
3. Write a program that enters a value for x and a given precision ÿ and you
calculates x using Heron's formula, counting how many iterations will be performed in the loop and
an estimate of the number of iterations in the worst case. Check the operation of the program on
tests for x equal to respectively: 0.000001, 0.0001, 0.01, 100, 10000, 1000000 for different values
of ÿ.
4. Write and debug a program that calculates the square root of a number using the Heron formula
and (for comparison) using the standard sqrt function. Determine (using a counter in a loop) how
many terms of the sequence must be calculated in order to achieve the relative accuracy of
calculating the square root of 10–6 from the numbers 0.0001, 0.01, 0.5, 2, 100, 104
, 106.
5. Write a program that introduces the boundaries of the interval a, b and the given accuracy 2
3 – 7x
ÿ, and calculates the root of the function y = x + 9x – 8. Typing times
personal boundaries, calculate all the roots of this function.
6. Write a program that introduces the boundaries of the interval a, b and the specified accuracy 3
ÿ, and calculates the root of the function y = x – 10 x + 35 x 2 – 40 x + 24
four
.
Using this program, find the roots of the function on the intervals: [0.5, 1.5], [1.5, 2.5], [2.5, 3.5],
[3.5, 4.5].
Machine Translated by Google
44 Lecture 2
7. Write a program that enters the base of the number system, and then an integer written in this
system. After that, it enters the base of the second number system, calculates and displays the
representation of the number in the second number system. Come up with principles for
representing numbers with a base greater than 10. Develop and justify tests for this program, test
it for numbers with bases: 2, 8, 10, 16.
8. Prove the correctness of the program that calculates the Fibonacci numbers using the inva method
riants.
9. Write a program that calculates the nth Fibonacci number from the recurrent sequence and from
the truncated Moivre formula without the second term. Choosing n, find out from which number,
using the truncated Moivre formula, you can calculate the Fibonacci numbers with an accuracy of
0.5. With an accuracy of 0.001?
10. Write a program that calculates the GCD for two input integers. Develop and justify tests for it,
conduct testing and debugging. Provide a counter to calculate the number of loop executions.
For various input numbers, compare the value of the counter with the estimate of the complexity
of the Euclid algorithm.
11. Write a program that enters a number x ( double type), a positive integer
p
p and calculates x by multiplying the number x by itself (p - 1) times, and also accelerated
algorithm. Test the program for various x: 2, 1.1, 1.01, 1.0001, and various p: 10, 100, 1000.
Compare the results (output with a relative accuracy of 15 digits) obtained by these two methods.
Machine Translated by Google
Lecture 3
Search and sort
The task of the search is as follows. Let an array A of n elements, numbered from 1 to n ,
and some value p (search) be given. It is required to find a number i such that: A[i]=p.
all elements:
i:=0; k:=1; while
k<=n do
if A[k]=p then begin
i:=k; k:=n+1 end
else k:=k+1;
46 Lecture 3
Example 3.2. Search in an ordered array. Let the array be ordered in non-
decreasing order:
A[1]ÿ A[2]ÿ ...ÿA[n].
Let's define the region of "suspicious" elements in the array in this way: if an
element with the value p exists in the array, then it exists inside this region. Let us
denote the number of the initial element of the region by the variable b, and the number
of the final element by the variable e. Before the start of the algorithm b=1,e=n.
The search is called dichotomous, because at each step of the algorithm, the area
of suspicious elements is halved. To do this, the number of the element with in the
middle of the area is calculated using the formula:
c=(b+e)div 2.
Two cases are possible:
1) A[c]<p. Then the required element can be among:
A[c+1],...,A[e];
2) A[c]ÿp. The element you are looking for can be among:
A[b],...,A[c].
Note that the area of suspicious elements is halved, even if there were only 2
elements in it.
Postcondition: b=e.
Invariant: the required element (if it exists) is among:
A[b], ...,A[e].
Let us calculate the complexity of the algorithm. Let:
2m - 1 < k ÿ 2 m , (*)
Machine Translated by Google
Note that by changing only lines 5-6, but not changing line 4, we
we get a looping algorithm!
End of example.
48 Lecture 3
end;
. . .
if j=n, then n – 1 inversions.
Total inversions: 1 + 2 + + (n . . –. 1) = n (n – 1)/2.
Since when an inversion is detected (the condition X[i]<=X[i+1] is false) in
the algorithm after the exchange of values, the number of inversions decreases
by 1, sooner or later all inversions will disappear. But then, while the loop is
running, the variable i will increase at each step and, in the end, will become
equal to n, after which the loop will end.
An inversion for some i can be detected if:
X[1]ÿX[2]ÿ ... ÿX[i], X[i]>X[i+1]. (*)
Therefore, to eliminate one inversion, it will take i cycle steps to get from the
1st element of the array to the i-th one. In the worst case, when condition (*) is
satisfied, the following is also true: X[1]>X[i+1]. Then, for the condition to be
fulfilled:
X[1]ÿX[2]ÿ ... ÿX[i+1], (**)
R(i) = 1 + 2 + . . . + i = i (i + 1)/2.
Then, to eliminate all n (n - 1)/2 inversions, the loop must be executed T(i) times:
3
T(i) = R(1) + R(2) + . . . + R(n – 1) ÿ n /6.
3
Thus, the complexity in the worst case is of the order O(n ).
Machine Translated by Google
fifty Lecture 3
Note that the complexity is at its best when the array is already completely
ordered, has order O(n). End of
example.
In this case, the cycle invariant remains the same, but in the worst
case, the elimination of each inversion will require exactly two cycle steps,
and there will be n (n – 1) steps in total. Thus, labor intensity at its worst
2
will have order O(n ).
After changing the algorithm, the worst-case complexity decreased by
about n/6 times. Thus, an array of 300 elements will be processed 50 times
faster, and an array of 30,000 elements will be processed 5,000 times faster!
End of example.
Example 3.7. Exchange sorting algorithm. It can be considered
further improvement of the simplest sorting algorithm:
for i:=1 to n-1 do
beginj:=i; while
(j>0)and(X[j]>X[j+1]) do
begin
z:= X[j+1]; X[j+1]:=X[j]; X[j]:=z;
j:=j-1end;
end;
Since it uses two nested loops, to prove it, you should use the abstraction
method, analyzing the inner and outer loops separately.
52 Lecture 3
Example 3.9. Selection sort algorithm. In the algorithm, in the inner loop,
the minimal element is selected from the elements in the range from the jth
to the nth, after which it is exchanged with the jth element.
{precondition: j=1} for
j:=1 to n-1 do begin k:=j;
{precondition: i=j+1, k=j}
for i:=j+1 to n do
if A[k]>A[i] then k:=i;
{postcondition: i=n+1}
{invariant: k = argmin(A[j],...,A[i-1])}
z:=A[j]; A[j]:=A[k]; A[k]:=z
end;
{postcondition: j=n}
{A[1]ÿA[2]ÿ,...ÿA[j-1]},A[j-1]ÿmin{A[j],...,A[n]}
Postcondition: A[1]ÿA[2]ÿ,...ÿA[n].
Labor intensity. Total number of executions of the inner loop:
1+2+ . . . + (n - 1) = n (n - 1)/2.
2
Those. complexity O(n ) for both the worst and the best.
End of example.
After the next execution of the inner loop, the largest among the first i elements
will be in the i-th place in the array. The total number of executions of the inner loop
2
is n (n - 1)/2, Labor intensity: O(n ).
End of example.
Machine Translated by Google
The element In[i] means that if the array A is sorted, then the element A[In[i]]
will be located at the i-th place.
Modification of the sorting algorithm for indirect ordering:
1) first, the elements of the array In must be assigned initial values:
In[1]=1, In[2]=2, . . ., In[n]=n;
2) everywhere in the program where the array element A[j] is used in the opera
comparison radio, replace A[j] with A[In[j]];
3) everywhere in the program where the array element A[j] is used in
the assignment, replace A[j] with In[j].
Any sorting algorithm can be used for modification.
End of example.
Example 3.12. Modification of dichotomous search in indirect mention
row array A:
Machine Translated by Google
54 Lecture 3
b:=1; e:=n;
while b<e do
begin
c:=(b+e)div 2; if
A[In[c]]<p then b:=c+1 else e:=c
end;
if A[In[b]]=p then i:=b else i:=0
End of example.
n:=100;
SetLength(A,n); SetLength(B,n);
SetLength(C,10,15);
The numbering of elements in a dynamic array starts from zero:
A[0],A[1],. . ., A[n-1];
C[0,0],C[0,1],. . .,C[0,14],
. . .
C[9,0],C[9,1],. . .,C[9,14].
Machine Translated by Google
After the arrays are no longer used in the program, you can free the memory:
SetLength(A,0);SetLength(B,0);
SetLength(C,0,0);
End of example.
Example 3.14. Dynamic array program:
programex14;
var X: array of integer;
n, i, z: integer;
begin readln(n); SetLength(X,n); for i:=0 do n-1
do read(X[i]);
i:=0;
while i<n-1 do
if X[i]<=X[i+1] then i:=i+1
else begin z:=X[i]; X[i]:=X[i+1];
X[i+1]:=z; i:=1
end;
for i:=0 do n-1 do write(X[i],' ');
writeln; SetLength(X,0); end.
First, the program enters the number n of elements in the array X and
allocates memory for it. After that, in a loop enters the values of the elements
array X, from number zero to n-1 inclusive. Then the array X is sorted by
the simplest algorithm and output in a loop. In the output, a space is printed
after the value of each element to separate one number from another. At
the end, the memory allocated to the array X is freed.
End of example.
Remapping standard input and output. When executing a program, instead of
standard keyboard input and screen output, you can do input from a file and output
to a file. To do this, you need to create an input file and write the input data into it as
if it were entered from the keyboard (including all spaces and newlines in the input).
This file must be written to the same folder where the executable program is written,
in which the input of such data is provided.
Machine Translated by Google
56 Lecture 3
An in.txt file can be created using Notepad or Far. The out.txt file is created
when prog.exe is executed and can then be viewed in Notepad or Far.
Using files for input and output is especially useful when testing a program,
because after discovering and correcting any bug in it, it is necessary to retest it on
the same tests on which it was tested earlier.
Another way to reassign standard input and output is to write a call to standard
procedures at the beginning of the program: reset to reassign input and rewrite to
reassign output. For example, to redirect input and output to in.txt and out.txt files ,
responsible:
reset(input,'in.txt');
rewrite(output,'out.txt');
program ex6;
varn,d,r,i: integer;
begin rewrite(output,'in.txt');
readln(n,d,r); {d - range of numbers}
randseed:=r; {r - initial random number}
writeln(n);
for i:=0 to n-1 do
write(random(d):5);
writeln;
end.
Machine Translated by Google
First, values are entered for the variables n, d, r. Prior to generation, the
standard randseed variable is initialized to r. The entered value n is output to the
output file , followed by the line feed of the output. After that, random integers from
the range from 0 to d-1 inclusive are generated in the loop and written to the file, 5
character positions are allocated for each number.
In the future, the in.txt file can be used as input for testing the number sorting
program.
End of example.
Although the numbers generated by the random function are called random,
they only simulate randomness. A computer is a deterministic system; in principle, it
does not allow any accidents.
The standard random function generates numbers according to the recursive
formula:
xi+1 = (aÿxi + c) mod m,
where a, c, m are special constants (integers), xi , xi+1 are the previous and
next elements of the random sequence, their value is stored in the standard
randseed variable.
When the random(d) function is called, the final result of f is calculated by the
formula:
f = (xi+1 / m) mod d,
1. Carry out a complete proof by the method of the invariant of the program for searching for an
element in an unordered array. Prove that if the array has several elements equal to p, then
the program will calculate the smallest number among them.
2. Change the program for finding an element in an unordered array so that in
if the array has several elements equal to p, then the program you
counted the largest number among them. Carry out a complete proof of this fact.
Machine Translated by Google
58 Lecture 3
3. Carry out a complete proof by the invariant method of the program for the dichotomous search
for an element in an ordered array. Prove that if the array has several elements equal to p,
then the program will calculate the smallest number among
them.
4. Change the program for dichotomous search for an element in an ordered array so that it
searches for the element equal to p with the largest number. Carry out a complete proof of this
fact.
5. Carry out a complete proof by the method of the invariant of the program for removing repetitions
floating values of elements in an ordered array.
6. Carry out a complete proof by the method of the invariant of the program for searching for the
beginning and end of an ordered segment of maximum length in an array.
7. Write a program that inputs the number n, then allocates memory for the n elements of array A,
and inputs n elements into array A. After that, it searches for the beginning and end of the
ordered segment of maximum length, and then prints its beginning and end. Create tests for
the program using the black and white box method and conduct testing.
8. Carry out a complete proof by the program invariant method of the improved simple sorting
algorithm. What makes it work faster?
9. Carry out a complete proof by the method of the invariant of the exchange sort program
rovki.
10. Carry out a complete proof by the method of the sorting program invariant
inserts.
11. Carry out a complete proof by the method of the invariant of the sorting program.
boron.
12. Carry out a complete proof by the invariant method of the bubble program
sorting.
13. Write a program that inputs the number n, then allocates memory for the n elements of array
A, and inserts n elements into array A. After that, it sorts it with selection sort, and then outputs
its elements. Create tests for the program using the black and white box method and conduct
testing.
14. Write a program that inputs the number n, then allocates memory for the n elements of array
A , and inputs n elements into array A. After that, indirectly ordering
Eats it with an insertion sort algorithm, and then puts its elements in order
in pure form. Create tests for the program using the black and white box method and
conduct testing.
15. Write a program that inputs the number n, then allocates memory for the n elements of array
A, and inserts n elements into array A. Then indirectly sorts it with a bubble sort algorithm,
inputs the search value p, performs a dichotomous search, then outputs the number of the
element equal to p in the array
Machine Translated by Google
ve A. Create tests for the program using the black and white box method and conduct
testing.
16. Write a program that inputs the numbers n, d, r and the character string S with the name for
a file, then redirects standard output to that file. After that, it outputs the number n to the file,
generates and writes to the file n random numbers from the range from –d to +d for a given
initial value of r. Create tests for the black-and-white-box program and conduct testing.
17. Write a program that inputs a character string S with the name of the input file (which was
written by the program from the previous task), then reassigns standard input to this file.
Reads the number n from the file , allocates memory for n
elements of array A and inserts n elements into array A. After that, it indirectly orders it with
selection sort and then outputs its elements in ordered form without repetition. Create tests
for the program using the black and white box method and conduct testing.
Machine Translated by Google
Lecture 4
recursion
The function call is executed inside the evaluated expression, the result
of the function (return value) is used when evaluating this expression.
recursion 61
programex1;
procedure pmin(var X: array of integer;
n: integer varr: integer);
var i: integer; {i - local variable}
beginr:=X[0];
for i:=1 to n-1 do
if r>X[i] then r:=X[i];
end; {end of procedure description}
var A: array of integer;
n,i,min: integer;
begin readln(n); SetLength(A,n);
for i:=0 to n-1 do read(A[i]);
pmin(A,n,min); {procedure call}
writeln('min=',min);
SetLength(A,0);
end.
62 Lecture 4
the inscription (min=) and the value of the min variable are displayed. In addition,
the memory allocated to array A is freed.
End of example.
Example 4.2. Program with a function that calculates the minimum value
array.
programex8;
function pmin(varX: array of integer;
n: integer): integer;
var i,r: integer; {i,r – local variables}
beginr:=X[0];
for i:=1 to n-1 do
if r>X[i] then r:=X[i];
pmin:=r;
end; {end of function description}
var A: array of integer;
n,i,min: integer;
begin readln(n); SetLength(A,n);
for i:=0 to n-1 do read(A[i]);
min:=pmin(A,n); {function call}
writeln('min=',min);
end.
recursion 63
ÿ 0! one,
ÿ
ÿ
ÿ
!
nnn ÿ ÿ ÿ ( one)!
n ÿ
12, ...
Proof.
Basis of induction. For n = 0, the fact function will calculate the result 0.
Assumption. Let the fact function calculate the correct result n! for n
= k, k ÿ 0. Induction. We make sure that for n = k + 1 the fact function will
calculate re
result equal to (n – 1)! n = n!.
Let's trace the calculation process when calling:
d:=fact(3);
To compute fact(3), the algorithm first computes fact(2), which computes fact(1),
then computes fact (0). This can be represented as a “deeper” calculation, as in the
left table in Fig. 4.1. Finally, when fact(0) is computed , the result of the algorithm is
1, then when fact(1) is computed, fact(2) is computed, and finally fact(3) is
computed. This process - returning from recursion - is presented in the right table in
Fig. 4.1.
64 Lecture 4
fact(n); fact(n);
3 3 6
2 2 2
one one one
0 0 one
Rice. 4.1
End of example.
Example 4.4. Task "Towers of Hanoi". There are three pegs, marked with letters:
a,b,c. On a peg a there are n discs strung in the form of a tower, like in a children's
pyramid.
Task: Move the entire tower to peg c, shifting one disk at a time so that any larger disk
does not lie on the smaller disk for any of the pegs.
Proof.
Basis. Number of disks n=1. Move the disc from peg a to
peg c.
Machine Translated by Google
recursion 65
Assumption. Let the algorithm be able to move towers from n=kÿ1 disks.
one
four
Rice. 4.2
Machine Translated by Google
66 Lecture 4
The algorithm for solving the game can be written down by repeating the proof
process. In the procedure, the process of shifting one disc is written as outputting the
number of the peg where the disc lay and the number of the peg on which the disc
was placed.
If, when carrying out the proof, we take into account that the lower disk can be
moved if and only if all the upper disks are transferred in the form of a tower to an
intermediate peg, then it follows that the algorithm implements the minimum possible
number of rearrangements!
procedure hanoi(n,a,b,c:integer);
begin
if n=1 then writeln(a,'>',c)
else begin
hanoi(n-1,a,c,b);
writeln(a,'>',c);
hanoi(n-1,b,a,c);
end;
end;
H n( ) ÿ
-
2H
( ÿn ÿ ÿ eleven, n ÿ
2, 3, ...,
From it we get:
n-1 n-2 n
H(n) = 2H(n – 1) + 1 = 2 2H(n – 2) + 2 + 1 = 2 +2 + …+2+1=2 - one.
Thus, the complexity of the algorithm is O(2n ), and this is the minimum
possible complexity of solving the problem. Recursion depth: n.
If it takes 1 second to shift one disk, then with n = 64 all the work can be
completed in 264 s ÿ 580 billion years.
End of example.
recursion 67
end;
end;
Machine Translated by Google
68 Lecture 4
i:=seek(X,d,0,n-1);
one n 2 ÿ
one,
recursion 69
fib(n:integer):integer;
begin
if n=0 then begin F[0]:=0; fib:=0 end
else if n=1 then
begin F[1]:=1; fib:=1 end
else if F[n]>0 then fib:=F[n] end
else begin
F[n]:=fib(n-1)+fib(n-2); fib:=F[n];
end;
end;
This version of the algorithm has a complexity and a recursion depth of O(n),
since each of the Fibonacci numbers is calculated only once, but its complexity is
several times greater than when calculating the numbers
Fibonacci in a cycle.
End of example.
70 Lecture 4
array C. The first loop is executed until one of the input arrays has no unscanned
elements. If, after the end of the first cycle, some of the elements of array A remain
unscanned, then in the second cycle the remaining elements will be copied to array
C, and if the elements of array B remain unscanned , then the elements remaining
there are copied to C by the third cycle.
recursion 71
else begin
Y[j]:=X[i2]; i2:=i2+1 end;
j:=j+1
end;
while i1<=e1 do begin
Y[j]:=X[i1]; i1:=i1+1; j:=j+1
end;
while i2<=e2 do begin
Y[j]:=X[i2]; i2:=i2+1; j:=j+1
end;
end;
End of example.
Example 4.10. Merge sort algorithm:
procedure sort(var X,Y: array of integer;
b,e:integer);
var c,i:integer;
begin
if b<e then begin
c:=(b+e)div 2;
sort(X,Y,b,c);
sort(X,Y,c+1,e);
S(X,Y,b,c,e);
for i:=b to e do X[i]:=Y[i]
end
end;
Machine Translated by Google
72 Lecture 4
The sort procedure uses procedure S from Example 4-9. The procedure sorts the
segment of the array X with element numbers from b to e. Array Y is auxiliary . Calling
the sort procedure for arrays A and B
of n elements:
sort(A, B, 0, n-1);
Proof.
Basis. The size n of the ordered segment in the array X is equal to 1. Al
the burn does nothing.
Assumption. Let the algorithm be able to arrange segments in mass
array X of size from 1 to n = k ÿ 1 elements.
Induction. Let a segment in array X have size n = k + 1 ÿ 2 elements. Then the
algorithm does the following:
1) divides the segment into two equal (or almost equal) parts;
2) each of the parts (no more than k elements in size) is recursively mentioned
line up;
3) merges two ordered parts into one segment of the Y array;
4) copies the segment of the Y array to the X array in place of the original segment
ka, obtaining an ordered segment of length n = k + 1 in the array X. If the
size n of the ordered array
m-1 m
2 <nÿ2 ,
then after no more than m consecutive divisions, the size of the array fragment
will become equal to 1. That is, the recursion depth will also not exceed m, i.e.
ÿlog2 nÿ , which is much less than the size of the array X.
Recurrent relation for labor input T(n):
ÿ T (eleven,
ÿ
ÿ
ÿ
T (n/ T2)n ( ) 2
ÿ
ÿ cn n , ÿ
2, 3, ...,
where c is a constant.
Assuming 2m – 1 < n ÿ 2m, we get:
2
T (n) = 2 T (n/2) + cn = 2 T (n/4) + cn + cn = … ÿ cnm = cn ÿlog2 nÿ
recursion 73
ÿ R ÿ
one,
one
ÿ 2
RR ÿ
2 n ÿ
2, 2 , ...
ÿ n nÿ/2 one,
Thus, the number of all recursive calls is much less than the number of other actions
during the execution of the algorithm (comparisons and copies).
Table 4.1 shows the values of such functions as ÿlog2 nÿ , n ÿlog2 nÿ, n
3/2 2 3
,n , n , 2n , which characterize the complexity of a number of types
output algorithms.
Table 4.1
3/2 2 3 n
n ÿlog2 nÿ n ÿlog 2 nÿ n n n 2
The superiority of the more efficient algorithm is especially evident for large values of n.
Thus, to sort an array of a million elements, the simplest sort will perform (in the worst case)
about 166ÿ1015
3 2
cycles (n /6), bubble sort – about 5ÿ1011 cycles (n /2), and litter
merging is about 40ÿ106 cycles ( 2n ÿlog2 nÿ ). If the computer performs 109 cycles per
second, which corresponds to a speed of about 5 billion operations per second, then the
operating time of these programs will be respectively: 5 years, 8 minutes and 0.04 seconds.
Machine Translated by Google
74 Lecture 4
n
If the algorithm has exponential complexity, for example, O(2
), then its running time grows catastrophically fast with an increase in n , and
no increase in computer speed will help. So, for n = 100, 2100 ÿ1030
, when performing 109 actions in 1 second, more than 40
trillion years will be required, and with 1015 actions in 1 second, more
more than 40 million years.
1. Write a program that describes a function with parameters n and A that calculates in a loop
the sum of n elements of array A. The program enters the number n, allocates memory for
n elements of array A , and enters n elements into array A. After that, by calling the function,
calculates and displays the sum of the elements of array A. Create tests for the program
using the black and white box method and conduct testing.
2. Write a program that describes a recursive function with parameters n and A, which calculates
the sum of n elements of the array A. Prove the correctness of the function by mathematical
induction. The program enters the number n, allocates memory for n
elements of array A and enters n elements into array A. After that, by calling the function,
calculates and displays the sum of the elements of array A. Create tests for the program
using the black and white box method and conduct testing.
3. How should the recursive algorithm be written in order to guarantee it for
veracity?
4. Write in recursive form the algorithm for calculating the greatest common divisor
two non-negative numbers and prove its correctness.
5. Write and debug a program that enters the number of discs to be moved in the Towers of
Hanoi problem and calls a recursive procedure that prints messages about each disc shift.
At the end, it prints the number of shifts counted in the function, as well as the number of
shifts calculated by the formula. Create tests for the program using the black box method
and conduct those
erasing.
6. Prove by the invariant method the correctness of the recursive function of the dichotomous
th search for an element in an ordered array. Prove that if the array has several elements
equal to p, then the program will calculate the smallest number among
them.
7. On the basis of the recurrent relation on the number of calls Rn of the recursive function for
calculating Fibonacci numbers, prove the relation by mathematical induction: Rn = 2Fn+1
– 1, where Fn is the Fibonacci number.
Machine Translated by Google
recursion 75
8. Prove by mathematical induction the correctness of the recursive function for calculating
Fibonacci numbers using the "dynamic programming" method. Prove that the number of calls
to this recursive function when calculating the nth Fibonacci number is at most n.
9. Prove by the invariant method the correctness of the procedure for merging two adjacent
ordered parts of the array X into one ordered part of the array Y.
10. Change the recursive merge sort procedure so that instead of calling the merge procedure
inside it, actions that implement such a merge are inserted
nie.
11. Write and debug a program that enters the number n, allocates memory for n
elements of array A and inserts n elements into arrays A and C. After that, it sorts array A by
calling the merge sort procedure, and also sorts array C by calling the insertion sort procedure,
after which it compares arrays A and C with each other. Create tests for the program using
the black method box and test.
12. Write and debug a program that inputs the value n, generates n random integers from the
range from -1000 to 1000, stores them in an array (dynamic memory is allocated for the
array), and sorts them one by one using several sorting algorithms (simple sorting, exchange
sorting). sort, bubble sort, merge sort). After executing the next sorting algorithm, check
whether this algorithm worked correctly. In addition, inside each algorithm, provide counters
that count the number of executions of the innermost loop. After completing all calculations
for various n (10, 100, 1000, 10000), print the values of these counters and draw conclusions
about which
Lecture 5
List Structures
typepel=^elem;
elem=record s:integer; p:pel end;
In this description, two types are described.
The pel type is described as a pointer to the elem type, i.e. list element.
The elem type is the element type of the list. It is defined as a structure of
two fields: the s field is the content, here the content type is integer; the field p
is a pointer that points to another element of the list, the type of the field p is
pel.
A type declaration does not create any variables or other objects in the
program, but only defines the types of variables that can be further described, for
example:
var p1,p2,p3: pel;
Only pointers are described here, there are no list elements themselves yet.
List elements are created when memory is allocated using the new operator, for
example:
new(p1); new(p2);
Machine Translated by Google
List Structures 77
There are two list elements created here: the list element pointed to by
takes the pointer p1, and the element of the list pointed to by the pointer p2.
Examples of creating two lists from the created elements are presented
us in fig. 5.1 in graphic form.
5 ten 5 ten
p1 p2 p1 p2
Rice. 5.1
p1^.s:=5; p1^.p:=p2;
The first element of the list contains 5, the pointer points to the 2nd element.
Here p1^.s is the field s of the list element pointed to by
pointer p1, and p1^.p is the p field of the list element pointed to by
pointer p1.
p2^.s:=10; p2^.p:=nil;
In the second element of the list, the content is 10, the pointer is equal to
nil (a special empty value, in the figure a crossed out rectangle, means the end
of the list). The result is a simple linear list. Pointer p1 points to the beginning of
the list, pointer p2 points to the end of the list. If a
replace the last assignment with:
p2^.p:=p1;
then in the second element of the list, the pointer will point to the initial element
of the list. The result is a cyclic list in which from the last element you can go to
the first element by reference.
The list can contain an arbitrary number of elements, even none, in which
case the pointer to the list is nil.
If any element of the list is no longer needed, it can be removed using the
standard dispose procedure, the argument of which is a pointer variable that
refers to the list element to be removed, for example:
dispose(p1);
78 Lecture 5
Example 5.1. A program for entering a set of integers from the keyboard
and forming a sequential list from them. The end of the input is determined
by the entered number 0. The pointer p1 points to the first, and the pointer
p2 points to the last element of the list.
typepel=^elem;
elem=record s:integer; p:pel end;
var p1,p2,p3:pel;
s: integer;
p1:=nil;
p2:=nil;
read(s);
while s<>0 do
begin new(p3); if
p1=nil then p1:=p3 {for the 1st
element of the list}
else p2^.p:=p3;{ for the 2nd, etc. list items}
p2:=p3; p2^.s:=s;
read(s)
end;
p2^.p:=nil;
...
end.
In the loop, the next new element of the list is appended to the end
list.
End of example.
The following example shows how to view all elements
sequential list.
Example 5.2. The program for calculating the sum of the contents of the
elements of the linear list created in example 5.1.
p3:=p1; sum:=0;
while p3<>nil do begin
sum:=sum+p3^.s;
p3:=p3^.p
end;
Machine Translated by Google
List Structures 79
The pointer p3 loops through all the elements of the list. Operator
p3:=p3^.p advances p3 to the next element in the list.
End of example.
end;
p2:=nil;
End of example.
In examples 5.1 - 5.3 the list can be empty, then both pointers
p1 and p2 will be nil.
In a number of tasks, such special data structures as queues and stacks (stores)
are used. Each of these structures contains a set of homogeneous elements that can
be added to and removed from the set. A queue is a set of data that works according
to the principle: first in, first out. The stack works on the principle: last in, first out. If
the problem knows in advance the maximum
a certain number of elements of the queue or stack, then they can be implemented in
in the form of arrays, and if unknown, then in the form of lists.
Example 5.4. Programs that perform actions on the stack and queue. A list that
implements a stack or queue also has two pointers: p1, which points to the beginning
of the list, and p2 , which points to the end of the list.
Adding an element with value X to the queue (at the end of the list):
80 Lecture 5
Adding an element with value X to the stack (at the beginning of the list):
Example 5.5. The program for finding the element of the list with the value S0 in
linear list. The pointer p1 is the beginning of the list:
p3:=p1;
while (p3<>nil)and(p3^.s<>S0) do
p3:=p3^.p;
"among the elements of the list with numbers 1, ..., i - 1, the content of none
of them is equal to S0."
Labor input O(n). If the search fails, the loop will run
exactly n times, and if successful, may end sooner.
End of example.
Example 5.6. The program for finding the list element with the value S0 in an
ascending sorted list:
Machine Translated by Google
List Structures 81
p3:=p1;
while (p3<>nil)and(p3^.s<S0) do
p3:=p3^.p;
if (p3<>nil)and(p3^.s>S0) then
p3:=nil;
Labor input O(n). In contrast to Example 5.5, the loop can end earlier on both a
successful and an unsuccessful search.
End of example.
new(p3); p3^.s:=S0;
p4:=nil; p5:=p1;
while (p5<>nil)and(p5^.s<S0) do
p4:=p5; p5:=p5^.p end;
if p4=nil then p1:=p3{insert at the beginning of the list}
else p4^.p:=p3;{insert into list between p4 and p5}
p3^.p:=p5; if
p5=nil then p2:=p3;{insert at end of list}
82 Lecture 5
p4:=nil; p5:=p1;
while (p5<>nil)and(p5^.s<S0) do
p4:=p5; p5:=p5^.p end;
if (p5<>nil)and(p5^.s=S0) then begin
{p5 points to the element to be removed}
if p4<>nil then p4^.p:=p5^.p
else p1:= p5^.p; {element to be removed 1st}
if p5^.p=nil then p2:=p4;
{element to be removed last}
dispose(p5);
end;
First, the loop searches for the element to be removed. Loop postcondition
options:
1) p5=nil – the list does not contain the element to be removed;
2) p5ÿnil, p5^.sÿS0, p4=nil – the loop has never been executed, the removed
element is the 1st one;
3) p5ÿnil, p5^.sÿS0, p4ÿnil – the element to be removed is between
the elements of the list with pointers p4 and p5.
End of example.
The above programs perform the search using a loop. With friend
On the other hand, recursive search algorithms are usually simpler.
function flist(p:pel,S0:integer):pel;
begin
if p=nil then flist:=nil
else if p^.s=S0 then flist:=p
flist:=flist(p^.p,S0)
end;
Exit from recursion: either the returned pointer points to an element with content
equal to S0, or it is equal to nil, then the desired value is not in the list. Call example:
p3:=flist(p1,d);
End of example.
Machine Translated by Google
List Structures 83
Example 5.11. Recursively searching for the value S0 in an ordered linear list:
function flist2(p:pel,S0:integer):pel;
if p=nil then flist2:=nil
else if p^.s=S0 then flist2:=p
else if p^.s>S0 then flist2:=nil
else flist2:=flist(p^.p,S0)
end;
The difference from the previous version is that here an additional case
of exiting the recursion with a search result of nil is possible, when the
content of the next element of the list is greater than S0.
End of example.
p3:=nil;
while p3<>p1 do begin
p4:=p1; p5:=p1^.p;
while p5<>p3 do begin if
p4^.s>p5^.s then begin
z:=p4^.s; p4^.s:=p5^.s; p5^.s:=z
end;
p4:=p5; p5:=p5^.p
end;
p3:=p4
end;
Pointer p3 is moved backwards when executing the outer loop.
on the other side, from the end of the list to the beginning, similar to how the
outer loop parameter changes in sorting for an array. Pointers p4 and p5
move through the list from beginning to end, with their help two adjacent elements of
the list are compared and, if necessary, they are exchanged
content.
Machine Translated by Google
84 Lecture 5
Conventionally, we can assume that the elements of the list are renumbered,
their number is equal to n, and that in the outer loop the elements are numbered
by the "variable" i, and in the inner loop - by the "variable" j .
Inner loop invariant:
1) pointer p4 points to the j-th element of the list;
2) pointer p5 points to the (j + 1)th element of the list;
3) the j-th element of the list has the maximum content (field s)
among the elements of the list from the 1st to the j-th;
4) the set of values (fields s) of all elements of the list remains unchanged
nym.
End of example.
Example 5.13. Merging two ordered lists. Pointers p1 and p2 point to the
beginning of the two input lists, and the output ordered list is built from the
elements of these lists, to which the pointer p3 points.
List Structures 85
First, before the loop, the smallest element is moved into the output list and
pointed to by p3. Pointers p1 and p2 are moved through the input lists during the
loop, and after moving all elements to the output list, they are assigned nil. The local
pointer p4 points to the last element of the output list being created.
The complexity of the algorithm is O(n), the same as merge for arrays.
End of example.
Example 5.14. List merge sort. The pointer p points to the beginning of the list,
the variable n must contain the number of elements
list.
86 Lecture 5
The algorithm is similar to merge sort for an array. The difference is that
first, after calculating the length of the first of the merged lists, the original list is
"cut" in two. In addition, after separately recursively sorting each of the two parts
of the list and merging them into a common ordered list by the slist procedure,
there is no need for any copying here.
The complexity of the algorithm is the same as in merge sort for an array,
i.e. O(n log n).
Compute the length of the list pointed to by p1, and you
call of the sort procedure:
p3:=p1; n:=0;
while p3<>nil do begin
n:=n+1; p3:=p3^.p end;
sortlist(p1,n);
End of example.
1. Write and debug a program that enters the number n and enters n numbers, placing them
sequentially in the created list elements, as in a queue. After that by
therefore extracts and removes elements from the beginning of the list, summing their
values, and calculating the minimum and maximum values. At the end displays the sum,
minimum and maximum value. Create tests for the program using the black and white box
method and conduct testing.
2. Write and debug a program that enters the number n and enters n numbers, placing them in
the generated list elements so that the list is ordered. Finally, prints the values in sequence
from the list. Create tests for the program using the black and white box method and conduct
testing.
3. Carry out a complete proof by the program invariant method (containing
loop) searching for an element in an unordered list.
4. Carry out a complete proof by the program invariant method (containing
loop) to find an element in an ordered list.
5. Carry out a complete proof by the method of mathematical induction recursive
programs to find an element in an unordered list.
6. Carry out a complete proof by the method of mathematical induction recursive
programs to find an element in an ordered list.
Machine Translated by Google
List Structures 87
7. Write a program that removes items with duplicate values from an ordered list. Carry out
its full proof by the invariant method.
8. Carry out a complete proof by the invariant method of the bubble sort program for lists.
9. Carry out a complete proof by the invariant method of the bubble sort program for lists.
10. Carry out a complete proof by the method of the invariant of the merge program in order
lists.
11. Carry out a complete proof by the invariant method of the merge sort program
sorted lists.
12. Write and debug a program that enters the number n and enters n numbers, placing
them sequentially in the created list elements, as in a queue. It then bubble sorts the
list and outputs the values from the list sequentially. Create tests for the program
using the black and white box method and conduct testing.
13. Write and debug a program that enters the number n and enters n numbers, placing
them sequentially in the created list elements, as in a queue. It then orders the list by
calling the merge sort routine and prints the values in sequence from the list. Create
tests for the program using the black and white box method and conduct testing.
Machine Translated by Google
Lecture 6
Backtracking
There are a number of problems that are very difficult to solve without recursion.
These include, in particular, combinatorial problems in which a solution is sought
that consists of a combination of values of some variables. As an example, consider
the problem of finding all permutations of natural numbers from 1 to n. We will solve
the problem as follows:
1) as the first number, choose any of the numbers 1, ..., n;
2) as the second number, choose any of the numbers 1, ..., n, except for the
number that was chosen first;
3) as the third number, select one of the numbers that is not selected per
you or the second, etc.
We continue this process until we choose the last, nth number for permutation.
Thus, n options are selected for the first number, 1 option for the second, and so on,
and 1 option for the last, nth number. In total, it turns out n (n - 1) ... 2ÿ1 = n!
permutation options. In order to obtain choosing
all possiblethepermutations,
kth number, itatiseach
necessary
stage of
to
sequentially go through all admissible numbers; however, it is possible to move
to the next variant only if complete permutations for all previous variants are found.
Such a process can
represent the decision tree shown in Fig. 6.1 for n = 3. The circles in the diagram
indicate the numbers chosen at the next step, the arrows indicate the transition to
the choice of the next number.
According to the scheme, the permutation 1–2–3 will be chosen first, then 1–
3–2, 2–1–3 , and so on. When you select the next number, the movement according
to the scheme goes along the down arrow, and if you refuse this choice (to select
another number), the reverse movement (backtracking) occurs. This process can be
easily implemented by a recursive algorithm.
Machine Translated by Google
Backtracking 89
one 2 3
2 3 one 3 one 2
3 2 3 one 2 one
Rice. 6.1
procedure per(k:integer);
var i:integer;
begin
for i:=1 to n do
if R[i]=0 then begin
P[k]:=i; R[i]:=1;
if k=n then OUTPUT
elseper(k+1);
R[i]:=0
end
end;
90 Lecture 6
The recursion depth is n, because for each nested recursive call, the parameter
k is incremented by 1, and the recursion returns when k=n. In this case, the value of
n in practice cannot be large due to the huge number of permutations (for example,
10! = 3628800).
End of example.
R[i3]:=0
end;
R[i2]:=0
end;
R[i1]:=0
end;
Machine Translated by Google
Backtracking 91
In this way it is possible to obtain a program for any fixed n, but in this case the flexibility
of the algorithm is lost, and its size also increases.
End of example.
Example 6.3. Recursive procedure for generating arrays of length m
of n numbers with repetitions. As in Example 6.2, the spreads are generated in a global
array P of n elements. There is no need for an R array here, since there is no need to check
which numbers are already in the arrangement:
procedure gen(k:integer);
var i,j:integer;
begin
for i:=1 to n do
beginP[k]:=i; if k=m
then OUTPUT
elsegen(k+1);
end
end;
The complexity of the algorithm can be estimated by the total number of loop executions
in all recursive calls:
– at the first call: n times,
2
– with recursion depth 2: n times n, i.e. n once,
3
– with recursion depth 3: n times in n2, i.e. n once,
- etc.
Total (sum of geometric progression):
2 m m
T(n) = n + n + ...+n = (n – 1) n / (n – 1).
End of example.
92 Lecture 6
was checked by the if statement, then the complexity would be the same as when
generating constellations using the gen procedure under the condition n = m:
n
T1(n) = (n – 1) n / (n – 1).
On the other hand, if there were no "extra" loop executions in the per procedure, i.e.
the loop would be executed not n times, but only n - k + 1 times, then the total number of
loop executions would be equal to:
nn! ! ÿ one one ÿ
T2nnnn
( ) ( ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ one)
ÿ ÿ ÿ ...
ÿ 1! nn! ! eleven ÿ ... ÿ
ÿ ÿ en !,
2! 2! (n
ÿ ÿ
ÿ
ÿ
one)! ÿ
since the limit of the expression in brackets as n ÿ ÿ is equal to e (the base of natural
logarithms).
The values T1(n) and T2(n) determine the upper and lower limits of the number of
loop executions, respectively. The exact value of this value can be calculated if we take
into account that all loops are executed n times, but the recursive call of them is only n - k
+ 1 times:
n! n!
ÿ 3ÿ( ÿ) (ÿ Tÿ nn
ÿ ÿnn
ÿ nn n one) ... n n
2! one!
one) (*)
2! (n n !ÿ
ÿÿ ÿÿ
one)!
new(p); p1:=p;
for i:=2 to n do
begin
new(p2); p1^.p:=p2; p1:=p2end;
p1^.p;=nil;
Machine Translated by Google
Backtracking 93
Just like in the per procedure, the perlist procedure uses the global
array R, which contains the signs that numbers are included in the
permutation:
procedure perlist(p:pel);
var i:integer;
begin
for i:=1 to n do
if R[i]=0 then begin
p^.s:=i; R[i]:=1;
if p^.p=nil then OUTPUT
else perlist(p^.p);
R[i]:=0
end
end;
The perlist generation procedure is called in the same way as the procedure
per:
specifies an array of six strings, with each string having a maximum length of 10
characters. If the rows of the array are given specific
values, then in the description of the per procedure, the output of the permutation of strings can be
write like this:
for j:=1 to 6 do
write(St[P[j]],' ');
writeln;
Machine Translated by Google
94 Lecture 6
m n!
Ann
n
ÿÿ
( one)...( ÿ ÿ ÿ nm one)
.
( nm )!
ÿ
n!
Cnm ÿ
( mm )! !
ÿÿ
In each such group, the order of the numbers is not important, but it is most
convenient to generate numbers in ascending order by placing them in an array C of m
elements. Then the number C1 will be in the first place in the range from 1 to n – m
+ 1, in the second place – the number C2 in the range from C1 + 1 to n – m + 2, …,
in the mth place – the number Cm in range from Cm – 1 + 1 to n.
In this case, there is no need to use the array R, but in order for the procedure
to be performed in the same way both when generating the first number and the rest
of the numbers, the global array C must contain an additional element C[0] with a
preassigned value of 0 to it.
Recursive procedure for generating combinations:
procedure combine(k:integer);
var i:integer;
begin
for i:=C[k-1]+1 to n-m+k do
begin C[k]:=i; if k=m
then OUTPUT
else combine(k+1);
end
end;
Machine Translated by Google
Backtracking 95
Before the call, you must set the zero value for C[0]:
C[0]:=0; combine(1);
96 Lecture 6
else
for i:=1 to n do
if R[i]=0 then begin
P[k]:=i; R[i]:=1;
if k=n then OUTPUT
else pers(k+1,s+i);
R[i]:=0
end
end;
Procedure parameters:
k is the number of the element of the array P, in which the queue will be stored
new generated numbers;
s is the sum of numbers in the previously calculated part of the generated
permutation, s=P[1]+...+P[k-1].
Calling the generation procedure:
for i:=1 to n do R[i]:=0;
pers(1,0);
End of example.
Example 6.8. Queen problem. Let the cells on the chessboard be numbered
by two numbers - the number of the row and the number of the column. The
figure queen, standing on the cell (i, j), keeps the cells of the chessboard under attack
in row i, column j, as well as cells of two diagonals passing through cell (i, j). We will
consider a "chess" board of size n x n. It is required to place n queens on the board
in such a way that they do not "hit" each other. The arrangement is written as n
numbers, the number i in the jth place determines the queen on the cell (i, j). For
example, for a 4x4 board, the arrangement (2, 4, 1, 3) shown in Fig. 6.1.
Machine Translated by Google
Backtracking 97
F
F
F
F
Rice. 6.1
0123 2345
-1 0 1 2 -2 3456
-1 0 1 4567
-3 -2 -1 0 5678
Rice. 6.2
The recursive procedure Queen calculates the arrangement of queens on the board
n x n:
procedure Queen(j:integer);
var i:integer;
begin
for i:=1 to n do
if (S[i]=0)and(R[ji]=0)and(L[j+i]=0) then begin
Unlike the per procedure, in the Queen procedure, when generating the next
number i in the string j , it checks that the cell (i, j) is not on
Machine Translated by Google
98 Lecture 6
on the occupied column (S[i]=0), on the occupied left diagonal (R[ji]=0) and
on the occupied right diagonal (L[j+i]=0).
The main program containing the declarations of global variables enters the
size of the board n (no more than 20), sets the arrays S, R, L to zero, and calls
the Queen procedure:
var S,Q:array[1..20]of integer;
R:array[-19..19]of integer;
L:array[2..40]of integer;
n,i:integer;
begin
readln(n); for
i:=1 to n do S[i]:=0;
for i:=1-n to n-1 do R[i]:=0;
for i:=2 to 2*n do L[i]:=0;
queen(1);
end.
End of example.
9 1 8 16 5 23 22 7 8
276 4 12 5 13 20 19 11 12 3
951 14 6 11 3 21 4 9 16 15
438 7 15 10 2 18 17 10 6 14
Rice. 6.3
We will look for all possible magic squares for a given n. We stretch the square
table into one line with the numbering of its elements from 1 to n
2
. Then the solution will be such a permutation of numbers 1, n 2 , koto
2, ..., paradise satisfies the conditions of the magic square. Therefore, the basis of al-
Machine Translated by Google
Backtracking 99
algorithm, we can take the procedure per, supplementing it with checking the
corresponding conditions.
The value of the sum for checking the conditions will be determined from the following
images. The sum S of all square numbers is:
2 2 2
S = 1 + 2 + +…1)+/ n2. = n (n
This sum is divided into n equal parts (according to the number of rows in the
square). So the required amount is:
2
S0 = nÿ(n + 1)/2.
Unlike permutations in the per procedure, magic squares will be only a small part
of all permutations. So, for n = 3, there are only 8 permutations out of 9! = 362880,
and for n = 4 only 7040 out of 16! = 20922789888000. Let, for example, a computer
be able to generate and check 107 squares in 1 second. Then it will take him more
than 20 days to generate all the magic squares for n = 4!
procedure sq(k:integer);
var i:integer;
begin
if k mod n=0 then begin {last column}
i:=s0-sumH(k);
if (i>=1)and(i<=n2)and(R[i]=0) then begin
R[i]:=1; T[k]:=i;
if k=n2 then OUTPUT
else sq(k+1);
R[i]:=0
end
end
else if k>n2-n then begin {last line}
i:=s0-sumV(k);
Machine Translated by Google
100 Lecture 6
The variable s0 contains the value of S0 (the sum of one row or column in the
magic square), n2=n*n. The auxiliary function sumH(k) calculates the sum of the
elements in the current row of the square located before the kth element in the array
T , and the function sumV (k) calculates the sum of the elements in the current
column of the square located above the kth element. The OUTPUT function checks
the last column and two diagonals of the square, and if the checks are positive,
outputs the generated magic square.
To speed things up even more, the sq procedure can additionally provide for
clipping at earlier stages of generating the square: when the number k corresponds
to the penultimate column and when the number k corresponds to the penultimate
row of the square. If all these
Machine Translated by Google
Backtracking 101
102 Lecture 6
6. Write and debug a program that inputs the numbers n and m, then inputs into an array
n character strings with words written in them. After that, the procedure for generating
placements from n to m generates and outputs the placements of these words. Create
tests for the program using the black and white box method and conduct testing.
7. Write and debug a program that inputs the numbers n and m, then inputs into an array
n character strings with words written in them. After that, the procedure for generating
combinations from n to m generates and outputs combinations of these words. Create tests
for the program using the black and white box method and conduct testing.
8. Carry out a complete proof by the method of mathematical induction for the program for
generating combinations from n to m. 9. Write down a non-recursive algorithm for generating
combinations of n by m for m = 3. Carry out its complete proof by mathematical induction.
10. Write an algorithm for generating placements from n to m with the constraint that the sum of
the numbers in the placement must be equal to S. Provide for the return from the recursion
as early as possible. Carry out its full proof by the method of mathematical
induction.
11. Write down an algorithm for generating combinations of n by m with the constraint that the
sum of the numbers in the combination must be equal to S. Provide for a return from the
recursion as early as possible. Carry out its full proof by the method of mathematical induction.
12. Write and debug a program that enters the number n, after which, using the procedure for
generating permutations of queens on an n x n chessboard , it generates and displays all
permutations as an image of a board with queens on it. Test for n from 4 to 8.
Lecture 7
Sets
Let N some objects (a set of objects) be given. If the objects are renumbered by numbers
from 1 to N, then each object will be determined by its number. In this case, different numbers
will be assigned to any two different objects . The whole set of considered objects
is called the original set or universe. Some of the objects of the universe can be selected, then
a subset of selected objects is formed, which is called simply a set. In set theory, both finite
and infinite sets are studied, but any finite algorithm can only deal with finite sets.
properties.
Sets can be defined in several ways. The easiest way is in the form of a binary array, the
size of which is equal to the number
objects in the universe, and each array element can take two values. Let N be the number of
objects in the universe, the array M contains
N elements, which can be specified as integer or byte (then their value is 0 or 1), or boolean
(then their value is false or true). A specific set is defined by a set of values of the elements of
the array M. If M[i]=1 (or true), then the i-th object of the universe is present in the set, and if
M[i]=0 (or false), then it is not. In total , there are 2N such different sets of N zeros and ones,
i.e., 2
N
various
subsets of this universe.
M[i]:=1.
Machine Translated by Google
104 Lecture 7
M[i]:=0.
The loop is executed N times, i.e. the complexity is of the order O(N).
End of example.
Example 7.2. Operations on two sets given by binary arrays A and B. The sets
must be defined on the same universe of N objects, so the size of arrays A and B
must be N. The result is in array C of length N.
Difference (A \ B) - set C includes those objects that are in set A, but are not in
set B:
for i:=1 to N do
if (A[i]=1)and(B[i]=0) then C[i]:=1
else C[i]:=0;
Sets 105
for i:=1 to N do
if (A[i]=1)xor(B[i]=1) then C[i]:=1 else C[i]:=0;
M[i]:= true;
Union (A U B):
for i:=1 to N do C[i]:= A[i] or B[i];
Intersection (A ÿ B) :
for i:=1 to N do C[i]:= A[i] and B[i];
Difference (A\B):
for i:=1 to N do C[i]:= A[i] and not B[i];
106 Lecture 7
End of example.
If the size of the universe is too large, then it is advisable to specify the sets as an
integer array. Let, for example, the universe be the set of all integers of a certain length
(for example, 32 bits), then its size is 232 = 4294967296. In a computer, for an array of
such a length, there may simply not be enough RAM, and if enough, then the execution
time of operations may be too large.
If the power of the set is always limited by a certain number L, then the size of the
array to represent the set must be equal to L. Then, in addition to the array M of L
elements, a variable K is needed that specifies the current power of the set, and always
K ÿ L.
The values M[1],...,M[K] define the numbers of objects belonging to the set. Note that
an array must not contain elements with the same value! In this case, the numbers of
objects in the array can be located
go both in an arbitrary order and in an orderly manner, for example, according to
ascending.
j:=1;
while (j<=K)and(M[j]<>i) do j:=j+1;
if j<=K then FOUND else NO;
j:=1;
while (j<=K)and(M[j]<>i) do j:=j+1;
if j>K then begin K:=K+1; M[K]:=i end;
Machine Translated by Google
Sets 107
j:=1;
while (j<=K)and(M[j]<>i) do j:=j+1;
if j<=K then begin M[j]:=M[K]; K:=K-1 end;
All actions with searching, adding, and deleting an object have O(K) complexity.
End of example.
Example 7.5. Operations on two sets given by unordered arrays A and B.
Number of objects in sets K1 and K2
respectively. The result of calculations is written to array C, the number of filled
elements in it is K3, and is calculated in the course of calculations.
Union (A U B):
for i:=1 to K1 do C[i]:=A[i];
K3:=K1;
for i:=1 to K2 do
beginj:=1;
while (j<=K1)and(A[j]<>B[i]) do
j:=j+1; if
j=K1+1 then begin
K3:=K3+1; C[K3]:=B[i]
end
end;
First, all objects from array A are copied to array C. Then , those objects that do
not exist are copied from array B to array C.
Machine Translated by Google
108 Lecture 7
in array A. In the while loop , an element of array B[i] is searched for a match with
any element from array A.
The complexity of the 1st cycle is O(K1), the 2nd (double nested) cycle
O(K1*K2), i.e. total labor input – O(K1*K2).
Intersection (A ÿ B):
K3:=0;
for i:=1 to K2 do
beginj:=1;
while (j<=K1)and(A[j]<>B[i]) do
j:=j+1; if
j<=K1 then begin
K3:=K3+1; C[K3]:=B[i]
end;
end;
Here , only those objects that are in array A are copied from array B to array C.
Labor input is O(K1*K2).
Difference (A\B):
K3:=0;
for i:=1 to K1 do
beginj:=1;
while (j<=K2)and(A[i]<>B[j]) do
j:=j+1; if
j=K2+1 then begin
K3:=K3+1; C[K3]:=A[i]
end;
end;
Here, from array A to array C , those objects that are not in array B are copied.
Labor input is O(K1*K2).
Sets 109
end;
if M[b]=i then FOUND else NO;
First, a dichotomous search is performed in the array M for an element with value
i. Adding is done only if there is no such element. When the while loop ends, b=e,
and the new element with value i must be placed at M[b] (or M[b+1] if the maximum
element in the array is less than i). Before placing this element in the array, all
elements located in places from b to K are sequentially shifted to the right by one
position.
Machine Translated by Google
110 Lecture 7
The complexity is O(K) if there was no added object, or O(log K) if this object was already in
the set.
b:=1; e:=K;
while b<e do
begin c:=(b+e)div 2; if M[c]<i then
b:=c+1 else e:=c
end;
if M[b]=i then begin while b<K do
begin
M[b]:=M[b+1]; b:=b+1;
end;
K:=K-1;
end;
Removal is performed only if such an element exists. When the while loop ends, b=e, the element
to be removed is at the location M[b]. To remove this element, all elements located in places from b
+ 1 to K are sequentially shifted to the left by one
position.
The complexity is O(K) if the object to be deleted was, or O(log K) if
this object was not in the set.
End of example.
Example 7.7. Operations on two sets given by ordered arrays A and B with the number of
objects in them K1 and K2 , respectively. The result of the calculations is in array C, the number of
elements in it is K3.
Union (A U B):
Sets 111
else begin
K3:=K3+1; C[K3]:=B[i2];
i2:=i2+1; i1:=i1+1
end;
while i1<=K1 do begin
K3:=K3+1; C[K3]:=A[i1]; i1:=i1+1end; while
i2<=K2 do begin
The union of sets in the form of ordered arrays is performed according to the
merge principle. However, unlike the merging of ordinary arrays, which may contain
elements with duplicate values, here in the first loop, when the elements in both
arrays have not yet been completely scanned, i.e. the loop continuation condition is
true, there are three options: 1) A[i1]<B[i2], then an element from A is copied into
the array C ;
2) A[i1]>B[i2], then an element from B is copied into array C ;
3) A[i1]=B[i2], then an element from B is copied into array C , but in this
case, both elements are considered scanned: A[i1] and B[i2].
When the first loop ends, either the elements from array A, the elements from
array B, or no elements remain unscanned. Then the remaining elements are added
to the end of the array C.
Intersection (A ÿ B):
i1:=1; i2:=1; K3:=0; while
(i1<=K1)and(i2<=K2) do
if A[i1]<B[i2] then i1:=i1+1 else if
A[i1]>B[i2] then i2:=i2+1 else begin
K3:=K3+1; C[K3]:=B[i2];
i2:=i2+1; i1:=i1+1
end;
Machine Translated by Google
112 Lecture 7
Sets 113
P3:=p1;
while (p3<>nil)and(p3^.s<>i) do p3:=p3^.p;
if (p3<>nil)and(p3^.s=i)then FOUND else NO;
Adding object number i to the set. First, it is checked whether the object
number i already belongs to the set. If not, then the object is added to the beginning
of the list.
Machine Translated by Google
114 Lecture 7
P3:=p1;
while (p3<>nil)and(p3^.s<>i) do p3:=p3^.p;
if (p3=nil) then begin
new(p3); p3^.s:=i; p3^.p:=p1; p1:=p3;
end;
while (p4<>nil)and(p4^.s<>i) do
p3:=p4; p4:=p4^.p end;
if (p4<>nil)and(p4^.s=i) then begin
if p3<>nil then p3^.p:=p4^.p
else p1:=p1^.p;
dispose(p4)
end;
K:=0; p3=p1;
while (p3<>nil) do
beginK:=K+1; p3:=p3^.p end;
Example 7.9. Operations on two sets given by unordered lists. The pointer p1 points to the
beginning of the 1st list, the pointer p2 points to the beginning of the 2nd list. As a result, a 3rd list
is created with the pointer p3.
Machine Translated by Google
Sets 115
Union of sets:
while(p5<>nil)and(p7^.s<>p5^.s)do p5:=p5^.p;
if p5=nil then begin
new(p6); p4^.p:=p6; p4:=p6; p6^.s:=p7^.s;
end;
p7:=p7^.p;
end;
p4^.p:=nil; p6:=p3; p3:=p3^.p; dispose(p6);
First, a fictitious element of the 3rd list is created (with the pointer p3),
then copies of the elements of the 1st list are attached to it in the 1st cycle.
The pointer p4 points to the last element in the 3rd list.
Then, the loop goes through all the elements of the 2nd list, and for
each of them in the nested loop, a match is checked with any of the
elements of the 1st list. If there was no match, then a copy of the element
from the 1st list is attached to the 3rd list.
Finally, the dummy element at the beginning of the 3rd list is destroyed.
Intersection of many:
while(p5<>nil)and(p7^.s<>p5^.s)do p5:=p5^.p;
if p5<>nil then begin
new(p6); p4^.p:=p6; p4:=p6; p6^.s:=p7^.s;
end;
p7:=p7^.p;
end;
p4^.p:=nil; p6:=p3; p3:=p3^.p; dispose(p6);
Machine Translated by Google
116 Lecture 7
Here, too, a dummy element of the 3rd list is created first. Then, in a loop, all the
elements of the 2nd list are viewed, and for each of them in
the nested loop checks for a match with any of the elements of the 1st list. If there
was a match, then a copy of the element from the 1st list is attached to the 3rd list.
Finally, the dummy element at the beginning of the 3rd list is destroyed.
Symmetric set difference:
while(p5<>nil)and(p7^.s<>p5^.s)do p5:=p5^.p;
if p5=nil then begin
new(p6); p4^.p:=p6; p4:=p6; p6^.s:=p7^.s;
end;
p7:=p7^.p;
end;
p7:=p2;
while p7<>nil do begin p5:=p1;
while(p5<>nil)and(p7^.s<>p5^.s)do p5:=p5^.p;
if p5=nil then begin
new(p6); p4^.p:=p6; p4:=p6; p6^.s:=p7^.s;
end;
p7:=p7^.p;
end;
p4^.p:=nil; p6:=p3; p3:=p3^.p; dispose(p6);
Sets 117
Example 7.10. Actions on an ordered list representing a set. The p1 pointer points to the
beginning of the list.
P3:=p1;
while (p3<>nil)and(p3^.s<i) do p3:=p3^.p;
if (p3<>nil)and(p3^.s=i)then FOUND else NO;
end;
It is separately checked whether the list is empty, and then it is created from the i element.
Otherwise, the loop checks if the object number i already belongs to the set. If not, the new
element is inserted at the beginning of the list or between p4 and p5.
118 Lecture 7
Example 7.11. Operations on two sets given by ordered lists. The pointer p1
points to the beginning of the 1st list, the pointer p2 points to the beginning of the
2nd list. As a result, a 3rd list with pointer p3 is created.
All operations are implemented by algorithms using the merge method, but,
unlike a normal merge, the created list should not contain elements with the same
value. Similar to operations on unordered lists, first a dummy element of the 3rd list
is created, to which other elements of the list are attached, and at the end this
dummy element is removed.
Union of sets:
end;
while (p11<>nil) do begin
new(p5); p4^.p:=p5; p4:=p5;
p5^.s:=p11^.s; p11:=p11^.p end;
Sets 119
The operation differs from the usual merge in that in the first cycle, if two
consecutive elements of the 1st and 2nd list are equal, then only one such element
is copied.
Intersection of many:
new(p3); p4:=p3; p11:=p1; p22:=p2;
{Dummy element created}
while (p11<>nil)and(p22<>nil) do
if p11^.s<p22^.s
then p11:=p11^.p
else if p11^.s>p22^.s then
p22:=p22^.p
else begin
new(p5); p4^.p:=p5; p4:=p5;
p4^.s:=p11^.s;
p11:=p11^.p; p22:=p22^.p end;
This operation differs from a normal merge in that if two successive elements
of the 1st and 2nd list are equal, then only one such element is copied, and
unequal elements are not copied.
120 Lecture 7
end;
while (p11<>nil) do begin
new(p5); p4^.p:=p5; p4:=p5;
p5^.s:=p11^.s; p11:=p11^.p end;
The operation differs from a normal merge in that in the first cycle,
only unequal consecutive elements from the 1st and 2nd lists are feasted.
End of example.
4. Write a program that converts the representation of a set from an ordered array M of numbers of
objects in the set into a binary array A of length n
elements, if it is known that the cardinality of the set is equal to K. What is its complexity?
5. Write a program that converts the representation of a set from an unordered array M of the numbers
of objects in the set into a binary array A of length n
elements, if it is known that the cardinality of the set is equal to K. What is its complexity?
Sets 121
if it is known that the cardinality of the set does not exceed L. Calculate the cardinality
of the set K.
7. Write a program that converts a set representation from an ordered list of numbers of
objects in the set into a binary array A of length n elements, if it is known that the
cardinality of the set is K. What is its complexity?
8. Write a program that converts a set representation from an unordered list of numbers of
objects in the set into a binary array A of length n elements, if the cardinality of the set
is known to be K. What is its complexity?
9. Prove the correctness of a program that adds an object to a set represented by an
integer ordered array. What is its labor intensity?
10. Prove the correctness of a program that removes an object from a set represented by
an integer ordered array. What is its labor intensity?
11. Prove the correctness of the program that calculates the union of the sets given
integer unordered arrays. What is its labor intensity?
12. Prove the correctness of the program that calculates the intersection of the sets given
integer unordered arrays. What is its labor intensity?
13. Write a program for calculating the symmetric difference of sets given
integer unordered arrays. Prove its correctness. What is its labor intensity?
14. Prove the correctness of the program that calculates the union of the sets given
integer ordered arrays. What is its labor intensity?
15. Prove the correctness of the program that calculates the intersection of the sets given
integer ordered arrays. What is its labor intensity?
16. Write a program for calculating the difference of the difference of sets given by ordered
integer arrays. Prove its correctness. What is its labor capacity?
17. To prove the correctness of a program that removes an object from a set is presented
ordered list. What is its labor intensity?
18. Prove the correctness of the program that calculates the union of the sets given
unordered lists. What is its labor intensity?
19. Prove the correctness of the program that calculates the intersection of the sets given
unordered lists. What is its labor intensity?
20. Write a program for calculating the difference of sets given by unordered lists. Prove the
correctness of the program. What is its labor intensity?
21. Prove the correctness of the program that calculates the union of the sets given
ordered lists. What is its labor intensity?
22. Prove the correctness of the program that calculates the intersection of the sets given
ordered lists. What is its labor intensity?
23. Write a program for calculating the difference of sets given by ordered lists. Prove the
correctness of the program. What is its labor intensity?
Machine Translated by Google
Lecture 8
Character strings and tables
In the table in fig. 8.1 and fig. 8.2 the character code (in hexadecimal) is
calculated as the sum of the row number (from 0 to F) and the number that
marks the column. For example, the character code '<' is:
Machine Translated by Google
The main ASCII table contains characters with codes from 0 to 127, 7
bits are enough to write them. When writing a code to a byte (8 bits), the
most significant bit is set to zero.
00 10 20 30 40 50 60 70
0 0 @P '
p
one ! 1 AQ aq
2 "2BR br
3 # 3 CS cs
four
$ 4 DT dt
5 % 5 EU
6 & 6 FV fv
7 '
7 gw gw
eight
( 8 HX hx
9 ) 9 IY iy
A * :JZ z
j
B + ; K[k{
C , <L\l|
D - = M]m}
E . >N ^ n~
F / ?O _ o
Rice. 8.1
124 Lecture 8
80 90 A0 B0 C0 D0 E0 F0
0ARaÿÿÿ1BSbÿÿÿsÿ R Yo
2 V T in ÿ ÿ ÿ t ÿ
3GUg ÿÿÿ4DFd y
ÿÿÿfÿ
5EXeÿÿÿxÿ
6 Zh C f ÿ 7 Z W h ÿ ÿ ÿ ÿÿcÿ
hÿ
º
8 I W i ÿ ÿ ÿ w 9 Y SH i ÿ ÿ
ÿ
sch •
AKbkÿÿ ÿÿÿ
BLYlÿÿÿsÿ
C M b m ÿ ÿ ÿ b No.
DNEn ÿ
ÿÿe¤
E O Yu o ÿ ÿ ÿ yu ÿ
ÿÿ I
FPInÿ
Rice. 8.2
Character strings. You can create arrays from characters, just like other
data types. In addition, you can describe character strings as special arrays.
Description example:
var s1, s2: string[20];
1) first, the first characters of both strings are compared with each other, then the
second, etc.;
2) the comparison continues until the first mismatch between the two characters
being compared, the larger string is considered to be the one whose code of the next
character is larger;
3) if the first line completely coincides with the beginning of the longer second line,
then the first line is considered to be smaller. Examples of comparing two strings:
The universe for this example is the set of all possible strings from 0 to 20
characters long. The number of objects in such a universe is usually
much more than what can be renumbered by integers of standard length. So, for this
example:
1+256+2562 +2563 + . . . + 25620 \u003d (25621 - 1) / (256 - 1) ÿ 1.467 ÿ 1048 .
Machine Translated by Google
126 Lecture 8
The algorithms for sets of character strings are identical to the corresponding
algorithms for sets of numbers, since strings can be ordered and compared like
integers. Such a set can be ordered by any sorting algorithm (direct or indirect).
varz:string[20];
The form of the algorithm is the same as for sorting an array of numbers:
End of example.
128 Lecture 8
The scomp function returns -1 if the string s1 is less than s2, returns 0,
if the strings are equal, and returns +1 if the string s1 is greater than s2.
It is easy to see that the complexity of the program is linear and is
determined by the number of characters in a shorter string (n1 and n2 are the
string lengths):
O(min(n1, n2)).
End of example.
Example 8.3. Sorting an array of strings, taking into account recoding.
Description of array D and auxiliary string z:
varD: array[1..1000]of string[20];
z:string[20];
End of example.
If the next character in the array S coincided with the first character in the string
d , then in the second (inner) loop the match of the subsequent characters of the
string d with the characters of S is checked . located symbols of the array S: S[i],
S[i+1], .
. ., S[i+m-1].
The program has a worst-case O(nÿm) complexity. Really,
since a mismatch can be detected when comparing the last, m - th character of
the pattern, it takes from 1 to m
character comparisons.
End of example.
130 Lecture 8
If the pattern string to be searched does not contain any characters, but
only some, then the search can be performed more efficiently than the
laborious O(m n) bone. Let, for example, the characters in the sample string
can only be letters. We will consider such a line as a word. Then we can
assume that the entire text in which the search is performed consists of
words separated by other characters (not letters). And then in the search
algorithm for each next character it is necessary to determine whether it
refers to letters or separators. In addition, we will use the variable p in the
algorithm, which is a sign of word recognition:
p=0 if the word hasn't started yet (or there were only delimiters),
p=1 if the word started (there were letters),
p=2 if the word has ended and is recognized.
To check separators, we will use a special Y table (an array of constants):
1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,0);
Example 8.6. Contextual search for the word d (first match) in sim
free array S of length n , taking into account character recoding:
m:=length(d); p:=0; j:=1;
while (p<2)and(j<=n) do
beginc:=S[j];
if p=0 then start
if Y[ord(c)]=1 then {beginning of word} begin
d1:=c; p:=1; i:=j end
end
else begin
if Y[ord(c)]=1 then d1:=d1+c
{word continues}
else if scomp(d,d1)=0 then p:=2
{word ended and matched the pattern}
else p:=0
{word ended but did not match the pattern}
end;
j:=j+1
end;
if p=0 then i:=0
else if (p=1)and(scomp(d,d1)<>0) then i:=0;
132 Lecture 8
Here the loop runs n+1 times, inside the loop j runs through values from 1
up to n+1, processing the symbol S[j]. When j=n+1 , a space character is
processed, this is necessary so that after the last word in the text there must
be a separator. The next word from the array S is accumulated in the
variable d1 . When a character other than a letter is encountered at p=1, the next
Machine Translated by Google
the word is fully formed in d1, and it is compared in a loop with all the
samples from the array D using the scomp comparison function with
recollation. When a match is found, the comparison loop is forcibly
interrupted and the word and number i of the beginning of this word in array D are ou
Labor input: O(nÿk), since each selected word from the text can be compared
in the worst case k times, and the total length of all words in
text does not exceed
n. End of example.
Example 8.8. Recognition of a group of words in a character array S of
length n:
p:=0; j:=0;
while j<=n do begin j:=j+1;
134 Lecture 8
Unlike the algorithm in Example 8-7, this assumes that the array D of k strings
of characters is pre-ordered with respect to recoding. Therefore, the comparison of
the word formed in the string d1 with the words from the array D is performed by a
dichotomous algorithm.
Labor input: O(n log k), since the comparison loop of the generated
words with words from the array D is executed no more than log k times.
End of example.
Here , all words are sequentially selected from the array S and written into the
array of strings D without repetitions. In the variable k is calculated
the number of selected words.
Machine Translated by Google
Laboriousness: O(nÿk), since each selected word from the text when searching
for repetitions can be compared in the worst case k times, and the total
The total length of all words in the text does not exceed n.
End of example.
an information table where each column defines a field and each row is a record. In
the program, the information table can be presented in various ways:
Then the i-th record in the information table is a set of array elements: {A[i], B[i],
C[i]}.
Description for the second method:
136 Lecture 8
Surname Result for the 1st type Result for the 2nd type
Array M1 – place according to the 1st type, real type; array M2 – place
according to the 2nd type. real type ; MS – the sum of places for two types, real type; M0-
common place for two types, type real. In addition, you will need an index array In
( integer type) to order the columns indirectly .
The program uses the place procedure, which calculates places (in
array M ) by one result (in array R):
Example 8.10. Joining individual result tables for two views into a common
table. The results of the athletes' competitions are presented in two tables:
138 Lecture 8
Surname F Result for the 1st type R1 Result for the 2nd type R2
The program for calculating the intersection of sets of rows from the 1st and 2nd
tables by last names:
F[n]:=F1[i1];R1[n]:=R01[i1];R2[n]:=R02[i1];
i2:=i2+1; i1:=i1+1
end;
The sort2 procedure used in the program sorts the character strings of the
array given as the first parameter while rearranging the elements of the numeric
array, the second parameter. The third parameter specifies the sizes of the arrays.
It is required to calculate the average grade and the number of current grades
for each student:
sort2(F,R,n);
S:=0; k:=0; m:=0; for i:=1
to n do
beginS:=S+R[i]; k:=k+1;
if (i=n)or(F[i]<>F[i+1]) then begin
m:=m+1;
FS[m]:=F[i]; KS[m]:=k; RS[m]:=S/k
S:=0; k:=0
end
end;
The sort2 procedure sorts the character strings of the array given as the first
parameter while rearranging the elements of the numeric array, the second parameter.
After that, the grades for each student will be placed in a row in the array R.
The loop then calculates the sum of grades and their number for one student. In
the if statement , the condition will be true when the
a group of records with the same last name.
The complexity of the entire program is determined by the complexity of using
sorting algorithm and can be estimated as O(n log n) .
End of example.
1. What is the cardinality of the set of all possible strings from 1 to 20 characters long,
containing symbols - only Russian lowercase letters? Is it possible to renumber all
elements of this set as integers (32 bits long) or int64s ( 64 bits long), and why?
140 Lecture 8
6. Write a procedure for lexicographic ordering of an array of character strings using a lookup
table, based on the merge sort procedure.
7. Write and debug a program that enters two character strings (the first is a long string, the
second is a short one) and performs a contextual search for all matches of the second string
within the first, identifying uppercase and lowercase letters. Create tests for the program
using the black and white box method and conduct testing
nie.
8. Write and debug a program that first enters a character string with a length of up to 20
characters, containing a word from Russian letters. Then the program enters a character-by-
character text of arbitrary length containing words from Russian letters separated by
separators, at the end of the text - the symbol '#', and which, during the input process, looks
for all matches (with identification of uppercase and lowercase letters) of the entered string
with the words in the text. Create tests for the program using the black and white box method
and conduct testing.
9. Write and debug a program that enters character-by-character text of arbitrary length
containing words from Russian letters separated by delimiters, at the end of the text - the '#'
symbol, and which, during the input process, selects all words and forms a dictionary of
these words as an array of strings. In the dictionary, all words must be different (with the
identification of uppercase and lowercase letters). It is assumed that the length of any word
is no more than 20 characters, and the number of different words in the text is no more than
1000. Create tests for the program using the black and white box method and conduct
testing.
10. Write and debug a program that completely solves the problem of "sport triathlon": it enters
three separate tables of results of athletes in separate
types, after which it calculates and displays the places of athletes by the sum of places, I have
providing results for all three types. Each table is entered as follows: 1) number of athletes
participating, 2) athlete's name, space, numerical result, space, etc. It is assumed that the
number of athletes is no more than 100, the length of surnames is no more than 20
characters. Create tests for the program using the black and white box method and conduct
testing.
11. Write and debug a program that calculates the average grades of students in two subjects:
first, it enters the total number of grades n, then n lines, each line contains a last name, a
space, a subject number (1 or 2), a numerical grade. It is assumed that the number of
students is no more than 50, the number of all assessments is no more than 1000. Display
the results for subject 1 first, then for subject 2. Create tests for the program using the black
and white box method and conduct testing.
Machine Translated by Google
Lecture 9
C language. Basic concepts
C program (or C++). Represents one or more text files with the extension
"c" or "cpp". During translation, each file is first processed by the preprocessor,
which, executing the preprocessor directives, makes some program
transformations, in particular, inserting text from the files specified in the
directives. Then the actual translation into machine instructions is performed,
the result is an object module - a file with the "obj" extension. An object module
is not yet an executable module: as a rule, it contains references to other object
modules, in particular, to standard functions from the program library. At the
final stage, the linker works, which combines all linked object modules into a
single executable module with the "exe" extension. Each text file of the program
may contain the following parts
sti:
142 Lecture 9
basic types - char (character), int (integer), unsigned (unsigned), float (float), double (double
length float), long (long), short (short) - can be combined. In general, describe
sleigh constants:
Description of variables:
If the variable is an array, then the number of elements is written after the name in square
brackets. If the variable is a pointer, then an asterisk is written before the name.
defines a constant - an array of 4 numbers occupying 8 bytes each with the value specified in
the description. Description:
defines three integer variables, each occupying 2 bytes in memory, which can have a value in
the range from 0 to 216 - 1. Description:
defines two arrays of floating (real) variables occupying 4 bytes in memory. In array A , the
elements are numbered from 0 to 99, in array B , from 0 to 9 along the first dimension, and from
0 to 19 along the second dimension. The number of elements in arrays is defined in the
description and cannot be changed during program execution. Description:
In some cases, the void specifier is used, which specifies an undefined data type.
priority that determines the order of execution, from 1st (highest) to 15th
(lower). Operations of the same priority are executed either from left to
right or from right to left, as shown in Table 9.1. Operations are also
subdivided into unary (with one operand), binary (with two) and ternary (with
three operands).
Table 9.1
Priory Order
tet
Operations performance
[] -> . ÿ
4 +- ÿ
5 << >> ÿ
7 == != ÿ
8 & ÿ
^
9 ÿ
10 ÿ
11 | && ÿ
12 ÿ
13 || ? : ÿ
144 Lecture 9
The sizeof operator calculates the size (in bytes) of the operand. There
are two possible formats for the operation: sizeof <expression> or sizeof
(<type>). The operation does not evaluate the value of the expression, it only determines
lays its type.
Unary operators with precedence 2 (++ --) can be used in prefix or postfix
form. In the first variant, they are written before, and in the second, after the
operand. The operand must be a variable of numeric type. The result of the
operation is the same variable whose value is either increased by 1 (operation +
+) or decreased by
Machine Translated by Google
1 (operation --). In the prefix version, the operand variable is first changed and
then used, in the postfix version, it is first used,
and then changes.
(a/b)*b + (a%b) = a.
Additive operations with precedence 4 - addition (+) and subtraction (-) -
can have any numeric operands and even pointers. The type of the result is
determined by the type of the operand with the largest bit width. If at least one
of the operands is real, the result will also be real. If both operands are integer,
then the result will also be integer. If the first operand is a pointer and the
second operand is an integer, then the result is a pointer.
Priority 5 shift operations (<< >>) require integer operands. The first
operand, treated as a bit vector, is shifted left (<<) or right (>>) by the number
of bits equal to the second operand. When shifting to the left, the vacated
positions are filled with zeros; when shifting to the right, they are also filled with
zeros if the first operand has a type with the descriptor unsigned or the high bit
otherwise.
Machine Translated by Google
146 Lecture 9
The rest of the assignment operators combine the usual binary operation
(<oper>) with the assignment. The notation a <oper>= b is equivalent to a =
a <oper> b.
The comma (,) operator separates consecutively (left to right) evaluated
expressions. The result of the operation is the value of the last expression
evaluated.
Operators in the C language. An expression ending with a semicolon
is considered an operator. A sequence of statements enclosed in curly
braces is also considered a statement. The if statement can take the full
form:
if (<expression>)<operator-1> else <operator-2>
or shortened form:
if (<expression>)<operator-1>
Machine Translated by Google
while statement:
while (<expression>)<statement>
implements a cyclic algorithm. When executed, <expression> is evaluated. If it
is equal to 0, then the execution of the loop ends, if not, then the <statement> is
executed, the <expression> is evaluated again, and so on.
for statement:
for(<expression-1>;<expression-2>;<expression-3>)<operator>
also implements a cyclic algorithm. When it is executed, <expression-1> is first
evaluated. Then <expression-2> is evaluated. If it is equal to 0, then the execution
of the loop ends, if not, then the <operator> is executed, after it - <expression-3>,
then <expression-2> is evaluated again, etc.
Machine Translated by Google
148 Lecture 9
do statement:
do {<list of statements>} while (<expression>);
implements a cyclic algorithm with a condition check at the end. When it is
executed, the <list of statements> is executed first, after that the <expression>
is evaluated. If it is equal to 0, then the execution of the loop ends, if not, then
the <list of statements> is executed again, the <expression> is evaluated, and
so on.
return statement:
return <expression>;
is the last executable statement within the function declaration.
After it, the program resumes execution after calling this function. In this
case, the calculated <expression> is the result of the function. The
<expression> may be absent in the statement record if the type of the
value produced by the function is declared as void.
Example 9.1. The program for entering numbers, their ordering and output:
#include ”stdafx.h” /* or <stdio.h> 1*/
void main(void) /*3*/ /*2*/
{int i, n, z, X[1000]; /*four*/
scanf(”%d”,&n);
for(i=0;i<n;i++) scanf(”%d”,&X[i]); /*5*/
i=0; / /*6*/
*7*/
while(i<n-1) /*8*/
if(X[i]<=X[i+1]) i++; else
/*9*/
{z=X[i];X[i]=X[i+1];X[i+1]=z; /*ten*/
if(i>0)i--; } /*eleven*/
/*12*/
for(i=0;i<n;i++) printf("%8d",X[i]); /*13*/
printf("\n"); /*fourteen*/
} /*fifteen*/
programs, followed by descriptions in curly braces, and program statements. The 3rd
line describes the integer variables i,n,z and an array X of 1000 elements.
4th line - call the standard function of data input from the keyboard. The 1st
parameter is a character string that specifies the input format for the 2nd parameter.
Character strings - constants in C are enclosed in double quotes. The % character
means that the character following it specifies a specific format, the d character
indicates an integer format. The 2nd parameter specifies a reference ( by the &
operation) to the variable n, since the result of the input will be the assignment of the
entered value to the variable n .
5th line - loop through the first n elements of array X, at each step
loop - input value for X[i].
In lines from 6 to 12 - the simplest improved sorting algorithm
values for n elements of array X.
13th line - a loop through the first n elements of the X array , at each step of the
loop - the output of the standard function of the value of X[i], the output format is 8
characters for each number, all numbers are displayed in one line in the output
window. 14th line - format output that sets the transition to a new line in the output
window.
End of example.
9.2. Functions
The header first indicates the type of the value returned by the function (it can
be void), then the name of the function, then the descriptions of the formal parameters
of the function, taken in parentheses, separated by commas. For example, description:
150 Lecture 9
defines a function sq2 with two formal parameters of type float, substituted by value,
which evaluates a result of type float. The calculation calls the standard square root
function sqrt. An example of calling this function from another function or main
program:
floatt; t=sq2(4,5.5);
Such a description is necessary in the program text file where the call to
this function is recorded, if the full description of the function is available in
another object file with the obj extension. For example, description:
float sq2(float x, float y);
sets the header of the sq2 function. The title must fully match the full description of
the function.
Example 9.2. A program with a function that exchanges the values of two
variables:
#include ”stdafx.h” void
mov(int *a, int *b)
{int z=*a; *a=*b; *b=z;}
void main(void)
{int x,y;
scanf("%d%d", &x, &y);
mov(&x,&y);
printf("x=%dy=%d\n",x,y);
}
The mov function does not return any value, i.e. used as a procedure. Its two
formal parameters (a and b) are described as references (pointers) to variables of
type int. Inside the function, an auxiliary variable z of type int is declared; its
description is combined with assignment. Since assignments do not refer to references,
but to values to which
Machine Translated by Google
parameters are referenced, they are used in conjunction with the unary
operation *(jump from reference to object).
In the main program, the scanf function enters numerical values for the variables
x and y, after which the mov function is called, in which these variables, as actual
parameters, are written with the unary operation & (transition from an object to a
reference to it).
At the end, the changed values of the variables x and y are displayed. The first
parameter in the printf function (output format string) specifies the following output
order: 1) x= text, 2) x value, 3) two spaces, 4) y= text, 5) y value, 6) change to new
output line.
End of example.
Example 9.3. Program with a function that calculates the minimum value
value in array:
The pmin function does not return any value, i.e. used as a procedure.
The first formal parameter X is described as a reference to an array of
elements of the int type, the second parameter n must specify the number
of elements in the array X and is declared as a value of the int type, the
third r is a reference to the value of the int type, which is used as a result
of calculations when calling the function .
In the main program, the variable A is declared as a reference to an int value, it
is further used as an array name. After entering the value
Machine Translated by Google
152 Lecture 9
for the variable n , the new operator allocates a memory area for n elements
of type int, and the reference A is assigned the address of the location of this
area. Then the values for the elements of the array A are entered in the loop
and the pmin function is called, the result of its calculations is assigned to the
min variable . At the end, the text min= and the result of the calculations are
displayed, and the memory area for the array A is also freed.
End of example.
Example 9.4. Program with a function that returns the minimum value
value in array:
Unlike the program in Example 9-3, here the pmin function returns the result of
the calculation directly, so its call is written as the right side of an assignment
statement.
End of example.
Example 9.5. Function (procedure) of merge sort in an array. The b
and e parameters specify, respectively, the number of the first and the
number of the last element in the array, which will be ordered. Parameters A and B
set references to arrays of the same size. In array A , elements are ordered, array B
is auxiliary. Variables c, i1, i2, j are local, their description is combined with assignment.
Machine Translated by Google
This program must be translated along with the description of the sort
function by adding the #include preprocessor directive . In the program,
the variables X and Y are declared as references to values of type int, they
are used as array names. After entering the value for the variable n , the
new operator allocates two memory areas with n elements of type int for
arrays X and Y. Then, in a loop, values are entered for the elements of array X
Machine Translated by Google
154 Lecture 9
and the sort function is called , after which the values of the elements of
the ordered array X are displayed in a loop, separated by spaces. At the
end, memory areas for arrays are freed.
End of example.
} else queen(k+1);
H[i]=0; R[i-k+21]=0; L[i+k]=0; }
} The algorithm is completely similar to the procedure from example 6.8, differs
from it only in that the array R, like all other arrays, has element numbering, starting
from zero, so when calculating the index, the number 21 is added. The sizes of the
arrays are set so that the generation is valid up to n equal to 20. End of example.
Example 9.8. The program enters the board size n for the queen problem
and calls the queen function:
void main(void) {int i;
scanf("%d",&n);
for(i=1;i<=n;i++) H[i]=0;
for(i=2;i<=n+n;i++)
{R[i]=0; L[i]=0;}
queen(1); }
Machine Translated by Google
Before calling the queen function , the program resets those elements
in the arrays H, R , and L that are used in the function for a given value.
n.
End of example.
Example 9.8. Calculation of the integral of a continuous function by the
trapezoid method. For an approximate calculation of the integral of the function
f(x) on the interval [a, b], the area under the curve y = f(x) is replaced by the
sum of the areas of the trapezoids obtained by dividing the interval into n equal
parts, as shown in Fig. 9.1.
a b
Rice. 9.1.
where d = (b - a) / n.
The Integr function calculates the integral for the integrand f
on the interval from a to b when splitting the interval into n parts:
float Integr(float(*f)(float),float a,float b,int n)
{int i; float d,s; s=(f(a)+f(b))/
2; d=(ba)/n;
for(i=1;i<n;i++) s=s+f(a+i*d);
return s*d;
}
156 Lecture 9
Examples of calls to the Integr function with sub-integral functions f1 and f2:
1. There is a description: int *x,y; What actions are correct and what they mean in operators:
x=y; y=5; *x=10; x=*y; *y=20;
2. In what order will the operations be performed and what do they mean in the operator:
x+=(b*c+d)*2<i&(y=a==b);
3. What is the function header description for without the function algorithm itself?
4. Write and debug a program in C that enters three numbers, checks if it is possible to construct
a triangle with sides of that length, and if so, calculates
its area. Create tests for the program using the black and white box method and
conduct testing.
5. Write in C a description of the function with two parameters: the name of the array is real
of elements and its length, which returns a real value, and which calculates the sum of the
elements of the array. Write an example of calling this function.
6. Write in C a description of a function with three parameters: the name of a real array, its
length, a reference to a real value (the result of calculations), and which calculates the sum
of the array elements. Write an example of calling this function.
7. Write in C and debug a program that contains a description of a function that implements the
sorting of a real array by the insertion method. The program should
enter the size of the array, allocate memory for it, enter the elements of the array, call a
function, print the array after sorting, check that the array has become ordered. Create tests
for the program using the black and white box method and conduct
testing.
8. Write in C a description of the function that generates all combinations of numbers from n to m.
Write an example of calling this function.
9. Write in C a description of the function Sum that returns a real value and has two parameters:
1) a reference to a function f with one integer parameter that returns a real value; 2) the
number of summed elements n. Sum function
should calculate the sum: Sum=f(1)+f(2)+. . .+f(n). Write examples of calling the function
2
Sum for functions f: 1/n, 1/n , n, n 2 .
Machine Translated by Google
Lecture 10
C language. Continuation
In this description, the field s is the content, the field p is a pointer to the next
element in the list. In the following examples with lists, we will use
This is the type description.
The -> operation performs a transition from a pointer to a structure field (element
list ment) referenced by the pointer.
Example 10.3. Ordering a list using the merge method, the slist function is used
in the sortlist function :
Machine Translated by Google
160 Lecture 10
Example 10.4. Reading numbers from 1st text file and output to 2nd
text file of the number of numbers and their average value:
void main(void)
{FILE *F1,*F2; intn,k,s;
char *S1="in.txt", *S2="out.txt";
if((F1=fopen(S1,"r"))==NULL||
(F2=fopen(S2,"w"))==NULL) puts("Error!\n"); else
{n=0; s=0;
while(feof(F1)==0)
{fscanf(F1,"%d",&k); s+=k; n++;}
fprintf(F2,"%d %8.3f\n",n,float(s)/n);
fclose(F1); fclose(F2); }
}
Machine Translated by Google
The FILE descriptor defines two pointers F1 and F2 (file variables). Variables
S1 and S2 are pointers, they are assigned references to character strings, they set
the names of two files.
The 1st call to the fopen function associates the file name S1 (1st parameter)
with the file variable F1, the string "r" (2nd parameter) opens this file for reading as
a text file. The 2nd call to the fopen function associates the file name S2 (1st
parameter) with the file variable F2, the string "w" (2nd parameter) opens this file for
writing as a text file. If at least one of the variables F1 or F2 is set to NULL (which
means that the file could not be opened), then an error message is displayed by
calling the puts function.
If both files can be opened, then in the loop the fscanf function sequentially
reads the integers written in file F1 , calculates their sum and number. The feof
function call checks that the end of the file has not been reached, and then the loop
continues.
After the end of file F1 is detected, the loop ends, and after it the number of
numbers read is output to file F2 , then 3 spaces, and then the average value of the
numbers in real format (8 positions, of which 3 digits after the decimal point). At the
end, both files are closed with the fclose function.
End of example.
{n=0;
while(feof(F1)==0)
{k=fread(X,1,4096,F1);fwrite(X,1,k,F2); n+=k;}
fclose(F1); fclose(F2); printf("File
length=%ld\n",n); }
}
Machine Translated by Google
162 Lecture 10
Here the main program is declared with the parameters p and S, and after
translation it can be called on the command line as a function with two parameters. If
the translation specifies that the compiled program will be given the name fcopy,
then the call from the command line should be in the form:
The p parameter specifies the number of character lines in the program call,
including both the name of the program itself and the names of two files, i.e. in this
example, the correct value for p is 3. The S parameter is of type an array of references
to character strings that are written on the command line, i.e.
S[0] is a link to a line with the program name, S[1] is a link to a line with the name
of the 1st file, S[2] is a link to a line with the name of the 2nd file.
The if statement checks that p is equal to 3, after which the 1st file is opened
with the "rb" option as a binary file for reading, and the 2nd file is opened with the
"wb" option as a binary file for writing. If p is not equal to 3, or at least one of the
variables F1 or F2 is null, then an error message is displayed.
If both files were successfully opened, then in the loop, the fread function
sequentially reads the data written in file F1 into the array X, as in 1 block of 4096
bytes long , and the fread function returns the number of bytes read into the variable
k . The write function writes data from array X to file F2, while the variable n counts
the number of all bytes read. The feof function call checks that the end of the file has
not been reached, and then the loop continues.
After detecting the end of the file F1 , the loop ends, and after it
both files are closed with the fclose function, and the text is displayed on the screen
"File length=" and the value n.
End of example.
In particular, the header file stdio.h contains descriptions of the I/O functions.
In the printf and scanf functions, the first parameter is a character string
containing the conversion specifications. Each conversion specification
corresponds to one value in the output list (or one pointer to a variable in the input
list). In general, the specification looks like:
The required character here is the percent sign and the specifier letter,
defining the type of input or output data:
d or i – int type, displayed as decimal digits;
u – unsigned type, displayed as decimal digits;
o – type unsigned or int, displayed as an octal digit
mi;
x or X – unsigned or int type, displayed as hexadecimal digits;
164 Lecture 10
Table 10.1
Type of Type of
Function Explanation
arguments result
strcat char *s1, char * String concatenation. After the
char*s2 characters of the string s1 , the
characters from s2 are added. Returns
a pointer to string s1
strchr char*s, char * Searches for the character c in the string s . Returns
char c
a pointer to the found character
strncat char *s1, char * At most n characters from s2 are added after the
char*s2, characters of the string s1 . Returns a pointer
unsigned n to string s1
Machine Translated by Google
166 Lecture 10
131,132,133,134,135,136,137,138,139,140,141,142,
143,176,177,178,179,180,181,182,183,184,185,186,
187,188,189,190,191,192,193,194,195,196,197,198,
199,200,201,202,203,204,205,206,207,208,209,210,
211,212,213,214,215,216,217,218,219,220,221,222,
223,144,145,146,147,148,149,150,151,152,153,154,
155,156,157,158,159,133,133,242,243,244,245,246,
247,248,249,250,251,252,253,254,255};
The table corresponds to the ASCII encoding, CP866. scomp lek function
sicographic comparison of two strings with recoding:
inline int ord(char c) { return /*type char -> int*/
c<0 ? c+256 : c;}
int scomp(char *s1, char *s2)
{int i=0,r=0;
while(s1[i]!=0 && s2[i]!=0 &&
T[ord(s1[i])]==T[ord(s2[i])]) i++;
if(s1[i]!=0 && s2[i]!=0)
{if(T[ord(s1[i])]<T[ord(s2[i])])r=-1;
else r=1;
}
else if(s1[i]!=0) r=1; else if(s2[i]!
=0) r=-1;
return r;
}
If Y[i]=1, then the character with code i is a letter, and if Y[i]=0, then
the character is not a letter. The dictionary compilation program is described
with the q and S parameters; after translation, it can be called on the
command line as a function with one parameter - a character string
containing the file name. The value of the q parameter must be 2. The if
statement checks that q is equal to 2, after which the file F1 named S[1] is opened.
Machine Translated by Google
168 Lecture 10
is stored in line d1. If p=1, and if Y[i]=1, then the read character is added to
the string d1. If p=1 and Y[i]=0, then a null character is added to the string
d1 - a sign of the end of the string, after which the array is searched for a
match of the word in the string d1 with the words previously placed in the
array D. If no match is found, then n is increased by 1, for the nth element of
the array D , memory is allocated, into which d1 is copied.
10.3. C syntax
170 Lecture 10
vertical bar, should be read as “or”), characters { } (large curly braces), characters
[ ] (large square brackets);
7) if two parts of the definition are separated by the symbol |, then for a specific
of the new variant of the concept being defined, only one of these parts is used;
For example, consider the rule for the concept <name>. One of the variants of
its definition is a letter (capital or lowercase Latin) or underscore. Another definition
is a name followed by a letter or number or underscore. In Russian, the rule for the
<name> concept can be written as follows: a name is a sequence of letters,
numbers, and underscores beginning with a letter or underscore.
The considered grammar rules do not completely specify the C language, since
as not all concepts have their definitions.
1. Write and debug a C program that contains a description of a function that implements
merge sort for lists. The program must enter the size of the list, enter values for the
elements of the list and form a list from them, call the sort function, and display the
list after sorting. Create tests for the program using the black and white box method
and conduct testing.
Machine Translated by Google
172 Lecture 10
2. Write and debug a C program that enters the name of an input file, then opens that file for input,
enters n integers from the file , then n numbers, sums them up, and outputs the sum. Create
tests for the program using the black and white box method and conduct testing.
3. Write and debug a program in C that contains a description of the function for comparing two
strings with recoding, enters character by character text of arbitrary length containing words
from Russian letters separated by delimiters, at the end of the text is the '#' symbol, and
which in the process input selects all the words and builds a dictionary of those words as an
array of strings. In the dictionary, all words must be different (with the identification of uppercase
and lowercase letters). It is assumed that the number of different words in the text is not more
than 1000. Create tests for the program using the black and white box method and conduct
testing.
4. What does the C translator check, syntax or semantics? What happens to a C program if there
are no syntax errors in it? Is such a program correct?
5. Which of the names are correct and which are not, and why:
f, 3f, _32, _abc, 3_a, b11110
6. In which case in the if statement before the else should there be a semicolon, and when -
shouldn't, and why?
Machine Translated by Google
Lecture 11
Algorithms of linear algebra. Vectors and matrices
First, the sizes of the arrays n and k are entered, memory is allocated
for an array X of n elements of type float, and n values are entered for all
n elements of the array X in a loop . If increased precision of calculations
with real numbers is required, then the type should be double.
Then memory is allocated for an array M of n elements of float reference type,
and in a loop for each element M[i] memory is allocated for k
Machine Translated by Google
174 Lecture 11
float elements . After that, n*k values are entered in a double loop for all elements of
M[i][j].
At the end of the program, when the arrays are no longer needed, the
allocated memory for them can be freed:
for (i=0; i<n; i++)
delete[] M[i];
delete[]M;
delete[]X;
End of example.
Operations on vectors and matrices. Addition and various types of
multiplication of vectors and matrices are realized directly by the definition of
the corresponding operations.
Example 11.2. Calculation of the sum of vectors (arrays) A and B of
dimension n. The result is a vector (array) C:
End of example.
Example 11.3. Calculation of the sum of matrices (two-dimensional arrays) A
and B of dimension n×m. The result is a matrix (two-dimensional array) C dimensionally
n × m:
End of example.
Example 11.4. Calculation of the scalar product of vectors (arrays) A
and B of dimension n. The result is the variable d.
d=0;
for (i=0; i<n; i++)
d+=A[i]*B[i];
End of example.
Machine Translated by Google
176 Lecture 11
End of example.
This program differs from the program in Example 2.10 only in that it is written in
C. The result of the condition in the if statement is 1 (which is true) if s is odd, and 0
if s is even. Shift right by 1 with assignment (>>=) for a non-negative value of s is
equivalent to dividing s by 2.
This is two multiplications more than necessary. One extra multiplication occurs when z equal to 1
is multiplied by y. The second extra multiplication is performed when, at the last step of the loop , s
is equal to 1, y is raised to
square, but y is not used further.
If the complexity of multiplication is high, then it is advisable to use an
improved version of the program, the number of multiplications in which
does not exceed 2ÿÿlog2 pÿ:
s=p; y=x;
while (!(s&1)) {s>>=1; y*=y;}
z=y; s--;
while (s>0)
{if (s&1) {s--; z*=y;}
s>>=1; if
(s>0) y*=y;
}
The difference from the improved version of the program from Example 11.8 is that here the
object to be exponentiated is a square matrix, so
Machine Translated by Google
178 Lecture 11
Axb
ÿÿ
,
ÿ
all elements below the main diagonal are zero. This is done by adding one of the
equations to the other, multiplied by a specially selected coefficient, as a result,
the coefficient for one of the variables becomes zero, and this process (forward
move) continues until a triangular matrix is obtained. Further, the elements lying
above the main diagonal are zeroed in the same way (this stage is called the
reverse move). As a result, the matrix becomes diagonal, and the unknowns are
calculated from it by dividing the right side by the corresponding diagonal
coefficient on the left side of the equation. Let us consider the intermediate stage
of the forward move, when it is required to set the coefficients ai + 1,i , ai + 2,i , …,
an,i to zero (in the formula i = 3):
ÿ aaa 11 12 13 ... a ÿ ÿx ÿ ÿb ÿ
one n one one
0 ... a x b
ÿ ÿ ÿ ÿ ÿ ÿ
aa 22 23
ÿ
2n ÿ ÿ
2 ÿ ÿ
2 ÿ
ÿ 00 a 33 ... a ÿ
ÿ
ÿ x ÿ
ÿ
ÿ b ÿ
3n 3 3
ÿ ÿ ÿ ÿ ÿ ÿ
ÿ ÿ ÿ ÿ ÿ ÿ
ÿ ÿ ÿ ÿ ÿ ÿ
ÿ 00 a ... a ÿ ÿx n ÿ ÿb n ÿ
ÿ ÿ ÿ ÿ ÿ ÿ
n3 nn
the following problem: the divisor ai,i may turn out to be equal to zero, and then
the coefficient c cannot be calculated. Moreover, if this coefficient is not equal, but
close to zero, then the result (unknown x1, ..., xn) will be calculated with large
errors. The point is that calculations over real numbers in a computer are performed
approximately, i.e., with rounding errors, and in this case the errors increase many
times over. To solve this problem, in the Gauss method, the leading (having the
maximum absolute value) element is selected among the matrix coefficients that
have not yet been processed. The easiest way is to choose it from ai,i , ai + 1,i ,
…, an,i . So that the solution of the system of equations does not change becauseof
this, it is necessary to interchange the row with the selected element with the i-th
row of the matrix (having also exchanged the corresponding coefficients of the
ÿ
vector b ).
Example 11.10. The program implements the Gaussian method with the
choice of the leading element in the column. Array A of dimension n×(n+1) in the first n
columns contains coefficients for unknowns, and in the last column -
Machine Translated by Google
180 Lecture 11
ce are the coefficients of the right side of the equation. The result is an array X of n
unknown.
Let's estimate the complexity of the program. At the stage of the forward stroke in the cycle for i
three actions are performed: 1) selection of the leading element, 2) permutation of
equations, 3) subtraction of equations. The number of executions of the innermost
loops in these actions in all loop steps for i , respectively:
2
T1(n) = (n – 1) + … + 1 = nÿ(n – 1)/2 ÿ n /2,
2
T2(n) = n + (n – 1) + … + 1 = nÿ(n + 1)/2 ÿ n /2,
Machine Translated by Google
3 2 3
T3(n) = (n – 1)(n + 1) + (n – 2) n + … + 1ÿ3 = (2n +3n – 5n)/6 ÿ n /3.
Number of executions of the inner loop during the reverse stage:
2
T4(n) = n + (n – 1) + … + 1 = nÿ(n + 1)/2 ÿ n /2.
Number of cycle steps at the stage of calculating unknowns:
T5(n) = n.
Thus, the total complexity of the entire algorithm is of the order
3
O(n ), and the main contribution to the complexity is made by the subtraction of the equations
3
in the forward stroke, the number of which is approximately equal to n /3.
End of example.
Example 11.11. The function of solving the system of equations implements the
Gauss method. In the program in Example 11-10, the forward step assumes that
each time A[v,i] is selected as the pivot, a non-zero value is obtained. If this is not
the case, then the subsequent division into it will cause an emergency termination of
the program execution. Moreover, if the leading element is not equal, but close to
zero, then due to the accumulation of rounding errors in calculations over real
numbers
the result obtained (the value of the unknowns) may be far from expected and cannot
be trusted. To detect such a situation, the following check is performed in the system
function:
float eps=0.000001;
int system(int n, float **A, float *X)
{ int i, j, k, v; for (i=0;
i<n-1; i++) { /*select pivot A[v]
[i]*/
if (abs(A[v][i])<eps) return 0;
else
{/*permutation of the i-th equation with v-m*/
/*subtraction of equations*/
}
}
/*reverse*/
/*calculation of unknowns*/
return 1;
}
182 Lecture 11
A hard value with the given eps, and if it is less, then the function exits slowly with a
return value of 0. If the calculation reaches the end, then the function returns the
value 1.
End of example.
printf("\n");
}
else printf("ERROR\n");
}
(including the vector element of the right side of the system of equations). After
that, the system function is called to solve the system of equations and the
value of g returned by the function is checked . If g is equal to 1, then the values
of the unknowns calculated in the array X are displayed in the loop , otherwise
an error message is displayed.
End of example.
1. Write a function for calculating the sum of two vectors, a function for calculating the
scalar product of two vectors, and a function for calculating the product of a vector and
a scalar. Write examples of their calls. What is the complexity of these functions and
why?
2. Write a function for calculating the sum of two matrices. Write an example of calling it.
What is its complexity and why?
3. Write a function for calculating the product of a matrix and a scalar. Write an example
her call. What is its complexity and why?
4. Write a function for calculating the product of a vector and a rectangular matrix. Write an
example of calling it. What is its complexity and why?
5. Write a function for calculating the product of a rectangular matrix by a vector. Write an
example of calling it. What is its complexity and why?
6. Write a function for calculating the product of two rectangular matrices. Napi
give an example of calling it. What is its complexity and why?
7. Write a function that calculates the product of a rectangular matrix and its transposed one.
Write an example of calling it. What is its complexity and why?
8. Write a program that contains a description of the function of raising a square matrix to a
positive integer power, counting the number of matrix multiplications. The program must
input the matrix and degree, call the function, and output the result. Create tests for the
program using the black and white box method and conduct testing. What is its complexity
and why?
9. Write a function for solving a system of linear equations with the following parameters: 1)
the dimension of the system, 2) the square matrix of the coefficients of the equation, 3)
the vector of right-hand sides, 4) the vector of calculated unknowns. Write an example
of calling it. What is its complexity and why?
10. How do the laboriousness of calculating the product of two square matrices compare
and solutions to a system of linear equations of the same dimension, and why?
Machine Translated by Google
Lecture 12
Algorithms of linear algebra. Continuation
float eps=0.000001;
i=0; r=n; p=1; while
(i<r)
{v=i; /*choose the leading element A[v][i]*/ for (j=i+1;
j<n; j++) if (abs(A[j][i])>abs(A[v][i] )) v=j;
if (abs(A[v,i])<eps) r=i;
else
{if (v!=i) /*reverse lines*/ {p=-p;
}
/*subtraction of matrix rows*/
for (k=i+1; k<n; k++) {c=A[k][i]/
A[i][i];
for (j=i; j<n; j++)
A[k][j]-=c*A[i][j];
}
i++;
}
}
/*calculation of the determinant*/
if (r<n) X=0;
else
{X=p*A[0,0];
for (i=1; i<n; i++) X*=A[i][i];
}
186 Lecture 12
ÿ
ÿ
In this case, one should take into account the case when the determinant of the system is equal to
zero, and then the inverse matrix does not exist.
Example 12.2. The program calculates the inverse matrix D to the original
matrix A by the Gaussian method:
float eps=0.000001;
/*setting the identity matrix D*/
i=0; r=n;
while (i<r)
{/*choose the leading element A[v,i]*/
if (abs(A[v][i])<eps) r=i;
else {/
*permutation of matrix rows*/
/*divide the i-th row by A[i,i]*/
/*subtraction of rows of matrices*/
i++;
}
}
An n×n array A contains the coefficients of the matrix. Comments here indicate
individual actions in the program. Definition of the identity matrix D:
aii=A[i][i];
for (j=i; j<=n; j++) A[i][j]/=aii; for (j=1; j<=n; j++)
D[i][j]/=aii;
If, after the execution of the program, the value of r turned out to be less than
n, then this means that the inverse matrix does not exist.
Due to the fact that, before subtracting the equations, the rows of matrices
A and D are divided by the diagonal element of matrix A, the diagonal
elements of matrix A become unit. In addition, unlike the program from
Example 11.10, here the subtraction of the rows of matrices is implemented in
such a way that the forward and backward steps are simultaneously performed,
in which both matrices A and D participate.
The complexity of the program, as well as the program from example 11.10,
is determined by the number of repetitions in cycles when subtracting equations.
Due to the combination of forward and reverse stroke, this number for matrix A
Machine Translated by Google
188 Lecture 12
3 3 3
/2, and for matrix D – n , those. total - 1.5ÿn
is equal to n . If rea
lize forward and reverse stroke separately, then the labor intensity can be ÿ
3 3 3
reduce to n /3 + n 1.33ÿn .
End of example.
ÿ aa 11 12 a 13 a 14 a 15 a
ÿ
one n ÿ
ÿ ÿ
0 a 22 a 23 a 24 a 25 ÿ
a
ÿ
2n ÿ
ÿ 0 0 0 a 34 a 35 ÿ
a ÿ
3n
ÿ ÿ
0 0 0 0 a 45 ÿ
a
ÿ
four n ÿ
ÿ ÿ
ÿ ÿ ÿ ÿ ÿ ÿ
ÿ ÿ
0 0 0 0 am ÿ
a
ÿ
ÿ
5 mn ÿ ÿ
Example 12.3. The program calculates the rank of matrix A using the Gaussian method:
float eps=0.000001;
for (r=0,i=0; (i<n)&&(r<m); i++)
{v=r; /*choose leading element: A[v][i]*/
for (j=r+1; j<m; j++) if (abs(A[j]
[i])>abs(A[v][i])) v=j;
if (abs(A[v][i])>=eps)
{if (v!=r) for /*permutation of the rth row with the vth*/
(j=i; j<n; j++)
{z=A[r][j]; A[r][j]=A[v][j]; A[r][j]=z;}
for (k=r+1; k<m; k++) {c=A[k] /*subtract rows*/
[i]/A[i][i];
for (j=i; j<n; j++) A[k][j]-=c*A[i][j];
}
r++;
}
}
Array A with dimension m×n contains matrix coefficients. The variable r keeps
track of the number of linearly independent rows, at the end of the calculation this will
be the rank of the matrix. When searching for a pivot element in the i-th column of the
matrix, it is checked that the pivot element is greater than a given small value eps,
otherwise it is considered zero. r=n. Choice of leading element
The complexity of the program for the case m ÿ n ,
menta:
T1(n,m) = (m – 1) + (m – 2) + … + (m – n + 1) =
2
= (2m – n) (n – 1)/2 ÿ mÿn – n /2.
String permutation:
2
T2(n) = n + … + 1 = (n + 1)ÿn / 2 ÿ n /2.
Row subtraction:
2 3
T3(n,m) = m n + (m – 1) (n – 1)… + (m – n + 1) 1 ÿ m n /2 – n /6.
General workload:
2 3
T(n,m) ÿ m n /2 – n /6.
Machine Translated by Google
190 Lecture 12
T(n) ÿ n3 /3.
End of example.
3) the system has infinitely many solutions if the rank r of the matrix A is less than
n, and the “extra” m – r equations are linear combinations of the remaining r equations.
In the latter case, the “extra” n – r unknowns can be considered independent and an
arbitrary set of values can be set for them, each time obtaining a new solution for
r “basic” unknowns.
The algorithm for obtaining a general solution must bring the matrix A to such a
form that the system of equations is as follows:
ÿ ten 0 a a ÿ ÿ b ÿ
1,r ÿ1
ÿ ÿ
one,
n one
ÿ ÿ ÿ ÿ
01 ÿ 0 a ÿ a b
2, r1ÿ 2, n 2
ÿx
ÿ ÿ ÿ ÿ
ÿ
ÿ ÿ ÿÿÿ ÿ ÿ ÿ
one
ÿ ÿ ÿ
ÿ ÿ
ÿ ÿ
x ÿ ÿ
00 a a 2
ÿ one ÿ
ÿ ÿ ÿ
ÿ
b
1rr, ÿ _ 2, n ÿ
ÿ ÿ ÿ
ÿ
r ÿ
ÿ
00 ÿ 00 ÿ 0 ÿ
ÿ ÿ
ÿ
b ÿ
rÿ
ÿ ÿ x one
ÿ nÿ
ÿ ÿ
ÿ ÿ ÿ ÿ ÿ ÿ
ÿ ÿ ÿ ÿ
00 00 0
ÿ
b
ÿ ÿ
ÿ ÿ
ÿ ÿ m ÿ
To do this, when choosing the leading element ai,i, it is necessary to look through
all the elements of the matrix A that lie in rows from the ith to the nth and in the
columns from the ith to the nth, performing the subsequent permutation of both two
rows and two columns. Then the solution variant of the system is determined by the
following checks:
Machine Translated by Google
1) the system has a unique solution if the rank r = n and the coefficients of the
right side br + 1, …, bm (if they exist) are errors);
rounding all equal to zero (or close to zero due to
2) the system has no solution if at least one of the coefficients of the right side
br + 1, …, bm is not equal to zero (or is not close to zero);
3) the system has infinitely many solutions if the rank r < n and the coefficients
of the right side br + 1, …, bm (if they exist) are all equal to zero
(or close to zero due to rounding errors).
In the first case, the values of the unknowns are equal to the first n coefficients
of the right side:
x1 = b1, …, xn = bn .
In the third case, the unknowns xr + 1 , …, xn are considered independent, and the unknowns
x1 , …, xr are calculated through them according to the formulas:
Example 12.4. The program for calculating the general solution of the system of
equations:
192 Lecture 12
Rearrangement of equations:
if (v!=i) for
(j=i; j<=n; j++)
{z=A[i][j]; A[i][j]=A[v][j]; A[v][j]=z;}
Column permutation:
if (u!=i)
{ for (k=0; k<m; k++)
{z=A[k][i]; A[k][i]=A[k][u]; A[k][u]=z;}
p=L[i]; L[i]=L[u]; L[u]=p;
}
c=A[i][i]; for
(j=i; j<=n+1; j++) A[i][j]/=c;
Subtraction of equations:
for (k=0; k<m; k++)
if (k!=i)
{c=A[k][i];
for (j=i; j<=n; j++) A[k][j]-=c*A[i][j];
}
Machine Translated by Google
i=r;
while (i<m && abs(A[i][n])<eps) i++;
if (i<m) {/*system solution does not exist*/} else if (r==n) /
*system solution is unique*/
{for (j=0; j<n; j++) X[L[j]]=A[j][n];}
else
{/* setting values for independent variables:
X[L[r]], ..., / X[L[n-1]]*/
*calculation of dependent variables:*/
for (j=0;j<r;j++)
{X[L[j]]=A[j][n];
for (k=r;k<n;k++)
X[L[j]]-= A[j][k]*X[L[k]];
}
}
Here the leading element is searched not in one i-th column of the matrix
A, but in the rectangular part of the matrix, from the i-th to the m-th row, and
from the i-th to the n-th column inclusive. And if it turns out that the leading
element is close to zero (thus, the first r rows and r columns of the matrix A
contain the identity submatrix), then the while loop terminates ahead of
schedule. When the columns are rearranged, the unknowns are renumbered
by exchanging the values in the index array L. The equations are subtracted in
such a way that the forward and reverse moves are combined.
After the while loop completes, it checks that the elements A[m][n] are close to
on the right hand side: A[r][n], ..., If it turns out that at least
zero.
one
elements
of them of
is the
greater
vector
(in
absolute value) eps, then the system of equations is inconsistent and has no solution.
If the check was successful, then two options are possible:
1) r=n, then the system has a unique solution, the values are unknown
known are calculated in the vector of the right side of the equations;
2) r<n, then the system has an infinite number of solutions, the unknowns
are divided into two groups: a) independent, they can be assigned any values,
their numbers are from r to n-1; b) dependent, are calculated through the
values in the vector of the right side of the equations with numbers from 0 to r-1.
Machine Translated by Google
194 Lecture 12
T1(n,m) = m n + (m – 1) (n – 1) + + … + (m – n + 1) 1 =
2 2
…/3+1
= n (n – 1)2 + ÿ n3 + (m+ –(mn)–nn) n + / … + (m – n) 1 ÿ
2 2 3
/2 = m n 2 – n /6.
Subtraction of equations:
2
T2(n,m) = m (n + 1) + m n + … +m2ÿmn /2.
2 3
Total labor input: T(n,m) ÿ m n – n /6.
3
Total labor intensity at m = n: T(n) ÿ 5/6 n .
End of example.
4. Write a program that enters a rectangular matrix and calculates its rank. Create tests for the
program using the black and white box method and conduct testing. What is its complexity
and why?
5. Write a program that calculates the general solution of a system of n linear equations with m
unknowns using the Gaussian method. What is its complexity and why?
6. How do the complexity of calculating the determinant of a square matrix,
rank of the same matrix and calculating the inverse of a matrix of the same dimension, and
why?
Machine Translated by Google
Lecture 13
Counts. Start
A graph is defined by two sets: a set of vertices and a set of edges (arcs).
An edge (arc) is defined by a pair of vertices (which it connects). There are
different types of graphs:
1) undirected graphs, in such graphs, for edges, the order of specifying
vertices in a pair is not important, if vertex i is connected by an edge to vertex
j, then this is the same as vertex j is connected by an edge to vertex i;
2) directed graphs, or digraphs, in such graphs, the arc determines the
order in which the vertices in a pair are specified; if there is an arc from vertex
i to vertex j, then the arc from vertex j to vertex i may or may not exist; loops
can also exist in such a graph, i.e. arcs from a vertex to itself;
196 Lecture 13
too efficient for use in algorithms that have to look at vertices and edges multiple
times.
Representation of a graph in graphical form. For clarity, the graph can be
depicted on a sheet of paper: graph vertices as dots or circles, edges in an
undirected graph as lines connecting pairs of vertices, arcs in a directed graph as
lines with arrows showing the order in which the vertices are connected. In this
case, the coordinates of the vertices do not matter, the vertices can be depicted
in any place on a sheet of paper. Lines can be straight or curved segments; line
intersections are not taken into account. A graph that can be drawn so that lines
(edges or arcs) do not intersect is called planar.
To view all vertices that are adjacent along edges to vertex i (or vertices to
which arcs from i go), it is necessary to iterate over the elements of the i-th row of
the matrix. To view the vertices from which arcs go to vertex i, it is necessary to
enumerate the elements of the i-th column of the matrix.
Representation of a graph by lists of adjacent vertices. If the number of edges
2
graph with a large number of vertices n is significantly less than n , then in
adjacency matrix, most of the elements will be zero, and the complexity of the
algorithms that look through all the edges will be much more than the minimum
possible. So, for example, according to the Euler theorem, in a planar graph, the
number of edges is less than 3ÿn, but the complexity of viewing all the edges by
2
the adjacency matrix will be of the order of O(n ).
In this case, it is more efficient to represent the graph as an array
of n pointers and n lists of vertices such that the i-th pointer refers to the list
containing the numbers of vertices adjacent to the i-th vertex. Those. each of the
lists is a set of adjacent vertices.
Machine Translated by Google
1234567111
(1,2)
one
one 2 3
3 (3.1)
2 2 one 3
(2.3)
3 111 one one 2 four
four
(4.3)
four one 3
5 6 (5.6) 6
5 one
6 one 5
7 7
Rice. 13.1
198 Lecture 13
First, the number of graph vertices n is entered, memory is allocated for an array
of n pointers to rows of the adjacency matrix. After that, memory is allocated in the
loop for n rows of the matrix with zeroing in the rows of matrix elements. Since in C
the numbering of array elements always starts from zero, the numbering of graph
vertices will also be from zero to n-1.
Next, the number of edges of the graph m is entered , after which m pairs of numbers i
and j of the vertices of the graph are entered in the cycle , and into the matrix M of the undirected
two units are entered in the graph: in the i-th row, j-th column, and also in the j-th
row, i-th column.
If a directed graph is given, then the unit for the edge is entered into the matrix
only once, in the i-th row, j-th column.
2
The complexity is of the order O(n ), since m ÿ n.
End of example.
First, the number of graph vertices n is entered, memory is allocated for the array
S of n pointers to lists. After that, pointers in the array S are set to zero in the loop.
Then lists of numbers of adjacent vertices are formed. For an undirected graph, two
list elements are formed for each edge, and for a directed graph, one element for each
arc. The complexity of both versions of the program is of the order O(n + m).
If the lists need to be ordered, then when filling the lists, it is necessary to count
their lengths in an integer array L , and then
Machine Translated by Google
1 2 3 4 5 6 7 8 9 10 2 3 1 3
LS D 124365
2 one
2 3
3 5
one eight
one 9
one ten
0 eleven
Rice. 13.2
Here, all lists are placed in an integer array D, the size of which for a directed
graph is equal to the number of edges, and for an undirected one, twice the number
of edges. These lists can be ordered to speed up searching. The array S contains
the indexes of the beginning for each of the lists, and the array L contains the lengths
of the lists. The length of arrays S
and L is equal to the number of graph vertices. If the graph is weighted, then another
array is needed (of the same length as array D) with edge weights.
To determine whether there is an edge (arc) connecting vertices i and j, it is
necessary among the elements of the i-th list:
find the element equal to j. When ordering lists, you can use
to develop a dichotomous search algorithm.
To view all vertices that are edge-adjacent to vertex i
(or vertices to which arcs from i go), it is necessary to enumerate all elements of
the i-th list. And to view the vertices from which arcs go to vertex i, it is necessary
to enumerate all lists, i.e. all elements of array D.
Machine Translated by Google
200 Lecture 13
First, the number of graph vertices n and the number of edges m are entered,
and memory is allocated to auxiliary arrays v1 and v2 of length m for entering edges.
Then, in a loop, pairs of numbers are entered into the arrays v1 and v2 , specifying
the numbers of the edge vertices. Next, memory is allocated to the arrays D, S , and
L of the graph structure, as well as to the auxiliary array U.
After that, the array L is reset to zero, then in this array, by looking at
the arrays v1 and v2 , the lengths of the lists are calculated, which will later
be placed in the array D. After that, the initial indexes of the placement of
these lists are calculated in the array S. At the final stage, the array D is
filled, while the elements are distributed among the lists in one scan due to
the duplication of the initial indices in the array U, which keeps track of free
places in the lists. It is easy to see that the complexity of all stages is of the
order O(n + m).
Lists in array D can be ordered, then additional
telny stage at which each of the lists is sorted separately.
Machine Translated by Google
The program in the example defines an undirected graph when each edge in the
array D is represented in two lists. To specify a directed graph in the program, a
number of changes should be made:
1) allocate memory to the array D in the amount of m elements;
2) when calculating the lengths of lists in the array L , use only the array v1;
3) when distributing adjacent vertices over lists of the array D , place each edge
in only one list.
End of example.
The task of viewing all the vertices of an undirected graph, taking into account
the edges connecting them with neighboring vertices, is an important step in solving
many more complex problems. There are two main methods: depth-first lookup and
breadth-first lookup. The scan can start from any starting vertex. In this case, the
vertices can receive new but
measure in viewing order.
When browsing in depth, the loop looks for an unscanned vertex adjacent to the
current one. Once such a vertex is found, the algorithm starts recursively from this
new starting vertex.
Example 13.4. Recursive lookup function deep into the graph, given
adjacency matrix:
void deep(int k)
{int i;
for (i=0;i<n;i++)
if ((M[k][i]==1)&&(R[i]==0))
{nom++; R[i]=nom;
deep(i);
}
}
202 Lecture 13
The termination of the function execution follows from the fact that before the
recursive call deep(i) it is checked that R[i]==0 and R[i]=nom is assigned . Therefore,
the total number of calls cannot exceed n. The recursion depth is limited to the same
value n.
If the graph is connected, then by mathematical induction it can be proved that
all its vertices will be scanned. If the graph is disconnected, then all those vertices
that can be reached along the edges from the initial vertex a will be searched, i.e., to
all vertices of the connected component, where
vertex a enters.
The complexity of the program is determined by the fact that each time the
function is called, the loop is executed n times, looking through all the elements of
2
the row of the adjacency matrix, i.e. the total complexity is of the order O(n
). Depth
recursion does not exceed n.
End of example.
Example 13.5. Recursive lookup function deep into the graph, given
th array of lists:
void deeps(int k)
{el *p1;
for (p1=S[k];p1!=NULL;p1=p1->p;)
if (R[p1->s]==0)
{nom++; R[p1->s]=nom;
deep(p1->s);
}
}
The deeps function is similar to the function in Example 13-4, the calls to the two
functions are identical. However, in contrast to the deeps function, here the graph from
Machine Translated by Google
n vertices are given by an array of lists S, so each time the function is called
the loop is executed exactly as many times as there are adjacent vertices with vertex
k. In this case, the total execution of all cycles in all recursive calls does not exceed
twice the number of edges, i.e., the total labor capacity is of the order O(n + m) .
End of example.
Using the algorithm of viewing the graph in depth, it is possible to solve the problem of
extracting the connected components of the graph.
Example 13.6. The program for extracting the connected components of a graph from
n vertices:
The program generates the elements of array C, which determine the connectivity
components for graph vertices. The global variable q is the counter of connected
components. C[i]=q if the ith vertex belongs to the qth connected component. Initially,
all elements of the array C are assigned zeros, which means that none of the vertices
of the graph is assigned to any of the components. The outer loop in the program
finds the next vertex for which C[i]=0, assigns the number of a new component to this
vertex, and then scans the graph, starting from this vertex, assigning to all vertices of
the component (in array C) the same room. For the example of the graph shown in
Fig. 13.2, the result of calculations in array C will be as follows:
1, 1, 1, 1, 2, 2, 3.
In this program, the depth-first lookup function must be such that it has the
assignment C[i]=q before the recursive call. The modified cdeep function is shown
below. In addition, it uses another representation of the graph, in the form of an array
of numbers of adjacent vertices D:
Machine Translated by Google
204 Lecture 13
void cdeep(int k)
{int i, j;
for (i=S[k];i<S[k]+L[k];i++)
{j=D[i];
if (C[j]==0) {C[j]=q; cdeep(j);}
}
}
It is easy to see that the total complexity of the program, including time
execution of all cdeep function calls has the order O(n + m).
End of example.
In breadth-scanning, the given initial vertex is assigned a level of 1. Then, the
loop searches for all unscanned vertices adjacent to
with the current one, and they are assigned a level that is 1 greater than
the level of the current vertex. Then the next vertex among the sequence
of scanned vertices becomes current, and so on. As a result, all vertices
reachable from the initial vertex are assigned a level that is 1 greater than
the shortest distance from the initial vertex, measured by the number of
edges traversed.
Example 13.7. Breadth Viewer for a Graph of n Vertices, Given
in the form of an array of numbers of adjacent vertices:
P[0]=a; r=0; t=0; //queue of one vertex a
for (i=0;i<n;i++) V[i]=0;
V[a]=1; //level for vertex a
while (t<=r)
{k=P[t]; q=V[k]+1;
for (i=S[k];i<=S[k]+L[k]-1;i++)
{j=D[i];
if (V[j]==0) {V[j]=q; r++; P[r]=j;}
}
t++;
}
The V array contains the levels for the viewed vertices, and the P array
contains the queue of numbers of the viewed vertices. The size of these
arrays is n. Initially, the element P[0] is assigned the number of the initial
vertex a, the element V[a] is assigned one, and all other elements of the mass
Machine Translated by Google
siva V are zeros. The variable r denotes the number of scanned vertices placed in
the queue P, and the variable t is an element in the array P containing the number
of the current processed vertex.
The processing of the current vertex P[t] consists in the fact that all unseen
vertices adjacent to it are placed in the queue P, and they are assigned a level that
is 1 higher than the level of the vertex P[t].
For a connected graph, all n vertices will end up in queue P, and for each of
them, the for loop will be executed as many times as it has adjacent vertices, so the
total complexity is of the order of O(n + m).
End of example.
Unlike the program in Example 13-7, here the for loop is executed n times when
processing the current vertex , so the total time is of the order of O(n
2
).
End of example.
206 Lecture 13
1. Write a program that enters: 1) the number of graph vertices, 2) the number of directed
arcs, 3) arcs are pairs of vertices. The program must generate an adjacency matrix of a
directed graph. What is its complexity and why?
2. Write a program that enters: 1) the number of graph vertices, 2) the number of undirected
weighted edges, 3) edges - pairs of vertices and weight. The program must form the
adjacency matrix of an undirected weighted graph.
What is its complexity and why?
3. Write a program that enters: 1) the number of graph vertices, 2) the number of undirected
weighted edges, 3) edges - pairs of vertices and weight. The program must generate lists
of numbers of adjacent vertices with weights of an undirected weighted graph. What is its
complexity and why?
4. Write a program that enters: 1) the number of graph vertices, 2) the number of oriented
weighted edges, 3) edges - pairs of vertices and weight. The program must form an array
of numbers of adjacent vertices with weights of an undirected weighted graph. What is its
complexity and why?
5. Write a program that converts the representation of an undirected graph from an adjacency
matrix into an array of numbers of adjacent vertices. What is its laborious bone and why?
How should the program be modified if the graph is directed?
6. Write a program that converts the representation of an undirected graph from an array of
numbers of adjacent vertices into an adjacency matrix. What is its laborious bone and
why? How should the program be modified if the graph is directed?
7. An undirected graph is defined by an adjacency matrix. Write a program that singles out the
connected components of a graph by depth-first scanning and displays the following data
for each component: 1) the number of the component; 2) the numbers of the vertices
included in it. What is its complexity and why?
8. An undirected graph is given by an array of numbers of adjacent vertices. Write a program
that selects the connected components of a graph by depth-first scanning and displays the
following data for each component: 1) the number of the component; 2) but the measure
of the vertices included in it. What is its complexity and why?
9. An undirected graph is defined by an adjacency matrix. Write a program that singles out the
connected components of a graph by a breadth scan and displays the following data for
each component: 1) the number of the component; 2) the numbers of the vertices included
in it. What is its complexity and why?
10. An undirected graph is given by an array of numbers of adjacent vertices. Write a program
that selects the connected components of a graph by scanning in breadth and displays
the following data for each component: 1) the number of the component; 2) but the
measure of the vertices included in it. What is its complexity and why?
Machine Translated by Google
11. An undirected graph is defined by lists of numbers of adjacent vertices. Write a program
that selects the connected components of a graph by depth-first scanning and displays
the following data for each component: 1) the number of the component; 2) but the
measure of the vertices included in it. What is its complexity and why?
12. An undirected graph is given by lists of numbers of adjacent vertices. Write a program
that selects the connected components of a graph by scanning in breadth and displays
the following data for each component: 1) the number of the component; 2) but the
measure of the vertices included in it. What is its complexity and why?
13. An undirected graph is given by an array of numbers of adjacent vertices. The number
u of one of the vertices is also given. Write a program that, by breadth-first scanning for
all vertices, calculates the distance to them from the vertex u in the number of arcs
traversed. What is its complexity and why? How should the program be modified if the
graph is directed?
Machine Translated by Google
Lecture 14
Counts. Simple Algorithms
The problem of finding the shortest path in a maze can be solved by the
breadth-wise graph scanning algorithm. For this task, there is no need to use any
special structure for the graph: the representation of the maze as a two-
dimensional array is itself a graph.
Let the labyrinth be given by a numerical two dimensional array L, which
corresponds to an n × n square matrix . The zero element of the array
corresponds to the passage in the maze, and the element with a large value (for
example, 1000) corresponds to the wall in the maze. From an arbitrary cell of the
labyrinth, you can move (if there is no wall) in four directions: right, left, up or
down. Let also the initial cell L[i0,j0] and the final cell L[ik,jk] be given. On fig.
Figure 14.1 shows an example of a labyrinth, in which cells with a wall are marked
with a '#' , the upper left cell is the beginning of the path, and the lower right cell
is the end of the path.
########
H# # # one # # #
## # # 2 ## # eleven #
# # 3 four 5 # 9 10 #
# four 5 678 9 #
## # # 5 ## eight # ten #
# To # 6 # 10 9 10 11 #
########
Rice. 14.1
In this problem, the matrix L defines the graph itself. Cells with a value of 0
(cells with spaces in Figure 14.1) define the vertices of the graph. Each of the peaks
Machine Translated by Google
the graph has edges with those of the four adjacent vertices that also
contain 0. To simplify the checks that moving through the maze does not
go beyond its limits, the maze can be surrounded by walls on all sides, as
shown on the right in Fig. 14.1. The solution of the whole problem can be
performed in 4 stages: 1) data entry and formation of the maze structure;
2) marking the labyrinth; 3) tracking the shortest path along the markup; 4)
output of the result.
Example 14.1. Data entry and formation of the maze structure:
int L[22][22],i,j,n,i0,j0,ik,jk; charS[21]; scanf("%d\n",&n);
for (i=1;i<=n;i++)
{S=gets();
for (j=1;j<=n;j++) if
(S[j-1]=='-') L[i][j]=0;
else L[i][j]=1000;
} for (j=0;j<=n+1;j++)
{L[0][j]=1000; L[n+1][j]=1000;}
for (i=1;i<=n;i++)
{L[i][0]=1000; L[i][n+1]=1000;}
scanf("%d%d\n",&i0,&j0); scanf("%d%d\n",&ik,&jk);
The maximum dimensions of the labyrinth are 20×20. First, the size of the maze
n is entered, then line by line (in the character string S) the maze itself is entered,
after that the line i0 and column j0 of the beginning of the path, as well as the line ik
and column jk of the end of the path in the maze. Input data for the maze in fig. 14.1:
6
-#---#
-##-#-
---#--
------
-##-#-
-#----
eleven
66
Machine Translated by Google
210 Lecture 14
Here the symbol "-" corresponds to the zero cell, and the symbol "#" corresponds to the
cell with the wall in the labyrinth.
End of example.
Example 14.2. Labyrinth layout:
212 Lecture 14
The current tracked path is stored in arrays Mi and Mj. In addition, two
more arrays must be described to store the best path among the previously
tracked paths. The variable kmin stores the length of the best path. The i
and j parameters of the Lab function set the row number and column
number of the current cell, and the k parameter specifies the length from
the beginning of the tracked path to the current cell.
The exit from the recursion in occurs in two cases:
1) the current cell turned out to be the final cell of the path, and then the
new path is stored; 2) the current length of the route k turned out to be such
that when the path continues to some neighboring cell, its length will be no
shorter than the length of the previously memorized best path.
The complexity is determined by the fact that from the second, etc. of the current
cell, no more than three possible movements along the path are possible (since at least
Machine Translated by Google
one neighboring cell is marked with one), and then the total number of checked
cells will be no more than:
The output of the result for both variants of finding the shortest path before
is supposed to be implemented independently.
there is an arc to vertex j, then the label of vertex i must be less than the label of
vertex j. This markup is called topological sorting.
As is proved in graph theory, in a directed acyclic graph there must be at least
one vertex that does not contain any arcs. Then this vertex can be assigned the
label number 1. After deleting this vertex and the edges leaving it from the graph,
at least one more vertex will appear in the graph (if it did not exist before), which
does not include any arc, the next label is assigned to it, and t .d., while there are
still unlabeled vertices in the graph. This algorithm calculates
one of the possible topological sorts, of which there may be several for the same
graph. An example of a problem that reduces to computing a topological sort
214 Lecture 14
my works. In order to cook fried potatoes, you need to do the following work:
a) peel potatoes
b) wash the potatoes;
c) put the potatoes in the pan;
d) put oil in a frying pan;
e) turn on the stove and put the pan;
e) cut potatoes;
g) fry, turning, potatoes;
h) salt;
i) Remove the pan from the stove.
The sequence of work, as one of the solutions
task:
bÿaÿfÿeÿdÿcÿhÿgÿi
Writing to the array P (queue) the numbers of vertices that do not include any
one of the arcs:
k=-1; t=0;
for (i=0;i<n;i++)
if (R[i]==0) {k++; P[k]=i;}
When viewing the graph in width for each written in the array P
vertex i , as it were, the edges emerging from it are removed (in fact, 1 is subtracted from
each element q of the array R if there is an arc from vertex i to vertex q). In this case, as
soon as a new vertex with zero
Machine Translated by Google
the number of edges included in it, it is also written to the array P. The
program terminates its work when there are no vertices left in the graph
that can still be written to the array P. Scanning the graph in width according
to the queue in the array P:
while (t<k)
{i=P[t];
for (j=S[i];j<=S[i]+L[i]-1;j++)
{q=D[j]; R[q]--;
if (R[q]==0) {k++; P[k]=q;}
}
t++;
}
The complexity of the program is O(n + m), since each vertex is scanned once,
and all the arcs emerging from it are scanned.
gi.
Note also that if the graph is not acyclic, then there will definitely come
a moment when the while loop is executed when there is not a single
vertex with a zero number of edges included in it, although not all vertices
have yet been written to the array P. In this case, the while loop will stop
execution ahead of schedule, while k<n-1.
End of example.
Writing to the array P (queue) the numbers of vertices that do not include any
one of the arcs:
k=-1; t=0;
for (i=0;i<n;i++)
if (R[i]==0) {k++; P[k]=i;}
216 Lecture 14
while (t<k)
{i=P[t];
for (j=0;j<n;j++)
{if (M[i][j]==1)
{R[j]--;
if (R[j]==0) {k++; P[k]=j;}
}
}
t++;
}
2
The complexity of the program is O(n ), since each vertex is scanned once, and all
arcs outgoing from it are scanned.
End of example.
The result of topological sorting is a sequence of vertex numbers in the array P.
If for a graph vertex it is necessary to find its ordinal number in the array P, then the
permutation inverse to P should be calculated . The reverse permutation is defined as
follows. Let's fill the elements in the array Q with numbers 0, ..., n-1 so that Q[i]=i.
Then the i-th place in the topological sorting array P is the vertex
If weP[Q[i]]
sort theofarray
the graph.
P
while simultaneously permuting the elements of the array Q, then Q will be the reverse
permutation array. In fact, you don't need to sort anything: there is a much simpler
algorithm.
2, 3, 0, 5, 1, 4
Reverse permutation (array Q):
2, 4, 0, 1, 5, 3
End of example.
Machine Translated by Google
0 – 10 5 4 15
18–28 one
27 _ fifteen 3
3 12 3 13 – 7
4 20 11 9 10 –
Rice. 14.1
The zero row of the matrix is the length of the edges between vertex 0
and all the others. Among them, the minimum length to the 3rd vertex, this
will be the minimum distance, since the path through any other vertex to the
3rd will be longer. We recalculate the lengths of paths from vertex 0 through
vertex 3 to other vertices if they have become smaller. As a result, we
obtain the path lengths in Fig. 14.2.
Machine Translated by Google
218 Lecture 14
01234
– 7 5 4 11
Rice. 14.2
Among the calculated lengths of paths, the minimum length (with ignoring
vertex 3) is at vertex 2. Recalculating the lengths of paths through vertex 2 to
other vertices, we obtain the lengths of paths in Fig. 3a. 14.3.
01234
–6548
Rice. 14.3
01234
–6547
Rice. 14.4
If, in parallel with the recalculation of the lengths of the paths at each step, in
a separate array, for each vertex, we mark from which other vertex there was a
transition to it, then we obtain an array of references in Fig. 14.5.
01234
–2001
Rice. 14.5
Using such an array, you can restore (in reverse order) each shortest
path from vertex 0. For example, the shortest path from vertex 0 to vertex 4:
0ÿ2ÿ1ÿ4
current minimum distance from the given vertex a to vertex i. The element P[i]
contains the number of the vertex from which the last edge of the current shortest path
goes to vertex i. The array Q contains at signs that the vertices belong to two sets:
1) the set of vertices up to which the shortest path has already been calculated
distance. If vertex i belongs to this set, then Q[i]=0;
2) the set of other vertices, the shortest distance to them is calculated among
the paths passing only through the vertices of the 1st set. If vertex i belongs to this
set, then Q[i]=1.
When arrays are initialized, vertex a is attached to the 1st set, and all other
vertices, to the 2nd set. The second for loop is executed n-1 times, at each step of
the loop, one vertex from the 2nd set is added to the 1st set, to which there is the
shortest path from the vertex a, after which the arrays R and P are corrected. execution
of the loop keeps the assertions about the 1st and 2nd sets true, which proves the
correctness of the program.
After the completion of the second for loop, the array R will contain the shortest
distances from vertex a to all other vertices, array P -
references to the tops, the last ones in the shortest
2
The complexity of the program is O(n paths. ), since the second for loop is
executed n-1 times, and inside it there are sequentially two loops of n steps each.
End of example.
Machine Translated by Google
220 Lecture 14
Example 14.8. Calculation of the shortest distance and path between two
vertices a and b. In order not to perform unnecessary actions in the program from
Example 14-7, at each step of the second for loop , it is necessary to additionally
check that the vertex b is still in the 2nd set. To do this, the heading of the second for
loop must be replaced with the following:
Then this cycle can end ahead of schedule, as soon as the shortest distance to
the vertex b is calculated, but in the worst case, the complexity will still be O(n
2
).
Recovering the shortest path between vertices a and b (in reverse order):
1. Write a program that enters the maze, the beginning and end of the path in the maze,
calculates by viewing in breadth and outputs the shortest route in the form of a maze with
labeled cells along which the path passes. Create tests for the program using the black
and white box method and conduct testing. What is its complexity and why?
2. Write a program that enters the maze, the beginning and end of the path in the maze,
calculates it using the backtracking algorithm, and displays the shortest route in the form
of a maze with labeled cells along which the path passes. Create tests for the program
using the black and white box method and conduct testing. What is its labor capacity and
why?
3. Write a program that inputs directed graph data and represents
Returns it as an array of adjacent vertex numbers, then computes a topological sort and
determines whether the graph is acyclic. If the graph is acyclic, then it also computes the
inverse permutation of vertex numbers. Create those
Machine Translated by Google
sty for the program using the black and white box method and conduct testing. What is
its complexity and why?
4. Write a program that takes the data of a directed graph and represents it as an adjacency
matrix, then computes a topological sort and determines whether the graph is acyclic. If
the graph is acyclic, then it also calculates the reverse permutation of the vertex numbers.
Create tests for the program using the black and white box method and conduct testing.
What is its labor capacity and why?
5. Write a program that, for a directed graph represented as an array of lists of vertex
numbers, calculates the topological sort and determines whether the graph is acyclic.
What is its complexity and why?
6. Prove the correctness of the program for calculating the inverse permutation.
7. Write a program that enters the matrix of distances between the vertices of the graph and
the number of the initial vertex, after which it calculates and displays all the shortest
distances and all paths from the initial vertex to all the others. Create tests for the
program using the black and white box method and conduct testing. What is its complexity
and why?
8. Write a program that enters a matrix of distances between the graph vertices and the
numbers of the start and end vertices, after which it calculates and displays the shortest
distance and the path from the start vertex to the end vertex. Create tests for the program
using the black and white box method and conduct testing. What is its complexity and
why?
Machine Translated by Google
Lecture 15
Cycles and paths in graphs
An Euler cycle is such a closed path that starts at some vertex and passes
through all edges (arcs) of the graph
exactly one time. In this case, the cycle can go through some euler vertices
several times. If the graph is undirected, then the cycle can pass along the
edges in any direction, and if the graph is directed, then along each of the
arcs included in it, the direction of passage must coincide with the
orientation of the arc.
For an Euler cycle to exist, the graph must be connected, but this is not enough.
As is known from graph theory, in an undirected Euler graph, a cycle exists if and only
if all graph vertices are incident to an even number of edges. For a directed Euler
graph, a cycle exists if and only if exactly as many arcs enter each vertex as there are
exits from it. Therefore, before constructing an Euler cycle, it is necessary to check
the condition for its existence.
If the graph is directed, then first the number of arcs entering all
vertices is calculated in the array R , then it is compared with the number
of outgoing ones:
for (i=0;i<n;i++) R[i]=0;
for (j=0;j<m;j++) R[D[j]]++;
i=0;
while ((i<n) && (L[i]==R[i])) i++;
if (i==n) {exists} else {does not exist}
Machine Translated by Google
The complexity of the first check is O(n), the second check is O(n + m).
End of example.
If an Euler cycle exists, then, as a rule, it is not unique. Euler's algorithm
calculates any of the possible cycles. at first
a cycle is built, starting from an arbitrary, for example, the first, vertex. Then all
the vertices on the constructed cycle are looked through, and as soon as the
vertex i is found , from which the vertex i, which is not yet included in the cycle, leaves
arc, a side cycle is traced, which is then inserted after vertex i.
Since new fragments are repeatedly inserted into the loop being formed, it
is most convenient to use list structures for this. On fig. 15.1 shows how the
formed side cycle is inserted into the initial loop written in the linear list.
one i k one
pb p
i1 i
one i k one
pb p
Rice. 15.1
as soon as a new list element is formed, the arc included in the cycle is removed
from the graph representation (for this, the element L[i] is reduced by 1, and
Machine Translated by Google
224 Lecture 15
S[i] is increased by 1). At the end of the formation of the side cycle, it is inserted into
the main list as a separate list.
} else p=p->p
}
The complexity of the program is O(n + m), since all arcs of the graph are viewed
rush one time. End of
example.
q=1;
for (i=0;(i<n) && q;i++) {s=0; for
(j=0;j<n;j++) if (M[i][j]) s++; if (!
(s&1)) q=0; //if not an even number of edges }
q=1;
for (i=0;(i<n) && q;i++) {s1=0; for
(j=0;j<n;j++) if (M[i][j]) s1++;
Machine Translated by Google
s2=0;
for (j=0;j<n;j++) if (M[j][i]) s2++;
if (s1!=s2) q=0; //if quantity doesn't match }
//incoming and outgoing arcs
if (q) {exists} else {does not exist}
2 2
The complexity of both checks is O(n ), since all n
elements of the adjacency matrix M.
End of the example.
In contrast to the program from Example 15.1, an auxiliary array U is used here,
the element U[i] points to the element of the matrix M[i][k], from which one should
continue scanning the i-th row of the matrix to find the next vertex adjacent to i- and
top. When about-
Machine Translated by Google
226 Lecture 15
When an edge (i,k) is found, the matrix element M[i][k], as well as M[k][i], is
set to zero, since in an undirected graph each edge is represented by two matrix
elements. Otherwise, the program is equivalent to the program in Example 15.1.
2 2
The complexity is of the order O(n ), since all n
elements of the adjacency matrix M, and only once due to the use of the array
U.
End of example.
If the conditions for the existence of an Euler cycle are not met, then there
can be a non-closed Euler path in the graph that starts at one vertex and ends
at another. The condition for the existence of an Euler path in an undirected
graph is as follows: the valencies of two vertices are odd, and all other vertices
are even. The path starts at one of the odd-valency vertices and ends at another,
so the program tracks the initial path between these vertices first. The rest of
the path-building program remains the same.
Example 15.5. Checking for the existence of an Euler path or cycle. Graph
is given by an array D of numbers of adjacent vertices. If the graph is
undirected:
q=0;
for (i=0;(i<n)&&(q<3);i++)
if (L[i]&1) {q++; ib=ik; ik=i;}
if (q==0) {there is a loop}
else if (q==2) {path exists}
else {doesn't exist}
Machine Translated by Google
If the graph is directed, then first the number of arcs entering all
vertices is calculated in the array R , then it is compared with the number
of outgoing ones:
for (i=0;i<n;i++) R[i]=0;
for (j=0;j<m;j++) R[D[j]]++;
q=0;
for (i=0;(i<n)&&(q<3);i++)
if (L[i]!=R[i])
{q++;
if(R[i]==L[i]+1) ib=i;
else if(R[i]==L[i]-1) ik=i;
else q=3;
if (q==0) {there is a loop}
else if (q==2) {path exists}
else {doesn't exist}
The q variable counts how many vertices have an edge imbalance. In the ib
variable , the beginning is calculated, and in the ik variable , the end of the path
is calculated, while for an undirected graph, the beginning and end can be
exchanged with each other. The complexity of the first check is O(n), the second
check is O(n + m).
End of example.
Example 15.6. Calculation of the initial Euler path in a directed graph
with n vertices. The graph is given by an array D of numbers of adjacent vertices:
p=new struct el; pb=p; p->s=ib; i=ib; while (L[i]>0)
If the path exists, then a linear list will be built, in the first element of which the
vertex ib, and in the last element - ik. To build the entire Euler path after this program,
you need to execute the program from Example 15.2, without the initial assignments
before the main loop.
Machine Translated by Google
228 Lecture 15
The complexity of calculating the entire path is O(n + m), the same as for
the structure of the Euler
cycle. End of example.
Example 15.7. Checking for the existence of an Euler path or cycle. Graph
is given by the adjacency matrix M. If the graph is undirected:
q=0;
for (i=0;(i<n)&&(q<3);i++) {s=0; for
(j=0;j<n;j++) if (M[i][j]) s++; if (s&1)
{q++; ib=ik; ik=i;} }
}
if (q==0) {cycle exists} else if (q==2)
{path exists} else {does not exist}
Similar to the program in Example 15-5, the variable q counts how many
vertices have edge imbalances. In the ib variable , the beginning is calculated, and
in the ik variable , the end of the path is calculated, while for an undirected graph,
the beginning and end can be exchanged with each other.
Machine Translated by Google
2
The complexity of each verification option is O(n ).
End of example.
Similar to the program from Example 15.6, a linear list will be built, in the first
element of which the vertex ib, and the last element ik. To build the entire Euler path
after this program, you need to run the program from Example 15.4, removing the
initial assignments in it before the main loop.
2
The complexity of calculating the entire path is O(n ), the same as for
the structure of the Euler cycle.
End of example.
A Hamiltonian cycle must traverse all vertices exactly once, and along edges
(arcs) no more than once. In this case, some edges (arcs) may not be included in the
cycle at all. The Hamilton cycle also does not exist for every graph.
Machine Translated by Google
230 Lecture 15
The complexity of the program in the worst case is the same as that of the program
generating permutations for n - 1, i.e. O(nÿ(n – 1)!) = O(n!). If it turns out that there
are no Hamiltonian cycles for the given graph, then the program will not output
anything.
Note also that it is completely unimportant for the program whether the graph is
directed or not, since the program checks only edges or arcs outgoing from vertices.
End of example.
void hamilton1(int k)
{int i,j;
i=P[k-1];
for (j=0;(j<n)&&(z==0);j++)
if (R[j]==0)&&(M[i][j]))
{P[k]=j; R[j]=1;
if (k==n-1)
{if (M[j][0])
{OUTPUT LOOP; z=1;}
}
else hamilton1(k+1);
R[j]=0;
}
}
The global variable z=0 while no cycle has yet been evaluated. As soon as the
first loop is built, z=1, after which all recursive calls exit. Calling the hamilton1
function:
The complexity of the program in the worst case is the same as that of the program
calculation of all Hamiltonian cycles, i.e. O(nÿ(n – 1)!) = O(n!).
End of example.
Machine Translated by Google
232 Lecture 15
void hamiltonp(int k)
{int i,j;
i=P[k-1];
for (j=0;j<n;j++)
if ((R[j]==0)&&(M[i][j]))
{P[k]=j; R[j]=1;
if (k==n-1) {OUTPUT PATH}
else hamilton(k+1);
R[j]=0;
}
}
void hamiltonp1(int k)
{int i,j;
i=P[k-1];
for (j=0;(j<n)&&(z==0);j++)
if ((R[j]==0)&&(M[i][j]))
Machine Translated by Google
{P[k]=j; R[j]=1; if
(k==n-1) {OUTPUT PATH; z=1;} else
hamilton1(k+1);
R[j]=0; }
The complexity of the program in the worst case is the same as that of the program
calculation of all Hamiltonian paths, i.e. O(nÿ(n – 1)!) = O(n!). End of
example.
{P[k]=q; R[q]=1; if
(k==n-1) {r=S[q];
while (r<S[q]+L[q])
if (D[r]==0) {OUTPUT LOOP;
r=S[q]+L[q];} else r++;
}
else hamiltons(k+1);
R[q]=0; }
}
}
Machine Translated by Google
234 Lecture 15
Unlike the program in Example 15-9, here, to check for loop closure, we have to
iterate over the numbers of vertices adjacent to the last vertex to find vertex 0, where
the loop begins.
The complexity in the worst case can be estimated as O(m1ÿm2ÿ . . .ÿmn),
where mi is the number of vertices adjacent to the i-th vertex, since at the next
step of the recursion the loop is executed mi times. Calling the hamiltons
function is similar to calling the hamilton function.
End of example.
void hamiltonsp(int k)
{int i,j,q,r;
i=P[k-1];
for (j=S[i]; j<=S[i]+L[i]; j++)
{q=D[j];
if (R[q]==0)
{P[k]=q; R[q]=1;
if (k==n-1) {OUTPUT PATH}
else hamilton(k+1);
R[q]=0;
}
}
}
Calling the hamiltonsp function is similar to calling hamiltonp. Trudeau
capacity in the worst O(m1ÿm2ÿ . . .ÿmn), the same as in Example 15.13.
End of example.
void hamiltonsp1(int k)
{int i,j,q,r;
i=P[k-1];
for (j=S[i];(j<S[i]+L[i])&&(z==0); j++)
{q=D[j];
if (R[q]==0)
{P[k]=q; R[q]=1;
Machine Translated by Google
1 – 8 12 3 15
26 _ - 9 7 11
3 10 4 – 16 8
4 3 12 15 – 7
5 13 9 5 6 –
Rice. 15.2
Machine Translated by Google
236 Lecture 15
There are (n – 1) in total! variants of Hamiltonian cycles, i.e. 24. The solution
(traveling salesman route) is the cycle: 1 – 4 – 5 – 3 – 2 – 1. Its length is: 3+7+5+4+6=25.
The k parameter in the TSP function specifies the number in the P array ,
which contains the number of the current route vertex, and the S parameter
specifies the length of the partially constructed route from vertex 0 to vertex P[k-1].
Calling the TSP function and outputting the result:
Machine Translated by Google
The complexity of the program in the worst case is the same as that of the
program for computing all Hamiltonian cycles of the graph given by the adjacency
matrix, i.e., O(nÿ(n – 1)!) = O(n!).
End of example.
238 Lecture 15
7. Write a program that inputs the data of a directed graph and represents it as an adjacency
matrix, after which it calculates one (any) Hamiltonian cycle in the graph. What is its
complexity and why? Create tests for the program using the black and white box method
and conduct testing.
8. Write a program that takes the data of a directed graph and presents it as an array of
numbers of adjacent vertices, after which it calculates one (any) Hamiltonian path in the
graph. What is its complexity and why? Create tests for the program using the black and
white box method and conduct testing.
9. Write a program that enters a matrix of distances between the vertices of a graph, then
calculates and outputs the optimal traveling salesman route. What is its labor capacity and
why? Create tests for the program using the black and white box method
and do testing.
Machine Translated by Google
Lecture 16
Programming technology
The scientific discipline of programming technology began to be created in the 60s, when
large programs began to be developed by teams of programmers, and when the requirements for
program reliability increased. Subsequently, the recommendations of this scientific discipline were
included in various industrial and state standards. Recently, programming technology has become
known as software engineering.
6) instrumental software complex - a set of software tools designed to develop programs for
solving a certain set of tasks, can exist in the form of libraries of procedures,
classes, etc.;
7) software product - a program (system, complex) + documentation required for its use;
Machine Translated by Google
240 Lecture 16
8) the life cycle of a software product - the time from its beginning to
buildings until the last use.
Further, for brevity, a software product or a complex software product will also be
called a system. When planning the timing of system development, the labor costs
required for this should be taken into account. Creation of a software product, i.e.
program and documentation, requires about 3 times more work than writing a simple
program of the same size. Creating a software system or complex requires 3–4 times
more labor than writing a simple program of the same size. If a complex software product
is created, then in general, labor costs increase by approximately 10 times, see Fig. 16.1.
complex
complex program
3 product
program
one
one
2 3 program
program product
Fig.16.1
The system life cycle can be divided into the following phases:
1) analysis of requirements for the system - development of terms of reference;
2) design - development of a model for the functioning of the system,
its general structure, basic data structures;
3) coding - writing system components in a programming language
nie, their compilation and debugging;
4) testing of system components and the system as a whole;
5) documentation - creation of documentation for the system;
6) maintenance - control of the use of the system and, if necessary, refinement of
the system, release of new versions.
These actions may not be performed strictly sequentially; after any phase, a return
to the first phase can, if necessary, and the subsequent execution of subsequent phases
be repeated based on the corrected
Machine Translated by Google
technical task. The system lifecycle continues as long as the system is maintained.
computer terms.
A good system should also contain software tools that help the user quickly get used to
the system, help him if the user has forgotten something in the description of the application.
Usually these tools are implemented in the form of help texts called at any moment of the
dialogue with the system.
Machine Translated by Google
242 Lecture 16
ribbons.
244 Lecture 16
them, and also describes the functions associated with this data, called
methods. Objects are created, used, and destroyed during program
execution. All this facilitates the creation of large programs.
System design. When designing, the main internal data sets and their
structure are determined, a general enlarged structure of the system is
created, and it is divided into main components. The main algorithms for
implementation in the system are selected. The designed structure is
carefully analyzed to what extent it will satisfy the requirements of the
technical assignment. Often, for this purpose, a simplified operating layout
of the system (prototype) is created in order to analyze its compliance with
the terms of reference and clarify the requirements. When creating complex
systems, this process unwinds like a spiral,
Machine Translated by Google
in order to get a detailed design as a result, in which an algorithm and data structures for it
were defined for each component.
Coding. If the component algorithms are standard, then they can be automatically
coded using CASE tools. In other cases, you must create component programs manually.
You can use the drill down method, also known as the top-down method, to do this. The
essence of the method is that, first, the algorithm of the program as a whole (the first level
module) is developed, in which the second level modules are used, which have not yet been
described, but the input and output data are defined for them. Then, algorithms are
developed separately for each of the modules of the second level, within which, in turn,
modules (of the third level) are also allocated, etc., until it is possible to write all the modules
directly in the programming language. For complex programs, it is useful to represent their
structure in graphical form, as
module hierarchy.
Example 16.1. A program that calculates the determinant of a square matrix. The
program must take input, calculate the determinant, and output its value. Input order:
246 Lecture 16
The module of the second level "Calculation of the determinant" contains in its
queue, modules of the third level - algorithms from example 12.1.
On fig. 16.2 shows the hierarchy of program modules.
Program
Subtraction calculation
Selecting
a Leading Element Rearranging lines lines determinant
Rice. 16.2
End of example.
As attractive as top-down design is, sometimes you have to consciously
deviate from it. An example is the development of a system in which, at lower
levels, many of the modules repeat identical actions, perhaps with slight variations.
In this case, it is desirable to design such identical modules once and, having
implemented them in the form of procedures or functions, simply call them in the
right place. In essence, designing a set of such universal (for a given system)
modules does not differ from designing a complex
programs.
Bottom-up testing technology. Bottom-up testing begins when the design and programming
of all modules of the system is completed and inputs and outputs are defined for each module. First,
the modules of the lowest level are tested separately, which are called in the system from modules
of higher levels. To run a module under test for execution, it is necessary to write a test program for
it, which first enters the input data, then calls the module, and finally displays the output data.
In this case, black and white box methods are used. Then the higher-level modules are tested by
assembling them from lower-level modules and also creating test programs for them. And only at
the very last stage, the module of the highest level is tested, i.e. the whole program
face.
If testing really begins after the design of the entire system, then the bottom-up method provides
a fairly good quality. However, in practice, due to lack of time, testing often begins before the end of
the full design, and the system is also designed using the bottom-up method. As a result, when
testing high level modules, an error in matching the inputs and outputs of the called modules can be
detected, which will necessitate their modification. The higher the level of the unit under test, the
higher the probability of such an error and the more work is required to correct it.
Top-down testing technology. Top-down testing begins when the highest level module is
designed and programmed, and the modules it calls and their inputs and outputs are defined. Since
these modules do not yet exist, they are replaced with stubs for the duration of testing, i.e. modules
that, for a pre-prepared set of input data (test), produce a pre-prepared set of output data. Sometimes
a stub is implemented in the form of an extremely simplified
Machine Translated by Google
248 Lecture 16
a variant of the algorithm that solves the same problem that the module should
solve, but, perhaps, not in full.
At the subsequent stages of testing, each of the stubs is replaced in turn
with a real module, but with its own stubs. Thus, the system becomes more
and more complete during testing, and the whole process ends when the stubs
at all levels are replaced by real modules.
2) when designing and testing the next module, the probability of an error
in matching the inputs and outputs of the modules it calls decreases;
3) from the very beginning of testing, the system looks like a single whole,
which gives the programmer confidence in the successful completion of
development.
However, this testing method is not without some drawbacks, the main of
which is that it is difficult to carry out sufficiently complete testing for low-level
modules. Therefore, for full-fledged testing, it is desirable to use both methods
with the primacy of the top-down testing technology. After testing is complete,
all used stubs, testers, and test datasets are saved and their descriptions
included in the maintenance documentation. This is necessary so that, if
necessary, you can always repeat testing of any module in the system and the
system as a whole. Testing system parameters. As a rule, the terms of
reference provide the main characteristics that the system must satisfy. These
include, in particular, the maximum amount of input data, the maximum
requirements for RAM and disk memory to accommodate the system itself
and the data being processed, the processing time for large amounts of data,
etc. Therefore, to determine the real characteristics, it is required to test on
special test data sets. When executing a system with such tests, it is also
necessary to include an operator in the system.
Machine Translated by Google
ry measuring characteristics (the amount of occupied memory, time measurements before and after
processing, etc.). At the same time, it should be taken into account that the measured time is a
random variable that , with the same amount of processed data, depends on the specific values of
these data. Therefore, as characteristics of the system, it is necessary to use not the measured
values themselves, but their averaged values. In the simplest case, it is possible to average the
processing time intervals for a sufficiently large number of input data sets of the same size but
different content .
go.
Documentation testing. Operational documentation is written for the user, and it should
make it easier for him to work with the system. It has the following requirements:
3) documentation must be accurate, i.e. it should not contain any deviations from the truth in
the description of the functioning of the system and in the presentation of data.
Analytical testing (proof) in designing and writing programs. The technology of top-down
design allows the proof to be carried out during the design process. When designing the main
module of the system, an algorithm is created for which inputs and outputs are specified. If they are
written in the form of logical conditions, then this will be a precondition and a postcondition. Analysis
of the structure of the module algorithm allows us to formulate the input and output (i.e. precondition
and postcondition) for each lower level module called in it. Assuming the correctness of all called
modules (using the abstraction method), it is possible to prove the correctness of the main module.
Further, this process is repeated for all called modules of the second, then the third level, and
so on. In this way one can prove the correctness of all modules, even of a very large system. In
spite of extra efforts, carrying out the proof will eventually justify itself.
Machine Translated by Google
250 Lecture 16
It works because it allows you to design the system with fewer errors and makes it
much easier to test and debug the entire system due to potentially fewer remaining
errors.
In an analytical study, the complexity is most often derived for the worst case;
this allows us to assess in advance, even before testing the performance, whether
the algorithms used in the system can, in principle, satisfy users.
will work equally effectively, it is easy to make a mistake with planning the timing of
the completion of the project.
Secondly, if you add people to the development team while delaying the project,
then, as a rule, the deadline for completion of the work will be pushed back even
more: the new programmer needs time to understand the task and study the created
part of the project. At the same time, new performers will distract from the work of
those who have been involved in the work from the very beginning.
All this allowed F. Brooks to formulate a law that bears his name: “If you add
performers during the project implementation, then the final deadline for completing
the project can only increase.”
In order to reduce the negative effect of this law, it is necessary to immediately
plan longer periods for the implementation of the project than the performers
themselves estimate, and monitor the progress of the project in the process of work.
In addition, it is necessary to distribute the work among the performers in such a way
that in the event of the retirement of any of them there would be no significant
slowdown in the performance of work. When developing large projects that involve
large teams of people, a significant part of the effort is spent not directly on
programming, but on the interaction between project participants. Special studies
show that: “When the complexity of the system increases by n times, to create it in
the same time frame, it usually takes
2
n times more people.
So that each programmer could apply his abilities in a team with maximum
efficiency, F. Brooks, back in the late 1960s, suggested organizing teams of
programmers in the form of teams, in which the individual roles of each are described.
The team is formed around the chief programmer, who has the highest qualifications.
The basic principles of the organization of the brigade:
1) each member of the brigade has his own specialization and basic duties
tasks along with the current tasks received from the head;
2) any member of the team works in direct contact with one or two colleagues so
that even in the event of his departure, work on the project is not suspended.
The chief programmer makes major decisions when designing the system
architecture, creates the most critical modules in the system, and writes or supervises
the writing of documentation. In the brigade
Machine Translated by Google
252 Lecture 16
The wife will be his deputy, who, like the chief programmer, owns all the most essential information
on the project, and, if necessary, can replace him. In addition, some responsibilities are shared
among individual programmers in the team. The archivist is responsible for maintaining all copies of
written system components and documentation, and all copies must be updated regularly. The tool
maker is responsible for preparing and mastering the auxiliary software tools required by all other
members of the team. The tester is responsible for testing the system and its modules. The Literary
Editor is responsible for preparing the documentation.
When using top-down design technology, it is possible already at the first stages of development
to more or less evenly load the work of all members of the team in order to complete the project on
time. In general, the team multiplies the abilities of the main programmer, on whom the success of
the work depends to the greatest extent.
still have to redo, perhaps from the very beginning. Hence the conclusion: the first system should be
created in such a way that it would not be a pity to throw it away. Those. first it is advisable to create
a valid layout
a system in which the main functions are implemented, but in a simplified form with the simplest
variants of algorithms, etc. After the customer or user has studied the developed system, determines
what does not suit him in it, it is possible to develop a draft of the second version of the system.
stems.
"The second system (its 2nd version) has the effect of the second system." When creating the
second version of the system, it is easy to go to extremes and implement unnecessary functions in
the system that the user does not really need, make the system architecture excessively cumbersome
and clumsy, because of which it will again not suit the customer. Hence the conclusion: it makes no
sense to “bring to a shine” the second system, after its testing and testing, it is necessary to quickly
move on to creating 3-
1. Why is the labor costs of creating a complex software product an order of magnitude greater
than the labor costs of developing a simple program of the same size?
2. What are the goals and objectives of the main stages of system development?
3. What is the maintenance of the software product? What is vital
system cycle?
4. Which documents relate to operational documentation, and what information
should be in these documents?
5. Which documents are related to maintenance documentation, and what information
should be in these documents?
6. Implement the project of the program for calculating the determinant of a square matrix, described
in example 16.1. Perform downward testing of the program. Write operational and maintenance
documentation.
7. In which case is it advisable to combine the top-down design method with bottom-up design?
Literature
There are a vast number of books and textbooks on Pascal and C. The books of
the author of the language Pascal N. Wirth [6, 13] and the author of the C language
D. Ritchie [15] are of interest. The book [22] is devoted to the C++ language, which is
an object-oriented development of C. For practical work on a computer, books or
manuals for a specific translator, as well as appropriate software, are required. For
example, to work with the Free Pascal and Lazarus translators, you can use the
textbook [2], and to work with the C translator, you can use the textbook [20]. The site
[23] hosts the Lazarus translator, and the site [24] hosts the Dev C++ translator.
See the books [1, 6, 9, 10, 11] for the main ideas of proving algorithms. The
problems of programming technology are discussed in books [3, 4, 8, 14, 18], the site
[25] hosts the StarUML system for creating program projects in the UML language.
See [1, 6, 7] for recurrent sequences and algorithms. See [7, 17] for sorting and
searching algorithms. For recursive algorithms and backtracking, see [1, 21]. Context
search algorithms are available in [7, 17], and Graph Theory and Algorithms with
Graphs are in [12, 19, 21]. Computational algorithms of linear algebra can be found
in [5].
This book has been substantially revised and supplemented
textbook [16]. The book comes with a set of 16 presentations.
Literature 255
7. Wirth N. Algorithms + data structures = programs Per. from English. / Per. With
English – M.: Mir, 1985. 406 p.
8. Glass R. A Guide to Reliable Programming / Per. from English. – M.: Mir, 1982. 280 p.
9. Gris D. Science of programming / Per. from English. – M.: Mir, 1984. 416 p.
10.Dal W., Dijkstra E., Hoor K. Structural programming / Per. With
English – M.: Mir, 1975. 245 p.
11. Dijkstra E. Programming discipline / Per. from English. – M.: Mir,
1978. 275 p.
12. Zykov A.A. Fundamentals of graph theory. – M.: High school book. 2004. 664 p.
13. Jensen K., Wirth N. Pascal: User manual and description
language / Per. from English. - M.: Finance and statistics, 1982. 151 p.
14. Yodan E. Structural design and program design / Per. from English. – M.: Nauka, 1979.
410 p.
15. Kernigan B., Ritchie D. Programming language C / Per. from English. – M.: Finansy i
statistika, 1992. 272 p.
16. Kostyuk Yu.L. Basics of programming. Development and analysis of algorithms: a
tutorial. - Tomsk: Publishing House Vol. university 2006. 244 p.
17. Knut D. The Art of Computer Programming: In 3 vols. Vol. 3: Sorting and
search / Per. from English. – M.: Mir. 1978. 846 p.
18. Myers G. The art of software testing / Per. from English. - M.: Finance and statistics,
1982. 175 p.
19.Ore O. Graph Theory. 2nd ed. / Per. from English. – M.: Nauka, 1980. 336 p.
20. Podbelsky V.V., Fomin S.S. C Programming: Proc. allowance. - 2nd ed., add. – M.:
Finance and statistics, 1999. 600 p.
21. Reingold E., Nivergeld Yu., Deo N. Combinatorial algorithms. Theory and
practice / Per. from English. – M.: Mir, 1980. 476 p.
22. Stroustrup B. Programming language C++ / Per. from English. - M .: Radio and
connection, 1991. 352 p.
23.https://lazarus-rus.ru
24.https://soft.mydiv.net/win/download-DEV-C.html
25.https://freeanalog.ru/StarUML
Machine Translated by Google
Table of contents
Lecture 5 ........................... 76
5.1. Algorithms with lists ............................................................... ......................... 76
5.2. Search in lists............................................................... ............................................... 80
5.3. Sorting lists .................................................................. .............................. 83
Questions and tasks ............................................... ......................................... 86
Literature 257
Lecture 11. Algorithms of linear algebra. Vectors and Matrices ................. 173
11.1. Addition and multiplication of vectors and matrices.................................... 173
11.2. Solving systems of linear equations .............................................................. 178
Questions and tasks ............................................... ............................................... 183
258 Literature