Algorithms & Data structures, Exercises of Data Structures and Algorithms

This document presents a number of modules, each containing a coherent set of questions and exercises. Pick any module you deem interesting!

Typology: Exercises

2022/2023

Uploaded on 03/01/2023

shahid_88c
shahid_88c 🇺🇸

4.4

(26)

261 documents

1 / 15

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Algorithms & Data structures
Tutorial
L.J. Bel
7 March 2018
Introduction
This document presents a number of modules, each containing a coherent
set of questions and exercises. Pick any module you deem interesting! If
you don’t like it, or it’s too easy or too difficult, just switch to another.
Each module has a difficulty rating, from 1 (easy) to 3 (difficult) stars. This
difficulty is based on my estimate of how much experience one has with
algorithms (and computer science in general). Each module also indicates the
language used. The code can be found here: github.com/lbel/icsc2018.
To run the software you need at least the following:
Python Python 2.7, 3.4 or newer. You can find an installa-
tion of Python 2.7.5 on CentOS 7 at lxplus7.cern.ch, under
/usr/bin/python.
C++ A C++ compiler supporting C++11, such as GCC 4.8 or newer. You
can find an installation of GCC 4.8.5 on CentOS 7 at lxplus7.cern.ch,
under /usr/bin/g++. This should be referenced automatically by the
Makefiles.
Java JDK version 1.8 or newer. This is also installed on lxplus7, and will
be picked up by the scripts.
1
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff

Partial preview of the text

Download Algorithms & Data structures and more Exercises Data Structures and Algorithms in PDF only on Docsity!

Algorithms & Data structures

Tutorial

L.J. Bel

7 March 2018

Introduction

This document presents a number of modules, each containing a coherent set of questions and exercises. Pick any module you deem interesting! If you don’t like it, or it’s too easy or too difficult, just switch to another. Each module has a difficulty rating, from 1 (easy) to 3 (difficult) stars. This difficulty is based on my estimate of how much experience one has with algorithms (and computer science in general). Each module also indicates the language used. The code can be found here: github.com/lbel/icsc2018. To run the software you need at least the following:

Python Python 2.7, 3.4 or newer. You can find an installa- tion of Python 2.7.5 on CentOS 7 at lxplus7.cern.ch, under /usr/bin/python.

C++ A C++ compiler supporting C++11, such as GCC 4.8 or newer. You can find an installation of GCC 4.8.5 on CentOS 7 at lxplus7.cern.ch, under /usr/bin/g++. This should be referenced automatically by the Makefiles.

Java JDK version 1.8 or newer. This is also installed on lxplus7, and will be picked up by the scripts.

Contents

  • 1 ∗ Breadth-first and depth-first search
  • 2 ∗ Java collections (Java)
  • 3 ∗ Recursion and stack overflow (Python)
  • 4 ∗∗ Bloom filters (Python)
  • 5 ∗∗ Dijkstra’s algorithm (Python)
  • 6 ∗ ∗ ∗ Linked lists (C++)

BFS is very similar to DFS, except it exhausts all the children of the current node before moving on to their children. Another way to see it is that it traverses a tree level-by-level (from left to right in the ASCII visualisation provided by the script).

Exercises

  1. Open the file bfs.py.
  2. Flesh out the Queue implementation, again using a Python list and as many built-in methods as you can find.
  3. Complete the BFS implementation. Note that it’s very similar to DFS!
  4. Again, check your implementations by running the script.
  5. Run the larger example (example3) by uncommenting the last line (and removing the one above it) in tree.py, both for DFS and BFS. Does it work?

2 ∗ Java collections (Java)

Java has very good out-of-the-box support for all the data structures dis- cussed in the lectures. In this exercise, you will verify their complex- ity by running large numbers of operations on them. We’ll be using the java.util.Collection interface, which is an interface common to all java collections. The advantage of this is that it supports similar operations through the same interface. For example, adding an object to a set and pushing an object to the back of an array both use the same method add.

3 ∗ Recursion and stack overflow (Python)

Recursive implementations can simplify many algorithms, such as the im- plementation of the Fibonacci sequence given in recursion/recursion.py. This script takes n as an argument and outputs the nth^ Fibonacci number. The recursion lies in the fact that the method fib repeatedly calls itself. This module is about inefficiencies and stack overflows (no, not the website).

Exercises

  1. Run the example. Does it give the right answer?
  2. Increase n. What do you observe?
  3. What is the complexity of this implementation?
  4. Of which concept, presented in the lectures, is this implemen- tation an example?

This implementation is rather terrible. We can speed it up a lot by using a cache.

Exercises

  1. Modify the code by adding a global cache and storing each answer in that cache after calculating.
  2. If a cached answer is available, just use it instead of recalculat- ing the result!
  3. Make sure your code works up to at least n = 500.
  4. Now try running with n = 1000. What happens?

When running code, the computer keeps track of all the called methods, so that it knows how to proceed once the current method returns. This is

done in a buffer with a fixed size. That size is large enough that normally this causes no problems, but if we go very deep – as a recursive algorithm very well may – it is definitely possible to hit the limit. Let’s fix the code!

Exercises

  1. Replace the method fib with one that doesn’t rely on recursion (ie., doesn’t call itself).
  2. Make sure it runs reasonably fast, even for n > 1000.
  3. Yup, that’s all – good luck!

You can find a cached implementation of the recursive algorithm in recursion/recursion_cache.py, and a solution of the final exercise in recursion/recursion_solution.py.

Exercises

  1. Write the missing bodies for the add and contains methods. You may use the methods __get_bit and __set_bit. Note that self.__hashes is a list of functions!
  2. Run the script. Do you get many false positives? And false negatives?
  3. Increase m. Does this help reduce the number of false positives?
  4. Add some hash functions to self.__hashes. What are good choices to prevent overlap with existing hash functions?

An example implementation with decent (but not perfect) performance can be found in bloom/bloom_solution.py.

5 ∗∗ Dijkstra’s algorithm (Python)

In this module, you will implement Dijkstra’s algorithm. A framework containing a Graph data structure and several test cases can be found in dijkstra/dijkstra.py. Everything below the method called dijkstra are test cases. The first is trivial, and the second is the one presented in the lectures.

Questions

  1. Try to understand the structure of the three classes near the beginning of the file.
  2. Look at the first two test cases, and see if you can map the nodes (vertices) and edges of the second test case to those in the lectures.

Next, let’s implement the actual algorithm! A skeleton implementation has been set up in the method dijkstra.

6 ∗ ∗ ∗ Linked lists (C++)

Linked lists were presented in the lectures as an alternative to array-based se- quential containers. This exercise explores some of their properties, strengths and weaknesses. The code relies heavily on C++14 features – don’t hesitate to ask if you have any questions about that! The folder linked_list contains two source files: linked_list.h fea- tures an almost compelete (singly-)linked list implementation, and main.cxx has some code to test it. There’s also a small shell script to compile the code.

Exercises

  1. Run ./compile to compile the code, then try running the code with ./main. You should see some arrays of numbers printed.
  2. The program prints the time in ms spent to allocate elements to a linked_list and an std::vector. Which one is faster?
  3. Look at main.cxx. You can pass it a number as an argument to insert a different number of elements (the default is 10). Run it again with a larger number of elements. At what point does the performance of the vector overtake that of the linked list? (Comment the call to print_all to see all the output.)

Now look at the linked list implementation. It features a lot of methods that coincide with the definitions of std::vector, including support for iter- ation (which is already used in the program to print the elements). However, there is a lot of duplicate and inefficient code.

Exercises

  1. Copy linked_list.h to linked_list_original.h to preserve its original contents.
  2. The current implementation of the size method is far less than optimal. Can you rewrite it so that it runs in O(1)? You can (and should) change other parts of the class!
  3. Add a reference to the last element of the linked list, and modify the back method to run in O(1) by using it. Do you need to update any of the modifier methods (push_front, push_back, pop_front, and pop_back) to keep the reference up-to-date.
  4. Modify push_back to use the field as well, then do the same with pop_back.
  5. How much faster does your code run compared to the original file? You can easily check by including the original file rather than the modified one in main.cxx. And how does your per- formance compare to that of linked_list_solution.h? And to the STL implementation (linked_list_std.h)?