// Stack · Queue · Linked List · Binary Trees · Infix/Prefix/Postfix
Every data structure has:
An Abstract Data Type (ADT) is a mathematical model for a data type that defines its behavior purely from the user's point of view — specifying the type of data and the operations possible, without specifying how these operations will be implemented.
interface keyword to define ADTs.
| Topic | Key Concepts | Weight |
|---|---|---|
| Stack | LIFO, push, pop, peek, isEmpty, overflow/underflow | High ⭐⭐⭐ |
| Queue | FIFO, enqueue, dequeue, circular queue, dequeue (double-ended) | High ⭐⭐⭐ |
| Infix/Postfix/Prefix | Conversion algorithms using stack, precedence rules | Very High ⭐⭐⭐⭐ |
| Linked List | Insertion, deletion, reversal, traversal, searching | High ⭐⭐⭐ |
| Binary Trees | Terminology, properties, traversals (conceptual) | High ⭐⭐⭐ |
| Interface & ADT | Java interface, multiple implementations | Medium ⭐⭐ |
| Operation | Description | Condition Check |
|---|---|---|
push(x) | Insert element x onto top of stack | Check: not full (overflow) |
pop() | Remove and return top element | Check: not empty (underflow) |
peek() / top() | Return top element without removing | Check: not empty |
isEmpty() | Returns true if stack has no elements | — |
isFull() | Returns true if stack is at max capacity | Array-based only |
size() | Returns number of elements | — |
// Stack interface (ADT)
interface Stack {
void push(int x);
int pop();
int peek();
boolean isEmpty();
boolean isFull();
}
// Array-based implementation
class ArrayStack implements Stack {
int[] arr;
int top, maxSize;
ArrayStack(int size) {
maxSize = size;
arr = new int[maxSize];
top = -1; // -1 means empty
}
public boolean isEmpty() { return top == -1; }
public boolean isFull() { return top == maxSize - 1; }
public void push(int x) {
if (isFull())
System.out.println("Stack Overflow!");
else
arr[++top] = x;
}
public int pop() {
if (isEmpty()) {
System.out.println("Stack Underflow!");
return -1;
}
return arr[top--];
}
public int peek() {
if (isEmpty()) return -1;
return arr[top];
}
}Java
| Operation | Description |
|---|---|
enqueue(x) | Add element at REAR |
dequeue() | Remove element from FRONT |
peek() | View FRONT element without removing |
isEmpty() | front == -1 (or front > rear) |
isFull() | rear == maxSize - 1 |
rear = (rear + 1) % maxSizefront = (front + 1) % maxSizefront == -1(rear + 1) % maxSize == frontclass CircularQueue {
int[] arr;
int front, rear, maxSize;
CircularQueue(int size) {
maxSize = size;
arr = new int[maxSize];
front = rear = -1;
}
boolean isEmpty() { return front == -1; }
boolean isFull() {
return (rear + 1) % maxSize == front;
}
void enqueue(int x) {
if (isFull()) { System.out.println("Queue Full!"); return; }
if (isEmpty()) front = 0;
rear = (rear + 1) % maxSize;
arr[rear] = x;
}
int dequeue() {
if (isEmpty()) { System.out.println("Queue Empty!"); return -1; }
int val = arr[front];
if (front == rear) front = rear = -1; // last element removed
else front = (front + 1) % maxSize;
return val;
}
}Java
| Operation | Description |
|---|---|
insertFront(x) | Add at front |
insertRear(x) | Add at rear |
deleteFront() | Remove from front |
deleteRear() | Remove from rear |
peekFront() | View front element |
peekRear() | View rear element |
| Property | Stack | Queue | Dequeue |
|---|---|---|---|
| Order | LIFO | FIFO | Both ends |
| Insert at | TOP only | REAR only | Both ends |
| Delete from | TOP only | FRONT only | Both ends |
| Uses | Recursion, Undo | Scheduling, BFS | Palindrome check |
| Notation | Operator Position | Example (A+B) | Also Called |
|---|---|---|---|
| Infix | Between operands | A + B |
Normal / Human notation |
| Prefix | Before operands | + A B |
Polish Notation |
| Postfix | After operands | A B + |
Reverse Polish Notation (RPN) |
| Precedence | Operator(s) | Associativity |
|---|---|---|
| 1 (Highest) | ( ) Parentheses | — |
| 2 | ^ Exponentiation | Right to Left |
| 3 | * / Multiply, Divide | Left to Right |
| 4 (Lowest) | + - Add, Subtract | Left to Right |
Convert: A + B * C - D
| Character | Stack | Output | Action |
|---|---|---|---|
| A | [ ] | A | Operand → output |
| + | [+] | A | Push + |
| B | [+] | AB | Operand → output |
| * | [+,*] | AB | * has higher precedence, push |
| C | [+,*] | ABC | Operand → output |
| - | [-] | ABC*+ | Pop * and + (≥ precedence), push - |
| D | [-] | ABC*+D | Operand → output |
| End | [ ] | ABC*+D- | Pop remaining - |
| Infix | Postfix | Prefix |
|---|---|---|
| A + B | A B + | + A B |
| A + B * C | A B C * + | + A * B C |
| (A + B) * C | A B + C * | * + A B C |
| A * B + C * D | A B * C D * + | + * A B * C D |
| A ^ B ^ C | A B C ^ ^ | ^ A ^ B C |
| (A + B) * (C - D) | A B + C D - * | * + A B - C D |
Example: Evaluate 5 3 2 * + 1 -
Scan 5 → push 5 Stack: [5]
Scan 3 → push 3 Stack: [5,3]
Scan 2 → push 2 Stack: [5,3,2]
Scan * → pop 2,3 → 3*2=6, push 6 Stack: [5,6]
Scan + → pop 6,5 → 5+6=11, push 11 Stack: [11]
Scan 1 → push 1 Stack: [11,1]
Scan - → pop 1,11 → 11-1=10, push 10
Result: 10
class Node {
int data;
Node next;
Node(int d) {
data = d;
next = null;
}
}Java
New node's next points to current head; head updated to new node.
void insertAtBeginning(int data) {
Node newNode = new Node(data);
newNode.next = head; // point to old head
head = newNode; // update head
}
Traverse to last node, set its next to new node.
void insertAtEnd(int data) {
Node newNode = new Node(data);
if (head == null) { head = newNode; return; }
Node temp = head;
while (temp.next != null)
temp = temp.next;
temp.next = newNode;
}
Traverse to node before desired position, redirect pointers.
void insertAtPosition(int data, int pos) {
Node newNode = new Node(data);
if (pos == 1) { newNode.next = head; head = newNode; return; }
Node temp = head;
for (int i = 1; i < pos - 1 && temp != null; i++)
temp = temp.next;
newNode.next = temp.next;
temp.next = newNode;
}
void deleteFirst() {
if (head == null) { System.out.println("Empty!"); return; }
head = head.next; // move head forward
}
void deleteLast() {
if (head == null) return;
if (head.next == null) { head = null; return; }
Node temp = head;
while (temp.next.next != null)
temp = temp.next;
temp.next = null; // remove last node
}
void deleteByValue(int val) {
if (head == null) return;
if (head.data == val) { head = head.next; return; }
Node temp = head;
while (temp.next != null && temp.next.data != val)
temp = temp.next;
if (temp.next != null)
temp.next = temp.next.next;
}
void reverse() {
Node prev = null;
Node curr = head;
Node next = null;
while (curr != null) {
next = curr.next; // save next
curr.next = prev; // reverse pointer
prev = curr; // move prev forward
curr = next; // move curr forward
}
head = prev; // new head is old tail
}Java
boolean isEmpty() {
return head == null;
}
void display() {
Node t = head;
while (t != null) {
System.out.print(t.data+" → ");
t = t.next;
}
System.out.println("null");
}
int getElement(int pos) {
Node temp = head;
for (int i = 1; i < pos && temp != null; i++)
temp = temp.next;
return (temp != null) ? temp.data : -1;
}
| Feature | Array | Linked List |
|---|---|---|
| Size | Fixed at creation | Dynamic |
| Memory | Contiguous | Non-contiguous |
| Access | O(1) random | O(n) sequential |
| Insertion | O(n) shifting | O(1) at known position |
| Deletion | O(n) shifting | O(1) at known position |
| Term | Definition | Example (above tree) |
|---|---|---|
| Root | Topmost node; has no parent | A |
| Internal Node | Node with at least one child | A, B, C |
| External Node (Leaf) | Node with no children | D, E, F, G |
| Parent | Node with child nodes | A is parent of B, C |
| Child | Nodes directly below a parent | B, C are children of A |
| Siblings | Nodes sharing the same parent | B & C are siblings; D & E are siblings |
| Subtree | A node and all its descendants | B's subtree = {B, D, E} |
| Edge | Connection between parent and child | A→B, A→C, etc. |
| Path | Sequence of nodes from one to another | A→B→D |
| Level | Distance from root + 1 (root = level 1) | A=1, B&C=2, D,E,F,G=3 |
| Depth of Node | Number of edges from root to node | depth(A)=0, depth(B)=1, depth(D)=2 |
| Height of Node | Number of edges on longest path from node to a leaf | height(A)=2, height(B)=1, height(D)=0 |
| Height of Tree | Height of root = max depth of any leaf | Height = 2 |
| Depth of Tree | Same as height of tree | 2 |
| Degree of Node | Number of children of that node | degree(A)=2, degree(D)=0 |
| Degree of Tree | Maximum degree of any node | 2 (binary tree) |
| Size | Total number of nodes in tree | 7 |
Visit left subtree, then root, then right subtree.
void inorder(Node root) {
if (root == null) return;
inorder(root.left); // Left
System.out.print(root.data + " "); // Root
inorder(root.right); // Right
}
Visit root first, then left subtree, then right subtree.
void preorder(Node root) {
if (root == null) return;
System.out.print(root.data + " "); // Root
preorder(root.left); // Left
preorder(root.right); // Right
}
Visit left subtree, right subtree, then root last.
void postorder(Node root) {
if (root == null) return;
postorder(root.left); // Left
postorder(root.right); // Right
System.out.print(root.data + " "); // Root
}
interface perfectly models an ADT — it declares what operations exist but not how they work. Multiple classes can implement the same interface differently.
// Stack ADT defined as interface
interface StackADT {
void push(int x);
int pop();
int peek();
boolean isEmpty();
int size();
}
// Implementation 1: using array
class ArrayStack implements StackADT {
int[] arr = new int[100];
int top = -1;
public void push(int x) { arr[++top] = x; }
public int pop() { return arr[top--]; }
public int peek() { return arr[top]; }
public boolean isEmpty() { return top == -1; }
public int size() { return top + 1; }
}
// Implementation 2: using linked list node
class LinkedStack implements StackADT {
private class Node {
int data; Node next;
Node(int d) { data = d; }
}
Node top = null;
int count = 0;
public void push(int x) {
Node n = new Node(x);
n.next = top; top = n; count++;
}
public int pop() {
int v = top.data; top = top.next; count--; return v;
}
public int peek() { return top.data; }
public boolean isEmpty() { return top == null; }
public int size() { return count; }
}
// Usage with polymorphism
StackADT s1 = new ArrayStack();
StackADT s2 = new LinkedStack();
// Both can be used the same way!Java
implements keyword to implement an interface