Computer Science/Data Structures

📚 Map

metamong 2023. 8. 3.

Map

fundamentals

  dictionaries are indexed by keys, which can be any immutable type; strings and numbers can always be keys. / map data structure is defined as a data structure that stores a collection of key-value pairs, where each key is associated with a single value / maps provide an efficient way to store and retrieve data based on a unique identifier(the key)

 

Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can’t use lists as keys, since lists can be modified in place using index assignments, slice assignments, or methods like append() and extend().

It is best to think of a dictionary as a set of key: value pairs, with the requirement that the keys are unique (within one dictionary). A pair of braces creates an empty dictionary: {}. Placing a comma-separated list of key:value pairs within the braces adds initial key:value pairs to the dictionary; this is also the way dictionaries are written on output.

The main operations on a dictionary are storing a value with some key and extracting the value given the key. It is also possible to delete a key:value pair with del. If you store using a key that is already in use, the old value associated with that key is forgotten(change a value). It is an error to extract a value using a non-existent key.

 

→ need for map data structure

(1) fast lookup: unordered maps allow for constant-time(O(1)) average-case lookup of elements based on their unique keys

(2) efficient insertion & deletion

(3) unique keys: ensure that each key is unique, allowing for efficient association of data with specific identifiers

(4) flexible data storage: store a wide variety of data types(as both keys and values) providing a flexible and versatile data storage solution

(5) intuitive representation: the key-value pair structure of maps offers an intuitive way to model and represent real-world data relationships.

 

→ properties of map data structure

(1) Key-Value association: allow you to associate arbitrary values with unique keys. Enables efficient data retrieval and manipulation based on keys

(2) Unordered: elements are not stored in any specific order. Iteration over a map will yield elements in an arbitrary order.

(however some map implementations(TreeMap in Java) maintain order based on keys)

(3) Dynamic Size: maps can grow & shrink dynamically as you add / remove elements. Flexibility allows them to adapt to changing data requirements

(4) Efficient Lookup: provide efficient lookup operations based on keys. Quickly find the value associated with a specific key using methods(get(), []) with an average time complexity of O(1) 

(5) Duplicate Key Handling: attempting to insert a key that already exists will typically overwrite the existing value associated with that key.(however, some map implementations, like multimap in C++, allow storing multiple values for the same key)

(6) Space Complexity: Hash-based maps typically have a space complexity(O(n)) / tree-based maps have a space complexity(O(nlogn))

(7) Time Complexity: Hash-based maps typically have an average time of O(1) / tree-based maps have an average time of O(logn)) + worst case time complexity for tree-based maps is still O(logn)

 

→ ordered vs. unordered

* ordered map: maintains the order in which key-value pairs are inserted(key and value are stored in the node)

: accessing element by key is efficient(typically O(log n)) / iteration over the map(typically O(n), preserves the insertion order)

: use cases(when the order of elements is important)

ex) binary search tree

 

* unordered map: the order in which elements are returned during iteratoin is not guaranteed and may vary across different implementations or executions

: implemented using a hash table / accessing elements by key is very efficient(typically O(1)) / making it faster than an ordered map in most cases / iterating over the map is less efficient than an ordered map(typically O(n))

: use cases(when the order is not important and fast access by key is crucial)

Feature Ordered Map Unordered Map
Order Maintains an insertion order No order
Implementation Self-balacing tree, skip list, BST Hash Table
Access by Key O(logn) O(1) average
Iteration O(n) O(n) (but less efficient than in an ordered map)
Use Cases Order matters, LRU cache Fast access, dictionaries

maps in C++

* C++ offers 2 primary map implementations

(1) std::map) standard ordered map. uses a red-black tree internally for efficient sorting and lookup operations

(2) std::unordered_map) uses a hash table for faster lookup operations.

Feature Ordered Map Unordered Map
Ordering Ordereb based on keys Unordered
Lookup Performance Slower than std::unordered_map Faster than std::map
Memory Overhead Higher due to the red-black tree structure Lower due to the hash table structure
Use Cases when order of elements is important when fast lookup performance is critical

 

 

 

 

maps in Python

techniques

① making a dictionary / change, delete, access

#1
tel = {'jack': 4098, 'sape': 4139}

#2
dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])

#3
dict(sape=4139, guido=4127, jack=4098)

#4
dict({1: 'Geeks', 2: 'For', 3: 'Geeks'})

#using tel dictionary
tel['guido'] = 4127 #add
tel['sape'] = 4111 #change
print(tel) #{'jack': 4098, 'sape': 4111, 'guido': 4127}
print(tel['jack']) #4098 - accessing

print('guido' in tel) # True - check key in a dictionary

del tel['sape'] 
print(tel) #{'jack': 4098, 'guido': 4127}

tel.pop('guido')
print(tel) #{'jack': 4098}

tel.popitem()
print(tel) #{} removes the last inserted key-value pair

 

② looping, sorted, 그 외 여러 dictionary 함수들

→ dictionary를 for loop으로 돌기 위해 dictionary_name.items()를 돌린다.

for k, v in tel.items():
    print(k,v)

'''
jack 4098
sape 4111
guido 4127
'''

 

→ keys()와 values()로 각각 key와 value list 출력

print(tel.keys()) #dict_keys(['jack', 'sape', 'guido'])
print(tel.values()) #dict_values([4098, 4111, 4127])

 

→ sort (dictionary sorting 꼭 기억하기!)

my_dict = {'banana': 3, 'apple': 1, 'orange': 2}

print(sorted(my_dict.items(), key=lambda item: item[1])) #Sorted based on values
#[('apple', 1), ('orange', 2), ('banana', 3)]

print(sorted(my_dict.items(), key=lambda item: item[0])) #Sorted based on keys
#[('apple', 1), ('banana', 3), ('orange', 2)]

print(sorted(my_dict.items(), key=lambda item: item[1], reverse = True)) #Sorted based on values in reverse order
#[('banana', 3), ('orange', 2), ('apple', 1)]

#or
print(sorted(my_dict.items(), key=lambda item: -item[1])) #only applied in numbers
#[('banana', 3), ('orange', 2), ('apple', 1)]

my_dict = {'banana': 1, 'apple': 1, 'orange': 2}
print(sorted(my_dict.items(), key=lambda item: (item[1], item[0]))) #sort based on values then keys
#[('apple', 1), ('banana', 1), ('orange', 2)]

time complexities

★ hash collision이 없다는 가정 하

+ 추가) checking a key in a dictionary(in operator) O(1) Time Complexity


 

'Computer Science > Data Structures' 카테고리의 다른 글

🥪Array & Linked List Intro  (2) 2024.01.08
🌳 Binary Tree 🌳  (1) 2023.12.19
Types of Binary Tree🌲  (0) 2023.01.10
👯Priority Queue(feat. Binary Heap)  (0) 2023.01.09
hash table / hashing  (0) 2022.11.06

댓글