Homework Solution

Amortization, Linked Lists

Problems to be Submitted (20 points)

  1. (10 points)
    /* Insert an object at the front of the deque. */
    template <typename Object>
    void AltLinkedDeque<Object>::push_front(const Object& e) {
        Node* v = new Node(e, NULL, head);
        if (head == NULL)
            tail = v;
        else
            head->prev = v;
        head = v;
        n++;
    }
    
    /* Remove the back object from the deque. */
    template <typename Object>
    void AltLinkedDeque<Object>::pop_back()  {
        if (empty()) throw std::runtime_error("popping from empty deque");
    
        Node* old = tail;
        tail = tail->prev;
        delete old;
        n--;
    
        // the following are for good measure for internal consistency
        // (although technically not required for proper functioning)
        if (tail != NULL)
            tail->next = NULL;
        else
            head = NULL;
    }
    
  2. (10 points)

    Queue operation Paid to Stack implementor
    (worst-case cost)
    Price List
    (paid to us)
    Queue.size() 2 2
    Queue.empty() 2 2
    Queue.push() 1 4
    transfer loop
    triggered
    transfer loop
    NOT triggered
    Queue.pop() 3 + 3|S1| 2 3
    Queue.front() 3 + 3|S1| 2 3

    Our claim is that we can keep a bank account which is guaranteed to hold $3 in reserve for each element currently stored in stack S1 of our structure.

    The operations size() and isEmpty() do not alter our structure, and to pay for these operations, we charge the customer a price exactly equal to our worst-case expenditures. An examination of the source code shows that the only way in which items can be added onto stack S1 is from within the push() method. We have set a price of $4 for this method, even though our expenditure is always $1. In this way, we are sure to have an extra $3 per item on S1 which we can keep in the bank.

    We analyze pop() and front() by case analysis. When stack S2 is non-empty, our expenditure is exactly $2, and this can be funded from the $3 price we charge our customer (the profit can be thrown away here).

    In the case when S2 is empty, we invoke transferItems. This includes one initial call to S1.size() and the for loop of the transferItems code, which moves all current items from S1 onto S2. This loop has an expenditure of exactly $(3|S1|), as the loop body involves 3 stack methods per iteration. The $3 savings-per-item-of-S1 can pay for this loop, with the $3 collected directly from the customer to pay for the overhead of the call to size and the calls to S2.empty and S2.pop (resp. S2.top) from within the call for queue::pop (resp. queue::top). Although we spend all of our savings, all items have been removed from S1 during this process, so we can still maintain our guarantee of having savings of $3 per item on S1.


Last modified: Monday, 10 March 2014