NivaarExam PrepOfficial exam papers ↗

25-Comp-A4 Program Design and Data Structures · December 2016

Question 7 of 9: Pointer-Based Data Structures — Linked-List Queue

Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)

Notes on this paper

Paper format. 98-Comp-A4 Program Design and Data Structures, December 2016 — 3 hours, closed book, no calculator permitted. Nine questions of equal weight (20 marks each: 1, 2 and 9 split as (a) 10 + (b) 10); candidates answer any six, so a complete paper is 120 marks. Pseudocode or any high-level language is accepted, and the examiner's note states explicitly that marking emphasises the operation of the program, not syntactic details. All nine questions are answered below, because the whole set is the more useful revision resource. Answers are given in C or C++ as the question dictates; each is compilable as written (or corrected where the printed paper itself has a slip), but a clear, correctly reasoned pseudocode answer would earn the same marks.

Reference texts for this subject.

  • Cormen, Leiserson, Rivest & Stein, Introduction to Algorithms, 4th ed. — tree traversals and BSTs (ch. 12), sorting (ch. 2, 7), asymptotic analysis (ch. 3).
  • Weiss, Data Structures and Algorithm Analysis in C, 2nd ed. — linked lists and queues (ch. 3), binary search trees (ch. 4).
  • Deitel & Deitel, C++ How to Program, 10th ed. — class design and templates (ch. 9–12), file streams (ch. 14), operator overloading (ch. 11).
  • Kernighan & Ritchie, The C Programming Language, 2nd ed. — character/array I/O idioms (ch. 1, 7), pointers, structures and linked lists (ch. 5–6).
  • Stroustrup, The C++ Programming Language, 4th ed. — class templates and value semantics (ch. 3, 25–27).

The Computer Engineering citation list is built around architecture and networking texts (Patterson & Hennessy, Tanenbaum, Mano); this subject is programming and data structures, so the works above are cited instead.

Question 7: Pointer-Based Data Structures — Linked-List Queue (20 marks)

Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.

Check: the printed declaration has two defects of the anonymous-typedef struct kind: (1) typedef struct {...node *next;...} node; uses the name node for the pointer field before the typedef that introduces it has finished — this does not compile in C, and is corrected below to a tagged struct node {...struct node *next;...};. (2) the paper closes the header guard as #end if (two words), which no preprocessor accepts; it is corrected to #endif below. (The guard's opening #ifndef QUEUE_H / #define QUEUE_H is printed correctly on the paper — only the closing directive is split.) Also, a single top pointer (naming that suggests a stack, not a queue) would force an $O(n)$ traversal to find the rear on every enqueue; the implementation below adds a second rear pointer so enqueue and dequeue are both $O(1)$, which is what "insertion at the rear, deletion at the head" implies a queue module should provide.

Given. A queue ADT with four operations (make_empty, is_empty, enqueue, dequeue) to be backed by a singly linked list.

Find. A working implementation of all four operations, each $O(1)$.

Approach. Keep two pointers, front (head, the next element to dequeue) and rear (tail, where the next enqueued element is linked in); enqueue appends after rear, dequeue removes and frees front.

  1. Write the corrected header, queue.h.
    #ifndef QUEUE_H
    #define QUEUE_H
    
    struct node {
        int data;
        struct node *next;
    };
    
    void make_empty(void);
    int  is_empty(void);
    void enqueue(int i);
    int  dequeue(void);
    
    #endif
  2. Write the implementation, queue.c.
    #include <stdio.h>
    #include <stdlib.h>
    #include "queue.h"
    
    static struct node *front = NULL;   /* head: next to dequeue */
    static struct node *rear  = NULL;   /* tail: last enqueued   */
    
    void make_empty(void) {
        while (!is_empty()) dequeue();
    }
    
    int is_empty(void) {
        return front == NULL;
    }
    
    void enqueue(int i) {
        struct node *n = (struct node *)malloc(sizeof(struct node));
        n->data = i;
        n->next = NULL;
        if (rear == NULL) {              /* queue was empty */
            front = rear = n;
        } else {
            rear->next = n;
            rear = n;
        }
    }
    
    int dequeue(void) {
        struct node *old;
        int value;
        if (is_empty()) {
            fprintf(stderr, "Error: dequeue from empty queue\n");
            exit(1);
        }
        value = front->data;
        old = front;
        front = front->next;
        if (front == NULL) rear = NULL;   /* queue just became empty */
        free(old);
        return value;
    }
  3. Trace enqueue(1), enqueue(2), enqueue(3), dequeue(), dequeue() to confirm FIFO order. After the three enqueues the list is $\text{front}\to1\to2\to3\leftarrow\text{rear}$. The first dequeue() returns 1 and advances front to the node holding 2; the second returns 2 and advances front to the node holding 3 — elements come out in the same order they went in, which is exactly the FIFO behaviour a queue (as opposed to a stack) requires. $$\boxed{\text{dequeue order for enqueue}(1,2,3) = 1,\,2,\,(3\text{ remains})}$$
Question 7 — results
Operation sequenceOutput / state
enqueue(1); enqueue(2); enqueue(3)front→1→2→3←rear
dequeue()returns 1
dequeue()returns 2
Time complexity, both operations$O(1)$ (front & rear pointers)