0% found this document useful (0 votes)
11 views21 pages

New Doc1

The document is an assignment from Mizan-Tepi University focusing on data structures and algorithms, specifically discussing excessive recursion and backtracking techniques. It includes examples such as the Fibonacci numbers and the Tower of Hanoi, illustrating the inefficiencies of excessive recursion and the systematic approach of backtracking in problem-solving. Additionally, it covers common backtracking problems like the N-Queens Problem and Subset Sum, emphasizing the importance of efficient algorithm design.

Uploaded by

tegenefikadu91
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views21 pages

New Doc1

The document is an assignment from Mizan-Tepi University focusing on data structures and algorithms, specifically discussing excessive recursion and backtracking techniques. It includes examples such as the Fibonacci numbers and the Tower of Hanoi, illustrating the inefficiencies of excessive recursion and the systematic approach of backtracking in problem-solving. Additionally, it covers common backtracking problems like the N-Queens Problem and Subset Sum, emphasizing the importance of efficient algorithm design.

Uploaded by

tegenefikadu91
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 21

MIZAN -TEPI UNIVERSITY

COLLAGE OF ENGINNERING AND TECHNOLOGY

SCHOOL OF COMPUTING AND INFORMATICS

DEPARTEMENT OF SOFTWARE ENGINEERING

ASSIGNMENT OF DATA STRUCTURE AND ALGORITHIM

GROUP 4 MEMBER

NAME ID

1 DESSALEGN ASEMAMAW 4188/16

2 MEDAGA TAJU 4428/16

3 ABENEZER GETACHEW 4004/16

4 ENTEWACHEW WONDIMGEZAHU 6134/16

5 ASINAKECH GIBORE 4085/16

6 CHUOL WAL 4169/16

Submitted to MR. wubi

Submission data 22/07/2017 E.C


TABLE OF CONTENT
CONTENT PAGE
Introduction.................................................................................................................................................1

1. Excessive recursion..................................................................................................................................2

A The fibonacci numbers......................................................................................................................3

B The tower of hanoi...........................................................................................................................6

2. Backtracking............................................................................................................................................9

2.1. Introduction to Backtracking.......................................................................................................10

2.2. Common examples.....................................................................................................................10

1 N-Queens Problem..................................................................................................................11

2 Subset Sum..............................................................................................................................16

Reference...................................................................................................................................................18

I
List of figure
Content page

Figure 1 the tree of calls for fib(6).....................................................................................................5

Figure 2 Number of addition operation and number of recursive calls to calculate Fibonacci
numbers .............................................................................5

Figure 3 workflow of tower of Hanoi have 3 disk.............................................................................7

Figure 4 chess board of 8*8.............................................................................................................13

Figure 5 the tree chart of sum of subset...........................................................................................17

II
Introduction

Excessive recursion and backtracking, while powerful problem-solving techniques in data


structures and algorithms, can lead to inefficiencies, especially with large or complex problems,
potentially causing stack overflow errors or high time complexity. Recursion involves a function
calling itself to solve smaller instances of the same problem. While elegant for certain problems,
excessive recursion can lead to a large number of function calls, consuming significant memory
and time.Backtracking is a problem-solving technique that explores potential solutions
incrementally, abandoning a path (backtracking) as soon as it determines that it cannot lead to a
valid solution. Backtracking is a fundamental algorithmic technique used in computer science
and mathematics for solving problems that involve finding all possible solutions or searching for
the best solution among a large number of choices. It's especially useful for problems with
multiple decision points and constraints, where you need to explore various possibilities
systematically. The core idea behind backtracking is to build a solution incrementally, starting
with an empty or partial solution and extending it step by step. At each decision point, the
algorithm explores one option and proceeds deeper into the solution space

1
1. Excessive recursion

Recursion is a technique where a function calls itself to solve a problem by breaking it down into
smaller, self-similar sub-problems. Excessive recursion occurs when a recursive function calls
itself repeatedly without a proper base case or stopping condition, leading to a stack overflow
error.

Logical simplicity and readability are used as an argument supporting the use of recursion. The
price for using recursion is slowing down execution time and storing on the run-time stack more
things than required in a non recursive approach. If recursion is too deep (for example,
computing 5.6100,000), then we can run out of space on the stack and our program crashes. But
usually, the number of recursive calls is much smaller than 100,000, so the danger of
overflowing the stack may not be imminent.However, if some recursive function repeats the
computations for some parameters, the run time can be prohibitively long even for very simple
cases.A recursive method is excessively recursive if it repeats computations for some parameter
values.

Why is this excessive?


Redundant calculations: Each function call recalculates Fibonacci values multiple times.
Exponential time complexity: O(2^n), making it impractical for large n.
Risk of stack overflow: Too many recursive calls fill the call stack.
Benefits of Memorization
Avoids redundant calculations, reducing time complexity to O(n).
Prevents excessive recursion, making it more efficient.

2
A The fibonacci numbers

Consider Fibonacci numbers. A sequence of Fibonacci numbers is defined as follows:

Fib(n) = { n if n<2
Fib(n-2) + Fib(n-1) otherwise

The definition states that if the first two numbers are 0 and 1, then any number in the sequence is
the sum of its two predecessors. But these predecessors are in turn sums of their predecessors,
and so on, to the beginning of the sequence. The sequence produced by the definition is
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,...
How can this definition be implemented in C++? It takes almost term-by-term translation to have
a recursive version, which is:
unsigned int Fib (unsigned int n)
{
if (n < 2)
return n;
// else
return Fib(n-2) Fib(n-1);
}

The function is simple and easy to understand but extremely inefficient. To see it, compute Fib
(6), the seventh number of the sequence, which is 8. Based on the definition, the computation
runs as follows:
Even if we try to compute the value of 5.6100,000 using an iterative algorithm, we are not
completely free from a troublesome situation since the number is much too large to fit even a
variable of double length. Thus, although the program would not crash, the computed value
would be incorrect (why?), which may be even more dangerous than a program crash.

3
Fib(6)= fib(4) +fib(5)
= fib(2) + fib(3) +fib(5)
= fib(0) + fib(1) + fib(3) +fib(5)
= 0 + 1 + fib(3) +fib(5)
= 1 +fib(1) + fib(2) +fib(5)
= 1 +fib(1)+fib(0)+fib(1) +fib(5)
etc.

This is just the beginning of our calculation process, and even here there are certain shortcuts.
All these calculations can be expressed more concisely in the form of the tree shown in Figure 1.
Tremendous inefficiency results because Fib() is called 25 times to determine the seventh
element of the Fibonacci sequence. The source of this inefficiency is the repetition of the same
calculations because the system forgets what has already been calculated. For example, Fib() is
called eight times with parameter n = 1 to decide that I can be returned. For each number of the
sequence, the function computes all its predecessors without taking into account that it suffices
to do this only once. To find Fib(6) = 8, it computes Fib (5), Fib(4), Fib(3), Fib(2), Fib(1), and
Fib(0) first. To determine these values, Fib(4),..., Fib (0) have to be computed to know the value
of Fib (5). Independently of this, the chain of computations Fib(3)..... Fib(0) is executed to find
Fib(4).
We can prove that the number of additions required to find Fib(n) using a re-cursive definition is
equal to Fib(n + 1)-1. Counting two calls per one addition plus the very first call means that Fib()
is called * Fib(n + 1) - 1 times to compute Fib(n). This number can be exceedingly large for
fairly small us, as the table in Figure 2. indicates.
It takes almost a quarter of a million calls to find the twenty-sixth Fibonacci number, and nearly
3 million calls to determine the thirty-first! This is too heavy a price for the simplicity of the
recursive algorithm. As the number of calls and the run time grow exponentially with n. the
algorithm has to be abandoned except for very small numbers.

4
Figure 1 the tree of calls for fib(6)

n fib(n+1) number of addition number of calls


6 13 12 25
10 89 88 177
15 987 986 1973
20 10946 10945 21891
25 121393 121392 242785
30 1346269 1346268 2692537

Figure 2 Number of addition operation and number of recursive calls to calculate Fibonacci

numbers

5
Implementation of Fibonacci

unsigned int iterativeFib (unsigned int n) {


if (n < 2)
return n;
else {
register int i = 2 , tmp, current 1, last = 0;
for(;i<n; ++i) {
tmp = current;
current += last;
last = tmp;
}
return current;
}
}

B The tower of Hanoi

Tower of Hanoi is a mathematical puzzle where we have three rods (A, B, and C) and N disks.
Initially, all the disks are stacked in decreasing value of diameter i.e., the smallest disk is placed
on the top and they are on rod A. The objective of the puzzle is to move the entire stack to
another rod (here considered C), obeying the following simple rules:
Only one disk can be moved at a time.
Each move consists of taking the upper disk from one of the stacks and placing it on top of
another stack i.e. a disk can only be moved if it is the uppermost disk on a stack.
No disk may be placed on top of a smaller disk.
The idea is to use the helper node to reach the destination using recursion. Below is the pattern
for this problem:

6
Shift (N-1) disks from ‘A’ to ‘B’, using C.
Shift last disk from ‘A’ to ‘C’.
Shift( N-1) disks from ‘B’ to ‘C’, using A.
faq.disk3
Image illustration for 3 disks.

Figure 3 workflow of tower of Hanoi have 3 disk

7
The implementation of tower of Hanoi.

#include <bits/stdc++.h>
using namespace std;
void towerOfHanoi(int n, char from_rod, char to_rod,
char aux_rod)
{
if (n == 0) {
return;
}
towerOfHanoi(n - 1, from_rod, aux_rod, to_rod);
cout << "Move disk " << n << " from rod " << from_rod
<< " to rod " << to_rod << endl;
towerOfHanoi(n - 1, aux_rod, to_rod, from_rod);
}

// Driver code
int main()
{
int N = 3;

// A, B and C are names of rods


towerOfHanoi(N, 'A', 'C', 'B');
return 0;
}

8
2. Backtracking

Backtracking and recursive problem-solving are two fundamental techniques in computer


science and algorithm design. Backtracking is an algorithmic approach that systematically
explores different possibilities by incrementally building a solution and backtracking when a
partial solution is deemed invalid or not suitable. It is often used to solve problems with multiple
decision points or constraints, such as the Traveling Salesman Problem and Sudoku puzzles.
Backtracking is efficient because it prunes the search space by eliminating branches of the
exploration tree that cannot lead to a valid solution, thereby reducing computational complexity.
On the other hand, recursive problem-solving is a programming paradigm that involves solving a
complex problem by breaking it down into smaller, more manageable sub-problems of the same
type. Recursion is defined by a function that calls itself, gradually reducing the problem's size
until it reaches a base case, where a straightforward solution can be obtained. This technique is
particularly useful for problems that exhibit self-similarity or have a recursive structure, such as
binary tree traversal or calculating Fibonacci numbers. Recursive algorithms are elegant and
often easier to understand, but they can be less efficient if not carefully optimized. Both
backtracking and recursion are powerful tools in the problem-solving toolbox of computer
scientists and programmers. They allow for the exploration of vast solution spaces and enable the
efficient resolution of complex problems, making them essential techniques in various domains,
including artificial intelligence, algorithms, and combination optimization.

The choice between using backtracking or recursion depends on the problem's nature and
requirements, and skilled practitioners often combine these techniques to develop efficient and
elegant solutions to challenging computational problems.

9
2.1. Introduction to Backtracking

Backtracking is a fundamental algorithmic technique used in computer science and mathematics


for solving problems that involve finding all possible solutions or searching for the best solution
among a large number of choices. It's especially useful for problems with multiple decision
points and constraints, where you need to explore various possibilities systematically. The core
idea behind backtracking is to build a solution incrementally, starting with an empty or partial
solution and extending it step by step. At each decision point, the algorithm explores one option
and proceeds deeper into the solution space. If it encounters a situation where the current path
cannot lead to a valid solution, it "backtracks" by undoing the last decision and trying a different
path. This process continues until a valid solution is found or all possibilities have been
exhausted. Backtracking can be visualized as exploring a tree-like structure, often referred to as
a "search tree" or "state space tree." Each node in the tree represents a choice or decision, and the
edges between nodes represent the transitions from one decision to another. Backtracking
algorithms typically use recursion or an explicit stack to manage the exploration of the search
tree.

2.2. Common examples

Common examples of problems that can be solved using backtracking include:

1 N-Queens Problem: Placing N chess queens on an N×N chessboard so that no two queens
threaten each other. Sudoku: Filling a 9×9 grid with digits so that each column, each row, and
each of the nine 3×3 subgrids contain all of the digits from 1 to 9.

2 Subset Sum: Finding a subset of numbers from a given set that adds up to a specific target
sum. Backtracking is a powerful technique for solving complex, combinatorial problems, but it's
essential to design the algorithm carefully to avoid inefficient exploration of the search space.
Proper pruning techniques, such as constraint propagation and heuristics, can significantly
improve the efficiency of backtracking algorithms.

3 Combinatorial Optimization: Problems like the Traveling Salesman Problem (TSP), where
you find the shortest possible route that visits a given set of cities and returns to the origin city.

10
In summary, backtracking is a systematic approach to problem-solving that explores a decision
tree, making choices along the way and backtracking when necessary to find a valid solution or
determine that no solution exists. It's a versatile technique used in various fields, including
artificial intelligence, optimization, and puzzle-solving.

1 N-Queens Problem

Example The 8 queens problems.

The eight queens problem is based on chess. A chess board is an eight by eight grid of squares. A
queen is a piece that can attack another piece if and only if that piece lies in the same row or
column as the queen, or along either of the two diagonals through the queen's square. The Eight
Queens Problem asks for a set of eight squares on which to place eight queens in such a way that
none can attack any other.

There is a natural backtracking solution to this problem. Since there must be exactly one queen
in each column of the board, and exactly one queen in each row, every queen must be in its own
unique row and column. We arbitrarily use the columns of the board to organize the search.
Assume the columns are numbered 1 to 8. Try to think recursively now. Imagine that you have
placed queens on the board already and that the queens that have been placed so far cannot attack
each other. In other words, so far the queens on the board are a potential solution. Initially this is
true because no queens are on the board. You have been placing the queens on the board by
putting them in successive columns. Now suppose further that you have a means of checking, for
any given potential position in which you want to place the current queen, whether doing so
would put it under attack by one of the queens already on the board. The task at the moment is to
place the queen in the current column, so you try each row position in that column to see if it
leads to a solution. If there is a row that is safe in this column, then you place the queen and
recursively advance to the next column, trying to place the next queen there, unless of course you
just placed the 8th queen, in which case you found a solution. However, if there is no row in the
current column that is safe for the queen, then you have to backtrack you have to go back to the

11
queen you placed in the preceding column and try a different row for it, repeatedly if necessary,
until it is safe, applying this same recursive strategy there. If you backtrack to the very first
queen and cannot find a row for it, then there is no solution to this problem.

A classic combinatorial problem is to place 8 queens on a 8*8 chess board so that no two

attack, i.,e no two queens are to the same row, column or diagonal.

Now, we will solve 8 queens problem by using similar procedure adapted for 4 queens problem.

The algorithm of 8 queens problem can be obtained by placing n=8, in N queens algorithm.

If two queens are placed at positions (i,j) and (k,l). They are on the same diagonal only if

i-j=k-l ……………….(1)or

i+j=k+l .....................(2).

From (1) and (2) implies j-l=i-k and j-l=k-i

Two queens lie on the same diagonal iff |j-l|=|i-k|

The solution of 8 queens problem can be obtained similar to the solution of 4 queens.

problem.X1=3, X2=6, X3=2, X4=7, X5=1, X6=4, X7=8, X8=5,

The eight queens problem attempts to place eight queens on a chessboard in such a way that no
queen is attacking any other. The rules of chess say that a queen can take another piece if it lies
on the same row, on the same column, or on the same diagonal as the queen (see Figure 4). To
solve this problem, we try to put the first queen on the board, then the second so that it cannot
take the first, then the third so that it is not in conflict with the two already placed, and so on,
until all of the queens are placed.What happens if, for instance, the sixth queen cannot be placed
in a non-conflicting position?
We choose another position for the fifth queen and try again with the sixth. If this does not work
the fifth queen is moved again. If all the possible positions for the fifth queen have been tried, the
fourth queen is moved and then the process restarts. This process requires a great deal of effort,
most of which is spent backtracking to the first crossroads offering some untried avenues. In

12
terms of code, however, the process is rather simple due to the power of recursion which is a
natural implementation of backtracking. Pseudo code for this backtracking algorithm is as
follows (the last line pertains to backtracking):

Figure 4 chess board of 8*8

The 8 queens problem implementation

class ChessBoard {

public:

ChessBoard();//8 x 8 chessboard;

Chess Board(int); // n x n chessboard;

void findSolutions();

private:const bool available;

const int squares, norm;

bool *column,* leftDiagonal, *rightDiagonal;

int *positionInRow, howMany;

void putQueen(int);

void printBoard (ostream&);

void initializeBoard();

};

13
ChessBoard:: ChessBoard() available(true), squares(8), norm(squares-1)

initializeBoard();

ChessBoard:: ChessBoard(int n) available(true), squares (n),

norm(squares-1) {

initializeBoard();

void ChessBoard:: initializeBoard() {

register int i;

column new bool [squares];

positionInRow = new int[squares];

leftDiagonal = new bool [squares*2- 1];

rightDiagonal new bool [squares*2- 1];

for (i=0; i < squares; i++)

positionInRow[i] = -1;

for (i=0; i < squares; i++)

column[i] = available;

for (i = 0; i < squares*2-1; i++)

leftDiagonal[i] = rightDiagonal[i] = available;

howMany = 0;

void ChessBoard:: put Queen (int row) {

for (int col = 0; col< squares; col++)

if (column[col] == available &&

14
leftDiagonal [row+col] == available &&

rightDiagonal[row-col+norm] == available) {

positionInRow[row] = col;

column[col] =!available;

leftDiagonal[row+col] = !available;

rightDiagonal [row-col+norm] = !available;

if (row squares-1)

putQueen (row+1);

else printBoard(cout);

column[col] = available;

leftDiagonal [row+col] =available;

rightDiagonal[row-col+norm]= available;

void ChessBoard:: findSolutions() {

putQueen(0);

cout << howMany << solutions found.\n";

15
2 Subset Sum

Example 1: The Sum of Four Squares

La Grange's 4-squares theorem states that any natural number can be written as the sum of four
squares (including 0 if need be.) Suppose we wanted an algorithm that, given any natural
number, could find four squares whose sum equals the number. Backtracking can do this. The
idea is to pick a square less than the number, subtract it, and then find three numbers that add up
to the difference. If we succeed, then we found the four numbers. If we do not, then we back up
to the first number we picked and try a different first. number. We can proceed by picking the
smallest first number first, or by picking the largest first number first. Either way we can proceed
methodically. The algorithm below picks the smallest number first.

Steps:

1. Start with an empty set

2. Add the next element from the list to the set

3. If the subset is having sum M, then stop with that subset as solution.

4. If the subset is not feasible or if we have reached the end of the set, then backtrack through the

subset until we find the most suitable value.

5. If the subset is feasible (sum of subset < d) then go to step 2.

6. If we have visited all the elements without finding a suitable subset and if no backtracking is

possible then stop without solution.

16
Example: S = {3,5,6,7} and d = 15, Find the sum of subsets by using backtracking

Figure 5 the tree chart of sum of subset

17
Reference
A. Drozdek, Data Structures and Algorithms in C++ (2nd ed.). Cengage Learning, 2013. Boston,
MA, USA.page(189-199).

Carmen, T.H., Leiserson, C.E., Rivest, R.L., & Stein, C. (2009). Introduction to Algorithms (3rd
ed. ed.). MIT Press.

Sedgewick, R., & Wayne, K. (2011). Algorithms (4th ed.). Addison-Wesley Professional.

Tanenbaum A. S. Augenstein M. J. (1986). Data Structures Using C. Upper Saddle River, New
Jersey: Prentice Hall.

18

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy