Bird
Raised Fist0
DSA Rustprogramming~20 mins

Collision Handling Using Open Addressing Linear Probing in DSA Rust - Practice Problems & Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Linear Probing Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
Output of Linear Probing Insertions in Hash Table
What is the printed state of the hash table after inserting keys 10, 22, 31, 4, 15 using linear probing with a table size of 10?
DSA Rust
struct HashTable {
    table: [Option<i32>; 10],
}

impl HashTable {
    fn new() -> Self {
        Self { table: [None; 10] }
    }

    fn hash(&self, key: i32) -> usize {
        (key % 10) as usize
    }

    fn insert(&mut self, key: i32) {
        let mut idx = self.hash(key);
        while self.table[idx].is_some() {
            idx = (idx + 1) % 10;
        }
        self.table[idx] = Some(key);
    }

    fn print(&self) {
        for i in 0..10 {
            match self.table[i] {
                Some(k) => print!("{} -> ", k),
                None => print!("null -> "),
            }
        }
        println!("null");
    }
}

fn main() {
    let mut ht = HashTable::new();
    let keys = [10, 22, 31, 4, 15];
    for &key in keys.iter() {
        ht.insert(key);
    }
    ht.print();
}
A10 -> 31 -> 22 -> null -> 4 -> 15 -> null -> null -> null -> null
B10 -> 22 -> 31 -> 4 -> null -> 15 -> null -> null -> null -> null
C10 -> 22 -> 31 -> null -> 4 -> 15 -> null -> null -> null -> null
D10 -> 22 -> 31 -> 4 -> 15 -> null -> null -> null -> null -> null
Attempts:
2 left
💡 Hint
Remember linear probing moves to the next slot when collision happens.
❓ Predict Output
intermediate
2:00remaining
Result of Searching in Linear Probing Hash Table
Given a hash table of size 7 with keys inserted using linear probing: 14, 21, 28, 35, what is the index returned when searching for key 35?
DSA Rust
struct HashTable {
    table: [Option<i32>; 7],
}

impl HashTable {
    fn new() -> Self {
        Self { table: [None; 7] }
    }

    fn hash(&self, key: i32) -> usize {
        (key % 7) as usize
    }

    fn insert(&mut self, key: i32) {
        let mut idx = self.hash(key);
        while self.table[idx].is_some() {
            idx = (idx + 1) % 7;
        }
        self.table[idx] = Some(key);
    }

    fn search(&self, key: i32) -> Option<usize> {
        let mut idx = self.hash(key);
        let start = idx;
        loop {
            match self.table[idx] {
                Some(k) if k == key => return Some(idx),
                None => return None,
                _ => {
                    idx = (idx + 1) % 7;
                    if idx == start {
                        return None;
                    }
                }
            }
        }
    }
}

fn main() {
    let mut ht = HashTable::new();
    let keys = [14, 21, 28, 35];
    for &key in keys.iter() {
        ht.insert(key);
    }
    let result = ht.search(35);
    println!("{:?}", result);
}
ASome(0)
BNone
CSome(6)
DSome(3)
Attempts:
2 left
💡 Hint
Calculate hash index and follow linear probing steps.
🔧 Debug
advanced
2:00remaining
Identify the Bug in Linear Probing Insert Function
What error will occur when running this Rust code for inserting keys 1, 6, 11, 16, 21 using linear probing?
DSA Rust
fn insert(table: &mut [Option<i32>], key: i32) {
    let size = table.len();
    let mut idx = (key % size as i32) as usize;
    while table[idx].is_some() {
        idx += 1;
    }
    table[idx] = Some(key);
}

fn main() {
    let mut table = vec![None; 5];
    insert(&mut table, 1);
    insert(&mut table, 6);
    insert(&mut table, 11);
    insert(&mut table, 16);
    insert(&mut table, 21);
    println!("{:?}", table);
}
AInfinite loop during insertion
BCompilation error due to type mismatch
CIndex out of bounds panic at runtime
DCorrect insertion without errors
Attempts:
2 left
💡 Hint
Check how index is incremented and used.
📝 Syntax
advanced
2:00remaining
Correct Syntax for Linear Probing Insert Loop
Which option correctly implements the loop to find the next empty slot using linear probing in Rust?
DSA Rust
fn insert(table: &mut [Option<i32>], key: i32) {
    let size = table.len();
    let mut idx = (key % size as i32) as usize;
    // Find empty slot
    loop {
        if table[idx].is_none() {
            table[idx] = Some(key);
            break;
        }
        idx = (idx + 1) % size;
    }
}
Aloop { if table[idx].is_none() { table[idx] = Some(key); break; } idx = (idx + 1) % size; }
Bfor idx in 0..size { if table[idx].is_none() { table[idx] = Some(key); break; } }
Cwhile table[idx].is_none() { idx = (idx + 1) % size; } table[idx] = Some(key);
Dwhile table[idx].is_some() { idx = (idx + 1) % size; } table[idx] = Some(key);
Attempts:
2 left
💡 Hint
Look for a loop that breaks when empty slot is found.
🚀 Application
expert
3:00remaining
Final Hash Table State After Mixed Insertions and Deletions
Consider a hash table of size 7 using linear probing. Insert keys 10, 20, 5, 15, then delete key 20 by marking its slot as deleted (using a special marker). Then insert key 27. What is the final state of the table?
DSA Rust
enum Slot {
    Empty,
    Deleted,
    Occupied(i32),
}

struct HashTable {
    table: [Slot; 7],
}

impl HashTable {
    fn new() -> Self {
        Self { table: [Slot::Empty; 7] }
    }

    fn hash(&self, key: i32) -> usize {
        (key % 7) as usize
    }

    fn insert(&mut self, key: i32) {
        let size = self.table.len();
        let mut idx = self.hash(key);
        loop {
            match &self.table[idx] {
                Slot::Empty | Slot::Deleted => {
                    self.table[idx] = Slot::Occupied(key);
                    break;
                }
                _ => {
                    idx = (idx + 1) % size;
                }
            }
        }
    }

    fn delete(&mut self, key: i32) {
        let size = self.table.len();
        let mut idx = self.hash(key);
        let start = idx;
        loop {
            match &self.table[idx] {
                Slot::Occupied(k) if *k == key => {
                    self.table[idx] = Slot::Deleted;
                    break;
                }
                Slot::Empty => break,
                _ => {
                    idx = (idx + 1) % size;
                    if idx == start {
                        break;
                    }
                }
            }
        }
    }

    fn print(&self) {
        for slot in self.table.iter() {
            match slot {
                Slot::Empty => print!("null -> "),
                Slot::Deleted => print!("del -> "),
                Slot::Occupied(k) => print!("{} -> ", k),
            }
        }
        println!("null");
    }
}

fn main() {
    let mut ht = HashTable::new();
    ht.insert(10);
    ht.insert(20);
    ht.insert(5);
    ht.insert(15);
    ht.delete(20);
    ht.insert(27);
    ht.print();
}
A10 -> del -> 5 -> 15 -> null -> 27 -> null -> null
Bnull -> 15 -> null -> 10 -> null -> 5 -> 27 -> null
C10 -> del -> 5 -> 15 -> null -> null -> 27 -> null
D10 -> del -> 5 -> 15 -> null -> null -> null -> 27
Attempts:
2 left
💡 Hint
Remember linear probing inserts at first empty or deleted slot.

Practice

(1/5)
1. What is the main idea behind linear probing in collision handling for hash tables?
easy
A. Use a secondary hash function to find a new slot.
B. Use a linked list to store multiple values at the same index.
C. Double the size of the hash table when a collision happens.
D. If a collision occurs, check the next slot sequentially until an empty slot is found.

Solution

  1. Step 1: Understand collision handling methods

    Linear probing is a method where, upon collision, the algorithm checks the next slot in the array sequentially.
  2. Step 2: Compare with other methods

    Other methods include chaining (linked lists), resizing, or double hashing, but linear probing specifically uses sequential slots.
  3. Final Answer:

    If a collision occurs, check the next slot sequentially until an empty slot is found. -> Option D
  4. Quick Check:

    Linear probing = sequential slot check [OK]
Hint: Linear probing means try next slot one by one [OK]
Common Mistakes:
  • Confusing linear probing with chaining
  • Thinking linear probing uses a second hash function
  • Assuming table size doubles on collision
2. Which of the following Rust code snippets correctly implements linear probing to find the next index after a collision in a hash table of size table_size?
easy
A. let next_index = (current_index + 1) % table_size;
B. let next_index = (current_index * 2) % table_size;
C. let next_index = (current_index - 1) % table_size;
D. let next_index = (current_index + 3) % table_size;

Solution

  1. Step 1: Understand linear probing index calculation

    Linear probing moves to the next slot by adding 1 to the current index and wrapping around using modulo.
  2. Step 2: Check each option

    let next_index = (current_index + 1) % table_size; adds 1 and uses modulo, which is correct. Others multiply or subtract, which are not standard linear probing steps.
  3. Final Answer:

    let next_index = (current_index + 1) % table_size; -> Option A
  4. Quick Check:

    Linear probing = increment index by 1 modulo table size [OK]
Hint: Linear probing increments index by 1 modulo table size [OK]
Common Mistakes:
  • Using multiplication instead of addition
  • Subtracting index without handling negative wrap
  • Skipping modulo operation causing out-of-bounds
3. Consider the following Rust code snippet for inserting keys into a hash table using linear probing. What will be the final state of the hash table array after inserting keys [5, 15, 25] with table size 10 and hash function key % 10?
let mut table = vec![None; 10];
let keys = vec![5, 15, 25];
for &key in &keys {
    let mut index = key % 10;
    while table[index].is_some() {
        index = (index + 1) % 10;
    }
    table[index] = Some(key);
}
println!("{:?}", table);
medium
A. [None, None, None, None, None, Some(5), Some(15), None, Some(25), None]
B. [None, None, None, None, None, Some(5), None, Some(15), Some(25), None]
C. [None, None, None, None, None, Some(5), Some(15), Some(25), None, None]
D. [Some(5), Some(15), Some(25), None, None, None, None, None, None, None]

Solution

  1. Step 1: Calculate initial indices for keys

    Keys 5, 15, 25 all hash to index 5 (5 % 10 = 5, 15 % 10 = 5, 25 % 10 = 5).
  2. Step 2: Insert keys using linear probing

    Insert 5 at index 5. For 15, index 5 is occupied, so move to 6. Insert 15 at 6. For 25, indices 5 and 6 are occupied, move to 7 and insert 25.
  3. Final Answer:

    [None, None, None, None, None, Some(5), Some(15), Some(25), None, None] -> Option C
  4. Quick Check:

    Linear probing places keys at 5, 6, 7 [OK]
Hint: Keys with same hash go to next free slot sequentially [OK]
Common Mistakes:
  • Placing all keys at index 5 ignoring collisions
  • Skipping modulo wrap-around
  • Inserting keys at wrong indices after collision
4. The following Rust code attempts to insert keys into a hash table using linear probing. However, it sometimes causes an infinite loop. What is the bug?
let mut table = vec![None; 5];
let keys = vec![1, 6, 11];
for &key in &keys {
    let mut index = key % 5;
    while table[index].is_some() {
        index = (index + 1) % 5;
    }
    table[index] = Some(key);
}
medium
A. The code does not check if the table is full, causing infinite loop when no empty slot exists.
B. The modulo operator is used incorrectly; it should be key % 6.
C. The loop should break after checking only once to avoid infinite loop.
D. The vector size is too large, causing index out of bounds.

Solution

  1. Step 1: Analyze the while loop condition

    The loop continues while the slot is occupied, moving to next index with wrap-around.
  2. Step 2: Identify missing termination condition

    If the table is full, the loop cycles endlessly because no empty slot is found and no exit condition exists.
  3. Final Answer:

    The code does not check if the table is full, causing infinite loop when no empty slot exists. -> Option A
  4. Quick Check:

    Missing full-table check causes infinite loop [OK]
Hint: Always check for full table to avoid infinite loops [OK]
Common Mistakes:
  • Ignoring full table condition
  • Changing modulo divisor incorrectly
  • Breaking loop too early causing wrong insertion
5. You have a hash table of size 7 using linear probing for collision handling. You insert keys [10, 20, 15, 7, 32] with hash function key % 7. After all insertions, what is the state of the table? Represent empty slots as null. Explain your answer step-by-step.
medium
A. [10, 20, 15, 7, 32, null, null]
B. [7, 15, null, 10, 32, null, 20]
C. [null, 15, 32, 7, 10, 20, null]
D. [null, 15, 32, null, 10, null, 7]

Solution

  1. Step 1: Calculate initial indices for each key

    10 % 7 = 3, 20 % 7 = 6, 15 % 7 = 1, 7 % 7 = 0, 32 % 7 = 4.
  2. Step 2: Insert keys using linear probing

    All hashed indices are empty, so place: 10 at 3, 20 at 6, 15 at 1, 7 at 0, 32 at 4.
  3. Step 3: Final table state

    Indices 2 and 5 remain null: [7, 15, null, 10, 32, null, 20].
  4. Final Answer:

    [7, 15, null, 10, 32, null, 20] -> Option B
  5. Quick Check:

    Insert keys at hashed index or next free slot [OK]
Hint: Calculate hash, insert or probe next free slot [OK]
Common Mistakes:
  • Not applying modulo correctly
  • Placing keys at wrong indices after collision
  • Ignoring empty slots in final output
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard