Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dictionaries #5351

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
package com.thealgorithms.datastructures.dictionary;

/**
* A clone of a Python dictionary in a Java class that simulates a key-value store using a hash table
* implemented from scratch without using standard collections like Map.
*/
public class "Dictionary(Sorted)" {
private static final int SIZE = 10; // Number of buckets
private Bucket[] buckets;
private SortStrategy sortStrategy = SortStrategy.KEY; // Default sorting strategy

/**
* Enum to represent sorting strategies.
*/
public enum SortStrategy {
KEY, VALUE
}

/**
* Inner class to represent a key-value pair.
*/
private static class Entry {
String key;
Object value;

Entry(String key, Object value) {
this.key = key;
this.value = value;
}
}

/**
* Inner class to represent a bucket in the hash table.
*/
private static class Bucket {
Entry entry;
Bucket next;

Bucket(Entry entry) {
this.entry = entry;
this.next = null;
}
}

/**
* Constructs an empty dictionary.
*/
public DictionarySort() {
this.buckets = new Bucket[SIZE];
}

/**
* Constructs a dictionary with initial key-value pairs.
*
* @param keyValuePairs An even number of arguments where each pair consists of a key and a value.
* @throws IllegalArgumentException if the number of arguments is odd.
*/
public DictionarySort(Object... keyValuePairs) {
this();
if (keyValuePairs.length % 2 != 0) {
throw new IllegalArgumentException("Key-value pairs must be even.");
}
for (int i = 0; i < keyValuePairs.length; i += 2) {
String key = (String) keyValuePairs[i];
Object value = keyValuePairs[i + 1];
put(key, value);
}
}

/**
* Computes the index in the hash table for a given key.
*
* @param key The key for which the index is computed.
* @return The index in the hash table.
*/
private int getIndex(String key) {
return Math.abs(key.hashCode()) % SIZE;
}

/**
* Adds or updates a key-value pair in the dictionary.
*
* @param key The key to be added or updated.
* @param value The value associated with the key.
*/
public void put(String key, Object value) {
int index = getIndex(key);
Bucket bucket = buckets[index];

// Traverse the bucket to find if the key already exists
while (bucket != null) {
if (bucket.entry.key.equals(key)) {
// Update the value if the key is found
bucket.entry.value = value;
return;
}
bucket = bucket.next;
}

// If key is not found, add a new entry to the beginning of the bucket
Bucket newBucket = new Bucket(new Entry(key, value));
newBucket.next = buckets[index];
buckets[index] = newBucket;
}

/**
* Retrieves the value associated with a given key.
*
* @param key The key whose value is to be retrieved.
* @return The value associated with the key, or null if the key is not found.
*/
public Object get(String key) {
int index = getIndex(key);
Bucket bucket = buckets[index];

// Traverse the bucket to find the key
while (bucket != null) {
if (bucket.entry.key.equals(key)) {
return bucket.entry.value;
}
bucket = bucket.next;
}
return null; // Return null if the key is not found
}

/**
* Removes the key-value pair associated with the given key.
*
* @param key The key to be removed.
*/
public void remove(String key) {
int index = getIndex(key);
Bucket bucket = buckets[index];
Bucket prev = null;

// Traverse the bucket to find the key
while (bucket != null) {
if (bucket.entry.key.equals(key)) {
if (prev == null) {
// Removing the first bucket in the slot
buckets[index] = bucket.next;
} else {
// Removing a bucket from the middle or end
prev.next = bucket.next;
}
return;
}
prev = bucket;
bucket = bucket.next;
}
}

/**
* Checks if the dictionary contains the specified key.
*
* @param key The key to check for.
* @return true if the dictionary contains the key, false otherwise.
*/
public boolean containsKey(String key) {
int index = getIndex(key);
Bucket bucket = buckets[index];

// Traverse the bucket to find the key
while (bucket != null) {
if (bucket.entry.key.equals(key)) {
return true;
}
bucket = bucket.next;
}
return false;
}

/**
* Sets the sorting strategy for the dictionary.
*
* @param strategy The sorting strategy to use.
*/
public void setSortStrategy(SortStrategy strategy) {
this.sortStrategy = strategy;
}

/**
* Returns a string representation of the dictionary in a JSON-like format without formatting.
*
* @return A JSON-like string representation of the dictionary.
*/
@Override
public String toString() {
return toString(false);
}

/**
* Returns a string representation of the dictionary in a JSON-like format with optional formatting.
*
* @param formatted If true, returns the string in a formatted JSON-like format.
* @return A JSON-like string representation of the dictionary.
*/
public String toString(boolean formatted) {
StringBuilder sb = new StringBuilder();
sb.append(formatted ? "{\n" : "{");

Entry[] entries = getAllEntries();
if (sortStrategy == SortStrategy.KEY) {
sortByKey(entries);
} else if (sortStrategy == SortStrategy.VALUE) {
sortByValue(entries);
}

boolean first = true;
for (Entry entry : entries) {
if (!first) {
sb.append(formatted ? ",\n" : ", ");
}
sb.append(formatted ? " " : "")
.append("\"").append(entry.key).append("\": ")
.append("\"").append(entry.value.toString()).append("\"");
first = false;
}
sb.append(formatted ? "\n}" : "}");
return sb.toString();
}

/**
* Retrieves all entries from the dictionary.
*
* @return An array of all entries.
*/
private Entry[] getAllEntries() {
// Gather all entries from all buckets
int count = 0;
for (Bucket bucket : buckets) {
while (bucket != null) {
count++;
bucket = bucket.next;
}
}

Entry[] entries = new Entry[count];
int index = 0;
for (Bucket bucket : buckets) {
while (bucket != null) {
entries[index++] = bucket.entry;
bucket = bucket.next;
}
}
return entries;
}

/**
* Sorts entries by key using quicksort.
*
* @param entries The array of entries to be sorted.
*/
private void sortByKey(Entry[] entries) {
quickSort(entries, 0, entries.length - 1, true);
}

/**
* Sorts entries by value using quicksort.
*
* @param entries The array of entries to be sorted.
*/
private void sortByValue(Entry[] entries) {
quickSort(entries, 0, entries.length - 1, false);
}

/**
* Quicksort implementation to sort entries by key or value.
*
* @param entries The array of entries to be sorted.
* @param low The starting index.
* @param high The ending index.
* @param byKey True to sort by key, false to sort by value.
*/
private void quickSort(Entry[] entries, int low, int high, boolean byKey) {
if (low < high) {
int pivotIndex = partition(entries, low, high, byKey);
quickSort(entries, low, pivotIndex - 1, byKey);
quickSort(entries, pivotIndex + 1, high, byKey);
}
}

/**
* Partition method for quicksort.
*
* @param entries The array of entries to be partitioned.
* @param low The starting index.
* @param high The ending index.
* @param byKey True to sort by key, false to sort by value.
* @return The index of the pivot element.
*/
private int partition(Entry[] entries, int low, int high, boolean byKey) {
Entry pivot = entries[high];
int i = low - 1;
for (int j = low; j < high; j++) {
boolean condition;
if (byKey) {
condition = entries[j].key.compareTo(pivot.key) < 0;
} else {
condition = entries[j].value.toString().compareTo(pivot.value.toString()) < 0;
}
if (condition) {
i++;
Entry temp = entries[i];
entries[i] = entries[j];
entries[j] = temp;
}
}
Entry temp = entries[i + 1];
entries[i + 1] = entries[high];
entries[high] = temp;
return i + 1;
}
}
Loading
Loading