Create a         public int GetMatchingOrNextAvailableBucket(K key) method for below class with the following requirements:
Looks for the next available bucket based on the key passed, (Uses linear probing for collision handling, will return to the 0 index and continue searching if array length is reached). Note, if the key exists, it returns the bucket of the matching key. 
DO NOT LOOP THROUGH EVERY ENTRY FROM 0 TO ARRAY LENGTH IN THIS METHOD. Start from the starting bucket and use linear probing. It may end up going through many indexes, but in practice it will never do that because you have a threshold and there are many empty array spots.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Assignment_4
{
    public class HashMap<K, V> : IMap<K, V>
    {
        /* Properties */

        public Entry<K, V>[] Table { get; set; }
        public int Capacity { get; set; }
        public double LoadFactor { get; set; }
        public int size; // Had to use a field to satisfy the IMap requirements of using the Size() method.
        public int Placeholders { get; set; } // Keeps track of the number of placeholders in the HashMap.

        /* Constructors */

        public HashMap()
        {
            this.Capacity = 11;
            this.Table = new Entry<K, V>[this.Capacity];
            this.LoadFactor = 0.75;
            this.size = 0;
        }

        public HashMap(int initialCapacity)
        {
            if (initialCapacity <= 0)
            {
                throw new ArgumentException();
            }

            this.Capacity = initialCapacity;
            this.Table = new Entry<K, V>[this.Capacity];
            this.LoadFactor = 0.75;
            this.size = 0;
        }

        public HashMap(int initialCapacity, double loadFactor)
        {
            if (initialCapacity <= 0 || loadFactor <= 0)
            {
                throw new ArgumentException();
            }

            this.Capacity = initialCapacity;
            this.Table = new Entry<K, V>[this.Capacity];
            this.LoadFactor = loadFactor;
            this.size = 0;
        }

        /* Methods */

        public int Size()
        {
            return this.size;
        }

        public bool IsEmpty()
        {
            return this.size == 0;
        }

        public void Clear()
        {
            Array.Clear(this.Table, 0, this.Table.Length);
            this.size = 0;
            this.Placeholders = 0;
        }

            throw new InvalidOperationException("“No available bucket found.");
        }

        public V Get(K key)
        {
            if (key == null)
            {
                throw new ArgumentNullException();
            }

            int bucket = GetMatchingOrNextAvailableBucket(key);

            if (this.Table[bucket] != null && this.Table[bucket].Key.Equals(key))
            {
                return this.Table[bucket].Value;
            }
            else
            {
                return default(V); // If no matching key is found, return the default value of the V type (usually null for reference types).
            }
        }

        public V Put(K key, V value)
        {
            if (key == null)
            {
                throw new ArgumentNullException();
            }
            if (value == null)
            {
                throw new ArgumentNullException();
            }

            if ((this.size + this.Placeholders + 1) >= this.Capacity * this.LoadFactor)
            {
                ReHash();
            }

            int bucket = GetMatchingOrNextAvailableBucket(key);

            for (Entry<K, V> entry = this.Table[bucket]; entry != null; entry = entry.Next)
            {
                if (entry.Key.Equals(key))
                {
                    V oldValue = entry.Value;
                    entry.Value = value;

                    return oldValue;
                }
            }

            Entry<K, V> newEntry = new Entry<K, V>(key, value);
            newEntry.Next = this.Table[bucket];
            this.Table[bucket] = newEntry;
            this.size++;

            return default(V);
        }

        public V Remove(K key)
        {
            if (key == null)
            {
                throw new ArgumentNullException();
            }

            int bucket = GetMatchingOrNextAvailableBucket(key);

            if (this.Table[bucket] != null && this.Table[bucket].Key.Equals(key))
            {
                V removedValue = this.Table[bucket].Value;
                this.Table[bucket].Value = default(V);
                this.Placeholders++;
                this.size--;

                return removedValue;
            }
            else
            {
                return default(V); // If no matching key is found, return the default value of the V type (usually null for reference types).
            }
        }

        private int ReSize()
        {
            int newCapacity = this.Capacity;

            // Find the nearest prime number greater than or equal to double the current capacity.
            if (newCapacity == 1)
            {
                newCapacity = 2;
            }
            else
            {
                newCapacity = this.Capacity * 2;

                while (!IsPrime(newCapacity))
                {
                    newCapacity++;
                }
            }

            return newCapacity;
        }

        public void ReHash()
        {
            Entry<K, V>[] oldTable = this.Table;
            int newCapacity = ReSize(); // Store the result of ReSize() in a local variable
            Entry<K, V>[] newTable = new Entry<K, V>[newCapacity]; // Create a new table with the updated Capacity

            this.size = 0; // Reset the size to 0 as we’ll be adding back all the elements.
            this.Placeholders = 0;

            // Rehash the entire hash map by iterating through the old table.
            for (int i = 0; i < oldTable.Length; i++)
            {
                Entry<K, V> entry = oldTable[i];
                while (entry != null)
                {
                    Entry<K, V> nextEntry = entry.Next;
                    int startPosition = Math.Abs(entry.Key.GetHashCode()) % newTable.Length;

                    for (int j = 0; j < newCapacity; j++)
                    {
                        int bucket = (startPosition + j) % newCapacity;

                        if (newTable[bucket] == null)
                        {
                            newTable[bucket] = entry;
                            entry.Next = null;
                            this.size++;
                            break;
                        }
                    }

                    entry = nextEntry;
                }
            }

            this.Table = newTable;
            this.Capacity = newCapacity;
        }

        public IEnumerator<V> Values()
        {
            List<V> valuesList = new List<V>();

            for (int i = 0; i < this.Capacity; i++)
            {
                Entry<K, V> entry = this.Table[i];

                if (entry != null && entry.Value != null)
                {
                    valuesList.Add(entry.Value);
                }
            }
            return valuesList.GetEnumerator();
        }

        public IEnumerator<K> Keys()
        {
            List<K> keysList = new List<K>();

            for (int i = 0; i < this.Capacity; i++)
            {
                Entry<K, V> entry = this.Table[i];

                if (entry != null && entry.Value != null)
                {
                    keysList.Add(entry.Key);
                }
            }

            return keysList.GetEnumerator();
        }

        private bool IsPrime(int number)
        {
            if (number <= 1) return false;

            if (number == 2 || number == 3) return true;

            if (number % 2 == 0) return false;

            for (int i = 3; i * i <= number; i += 2)
            {
                if (number % i == 0) return false;
            }

            return true;
        }
    }
}