Evanalysis
1.1Source-backedEmbedded interactionEstimated reading time: 3 min

1.1 ADT operations: stack, queue, and function pointers

Specify operation contracts first, then track exactly how stack/queue operations change state and how function pointers dispatch those operations in C.

Note collections

CSCI2520: Data structures

Structured notes for CSCI2520 data-structure foundations with operation-level reasoning and selective interactive demonstrations.

Chapter 1

ADT and operation semantics

From ADT contracts to operation behavior in stack/queue implementations.

Chapter 2

Complexity and sorting

Asymptotic growth, cost comparison, and sorting-oriented complexity reasoning.

Why start from ADT contracts

In data structures, implementation details are secondary to operation contracts. An ADT (Abstract Data Type) defines the legal operations, the state guarantees, and the error cases before we commit to arrays, linked lists, or any specific layout.

Stack ADT: operation semantics

Definition

Stack ADT core operations

For a stack SS:

  • push(x): insert x on top,
  • pop(): remove and return top element,
  • top(): return top element without removing,
  • isEmpty(): return whether SS is empty.

LIFO is not a slogan. It is an invariant: if a is pushed before b, then b must be popped before a unless removed by error handling.

Worked example

State trace for push/pop/top

Start with empty stack.

  1. push(10) -> [10]
  2. push(20) -> [10,20] (top is 20)
  3. top() returns 20, state unchanged
  4. pop() returns 20, state becomes [10]

Queue ADT: operation semantics

Definition

Queue ADT core operations

For a queue QQ:

  • enqueue(x): insert x at rear,
  • dequeue(): remove and return front element,
  • front(): inspect front without removal,
  • isEmpty(): return whether QQ is empty.

Queue invariant is FIFO: earlier inserted item exits earlier.

Worked example

State trace for enqueue/dequeue

Start with empty queue.

  1. enqueue(3) -> [3]
  2. enqueue(5) -> [3,5]
  3. dequeue() returns 3, queue becomes [5]
  4. front() returns 5, state unchanged

Function-pointer dispatch in C

When implementing ADT operations in C, we often store function pointers in an operation table so code can switch behavior by structure type without rewriting call sites.

Theorem

Interface consistency via function pointers

If every implementation of an ADT exposes the same function-pointer signatures, client code can remain stable while underlying structures vary.

This is effectively manual polymorphism in C.

Read and try

Trace ADT operation semantics

The stepper shows operation-by-operation state transitions so ADT contracts can be checked directly.

Row operation: push(10)

stack: [10]

queue: []

Top now points to 10.

Common mistakes

Common mistake

Mixing stack and queue invariants

Using enqueue/dequeue names but applying LIFO behavior (or vice versa) breaks ADT contracts even if code compiles.

Common mistake

Ignoring empty-structure preconditions

pop and dequeue on empty structures need explicit error policy (status code, exception-like return, or sentinel with validity flag).

Quick checks

Quick check

After push(1), push(2), pop(), what remains in the stack?

Apply LIFO strictly.

Solution

Answer

Quick check

After enqueue(4), enqueue(7), dequeue(), which element is returned?

Apply FIFO strictly.

Solution

Answer

Exercises

Quick check

Design precondition/postcondition for stack pop().

Write one valid contract in words.

Solution

Guided solution

Quick check

Explain in one paragraph why an operation table of function pointers helps testing.

Focus on swapping implementations with unchanged client tests.

Solution

Guided solution

Prerequisites

This section can be read on its own.

Key terms in this unit

More notes in this series