Classroom practice, week 1: Algorithms

Zsolt Kohári · 2019.09.10.

Introduction to programming and algorithms. The description of some basic algorithms with flowcharts and pseudo-code.

This is the first classroom practice of the semester. The aim of the practice is to provide an introduction to the logic of programing. We are going to cover some very basic, widely known algorithms. The task is to describe them in a formal way, and to convert them to a sequence of instructions.

We are going to describe the algorithms in English, by pseudo-codes. In a pseudo-code the steps of the algorithm are numbered. Numbering the lines enables us to refer to them later (like "jump to step n."), making iterative algorithms possible. The programs can be descibed by flow-charts as well, in which the lines and arrows define the order of execution of the operations.

1. Printing subsequent numbers

The first task is a basic, but very important one. Let us create an algorithm to print numbers below each other, from 1 to 10!. The solution should be precise, it should contain all the necessary steps.

How can we describe repetitive steps?

Supplement the pseudo-code with arrows following the sequence of execution!

Solution

The idea is as follows:

Let's print 1.
Let's print 2.
Let's print 3.
…
Let's print 10.

Observe that this solution is not precise enough. There a slight detail that has not been taken into account: each number should appear in a new line. A more precise solution is:

Let's print 1. I don't write anything into this line anymore.
Let's print 2. I don't write anything into this line anymore.
…
Let's print 10. I don't write anything into this line anymore.

Note that these are simple, repetitve steps, that are almost identical. The only difference between the instructions in the number to be written to the screen. Hence, we can put together a more general solution:

Let's consider number 1.
Print the number number to the screen. Start a new line.
Let's increment our number by one.
Print the number number to the screen. Start a new line.
Let's increment our number by one.
Print the number number to the screen. Start a new line.
Let's increment our number by one.
…

Describing this algorithm by pseudo-code leads to:

   1. Let's consider number 1.
   ↓
┌> 2. Print the number number to the screen. Start a new line.
│  ↓
│  3. Let's increment the number by one.
│  ↓
└─ 4. If the number is ≤ 10, go back to step 2
   ↓
   5. End.

Let us now transform the solution further. This time we aim to get a structured solution, that does not have line numbers, the control flow is reflected by the structure of the program itself.

Solution

   Let's consider number 1.
   ↓
┌> Repeat the following operations:
│    ↓
│    Print the number number to the screen. Start a new line.
│    ↓
│    Let's increment the number by one.
│    ↓
└─── Repeat again, if the number is ≤ 10, otherwise go on to the next line.
   ↓
   End.

Let us introduce variable names and transform the repetition used in the previous solution to a proper loop. What we get is very close to a C program.

Solution

   X = 1
   ↓
┌> While X ≤ 10, repeat:
│    ↓
│    Print X to the screen. Start a new line.
│    ↓
│    X = X+1
│    ↓
└─── End of repeatition.
   ↓
   End.

Let us write a program that prints only the even numbers (between 1 and 10)! Do we need to test whether X is even or odd? How to solve this task with testing and how to solve it without this testing step?

Solution

Testing is not required, it is enough to start the loop from 2 and increment the variable by 2 in each iteration.

Write a program to print all numbers from 1 to 100 that are divisible by 3 but are not divisible by 5.

Solution

In this case we have no choice, we need to go one-by-one and test all numbers whether they satisfy the criteria individually. We introduce conditional branches:

   X = 1
   ↓
┌> While X < 100, repeat:
│    ↓
│    If X is divisible by 3, and it is not divisible by 5, then:
│        ↓
│        Print X. Start a new line.
│    ↓
│    X = X+1
│    ↓
└─── End of repetition.
   ↓
   End.

2. Adding up two numbers

 239

+124
────
 363

Everybody has learnt in elementary school how to add two (potentialy big) numbers together. This is probably the first algorithm that is taught to every child. By this algorithm, the complex task is reduced to a more elementary one, to the addition of numbers smaller than 10. Hence, the problem is broken down to elementary steps. We can consider the addition of single-digit numbers elementary enough, since we can perform it instantly without any aid.

Let us describe this algorithm in a formal way! Let us use arrows again to indicate the order of execution of the steps in the program!

Solution

We start at the least significant decimal digit. We add the two digits, and write down the last digit of the sum (between 0 and 9). If the result is greater than 10, we keep the first digit (that is 1, called carry) in mind, since we have to take it into consideration in the next step of the algorithm. These steps need to be repeated as long as we have further digits to add.

To obtain the next digit of the solution and the carry digit, we need to obtain the integer part and remainder part of the division by 10. If the sum of the digits is 13, the integer part of 13/10 is 1 (this will be the carry digit), and the remainder of the division is 3 (giving the next digit of the solution).

   1. Start with the least significant decimal digit
   ↓
┌> 2. Add up the digits below each other
│  ↓
│  3. If there is one, add up the carry digit from the previous iteration as well.
│  ↓
│  4. Divide it by 10, write down the remainder below the line.
│  ↓
│  5. If we have a carry (the integer part of the division), keep it in mind.
│  ↓
└─ 6. Move to a more significant position, If we still have digits (local values) left, jump back to step 2.

Adding up two numbers - fix

The solution above in not perfect. What is missing, in which case does it give a wrong result?

 999

+  1
────
   ?

Let us follow (by hand) the behavior of our algorithm with this input.

How can be extend the algorithm to provide the correct solution for this input as well?

3. Prime factorization algorithm

Write a program to perform and print the prime factorization of an integer number!

Provide the pseudo-code (as before) and indicate the order of execution by arrows!

Solution

This is again an algorithm that is thaught in elementary school.

Let us review the algorithm through an example, number 120. We have to divide this number by primes, starting with 2 (that is the smallest prime number). If our number is divisible by 2 (without remainder), then we write down the prime (120|2 ), and actually perform the division on the number. If it is not divisible, then we try to divide it by the next prime number, till we find a proper prime divisor. These steps are repeated till our number, as the result of the subsequent divisions, reduces to 1.

Two small details need to be discussed before writing down the program. First of all, the next prime divisor is taken only when the division with the current one was not possible, hence, the number can potentially be divided by the same prime factor many times. Next, we don't have to restrict ourselves to prime divisors. In our example, we have to divide 120 by 2 three times (resulting 120/2/2/2=15), then by 3 once (giving 15/3=5), and then we can go on and try to divide it by 4 even if it is not a prime, since the division is going to fail anyway (as we divided by 2 as many times as we could). This observation simplifies the solution siginficantly.

   1. Ask the user for a number subject to prime factorization.
   ↓
   2. The smallest divisor to try is 2.
   ↓
┌> 3. Check if the number can be divided by the divisor without remainder.
│     ├─> If yes, then print: number | divisor; and perform the division.
│     └─> If not,  then try the next divisor.
│  ↓
└─ 4. While we do not reach 1, do again from line 3.
   ↓
   5. Print 1|.
120│2
 60│2
 30│2
 15│3
  5│5
  1│

It is possible to put together another solution as well, which is clearly visible from the example above. We first divided by 2, then again by 2, again and again till it was possible. In case of failure we can increment the divisor by one.

While this solution is essentially different from the previous one, still it provides the same output. Having very different solutions to the same problem is typical in programming.

      1. Ask the user for a number subject to prime factorization.
      ↓
      2. The smallest divisor to try is 2.
      ↓
┌> ┌> 3. If the number can be divided by the divisor,
│  │       print: number | divisor; and perform the division.
│  └──── Try again: if it was divisible, repeat line 3.
│     ↓
│     4. Increment the divisor by 1.
│     ↓
└──── 5. While we do not reach 1, do again from line 3.
      ↓
      6. Print 1|.

4. Flow-charts

The flow-chart depicts the various operations with rectangles and other geometric shapes, as demonstrated below.

Draw the flow-charts for the two solutions of the prime factoring program!

5. Further tasks to practice

  • Create a program to test a number whether it is prime.
  • Write a program to test if a sequence of numbers is monotonously increasing.
  • Provide the algorithm for multiplying two numbers, as learnt in the elementary school:
      123×24
      ──────
      492
    
    +246
    ─────
     2952