Assignments | Course Home | Documentation | Lab Hours/Tutoring | Schedule | Submit

Saint Louis University

Computer Science 2100
Data Structures

Michael Goldwasser

Fall 2015

Dept. of Math & Computer Science

Homework Assignment 05

Amortization, Linked Lists

Contents:


Overview

Topic: Amortizations, Linked Lists
Related Reading: Ch. 5.3 and 6.1
Due: Friday, 23 October 2015, 10:00am


Collaboration Policy

For this assignment, you must work individually.

Please make sure you adhere to the policies on academic integrity in this regard.


Problems to be Submitted (20 points)

  1. (10 points)

    When using a doubly linked list to implement the Deque ADT, we relied on the use of a header and trailer sentinel nodes, claiming that this made the rest of our implementation cleaner by removing the need for special cases.

    In this problem, we explore a potential implementation of an AltLinkedDeque class without the use of any sentinels. Instead, the class will explicitly maintain two Node* pointers, head and tail, which should reference the first and last nodes of the list, respectively, and which should be NULL when the list does not have any nodes. While maintaining such a convention, you are to:

    1. Provide a working implementation of the push_front method.

    2. Provide a working implementation of the pop_back method.

    As a starting point, we provide the nearly complete AltLinkedDeque class as a PDF handout. Your solution should be consistent with this code, and you should make sure to consider special cases, such as when working with an empty list.

    As a "homework" you are not required to formally implement the code on a computer. However, if you prefer to do so, in order to compile and test your solution, our starting files are available as AltLinkedDeque.h and AltLinkedDeque.tcc. We'll even help you out by providing the following simple test driver: Test_AltLinkedDeque.cpp.

  2. (10 points)

    In the solutions for an earlier homework, we gave a method for implementing a queue with the use of two stack data structures. Although this method was relatively simple to understand, it was not very efficient. This is true both in terms of worst-case analysis and amortized analysis.

    Here, we present an alternative solution. Whereas the original solution used stack S2 only temporarily to hold objects, this new method uses both stacks S1 and S2 for storing objects. Although you are not required to argue the correctness of this new method, you will certainly need to understand how and why it works to complete this assignment.

    template <typename Object>
    class queue {
    public:
      int size() const { return S1.size() + S2.size();  }
    
      bool empty() const { return S1.empty() && S2.empty();  }
    
      void push(const Object& item) { S1.push(obj); }
    
      void pop()  {
        if (S2.empty())
          transferItems();
        S2.pop();
      }
    
      Object& front() {
        if (S2.empty())
          transferItems();
        return(S2.top());
      }
    
    private:
      // Do not use any data members other than the following two stacks
      std::stack<Object> S1;
      std::stack<Object> S2;
    
      void transferItems() {
        int s = S1.size();
        for (int i=0; i<s; i++) {
          S2.push(S1.top());
          S1.pop();
        }
      }
    };

    For the new implementation, the worst-case time per operation is not guaranteed to be O(1). However, it can be shown that each operation requires only O(1) amortized time. Your job is to prove this amortized bound using the accounting method described in Ch. 6.1.3 of the text. Specifically, you should imagine yourself in the role of the queue implementor. The person who has implemented the stack has demanded that you pay $1 cyber-dollar every time your code calls one of the stack methods.


Michael Goldwasser
CSCI 2100, Fall 2015
Last modified: Tuesday, 13 October 2015
Assignments | Course Home | Documentation | Lab Hours/Tutoring | Schedule | Submit