In the last post we talked about Maps. We learned that Maps can be referred to as dictionaries, associative arrays, etc. Sometimes you will also hear Maps or Sets being referred to as a Hash ( You will hear the likes of HashMaps or HashSets ). These types of key/value pair collections, are “Hash-bashed Data Structures”. What is hashing? In my very first post on data structures, i mentioned that Linked Lists are faster at adding data quicker to a collection, than it is at retrieving. Hashing is a way of storing data that makes retrieval and access extremely fast (Runtime complexity of O(1) for both retrieval, access, and deletion operations). Our collection is stored in a data structure known as a hash-table. This table is what makes data retrieval and storage so fast. When we looked at Maps in the last post (or even linked lists), anytime we wanted to find data, we had to traverse the whole collection in order to find it. Given a key, we would enumerate the whole thing for its value. Therefore it would take a long time we had a huge collection. Hash tables can be used to solve this problem. When using hash tables we can find data in the shortest amount of time because we already know which position in the table the value is stored. Like an array, we can retrieve the value at position 4 instantly. But as we said in the previous post, writing a statement like state does not convey meaning (number index based structure, what if we don’t know its location?). When we tried to solve this problem with maps, we looked at how to write data structures so we could retrieve them using syntax that looked more like this state[‘NY’]. The only disadvantage here is we still would have to enumerate the entire object to get its value (though the syntax was nicer). Hashing employs a technique using something called a hash function. Given a key, it is passed to a function, and a value is returned right away (the key is hashed into a value). That value is used as an array index(in the hash table to retrieve values). The value of the index can be retrieved instantly because of its array nature. Read More
As we journey down the lane of data structures, you may or may not have noticed a pattern for how we access data. Since the underlying data storage we have used have been arrays, we have had to rely heavily on using numeric type indexing to retrieve values. Even though in stacks and queues we were only interested items at the top or front, indirectly we were still using some sort of indexing to get those item values. Also when we did traversals in our data structure, it was based on indexing. While this has served us well, sometimes you want to put more meaning into how you retrieve values. Asking for items, doesn’t really give a clear definition of what is being asked for. In this and the next post, we will be talking about accessing data based on meaningful keys/names. Think of a real world dictionary for example. Every word in a dictionary has a meaning. You can think of a word as a key, and the meaning as a value. So in essence you are using one unique word to look up a meaning. A key mapped to a value ( key/value pairs). Notice that dictionaries do not have duplicate keys. If you need the meaning for a word, for e.g engineer, you will not find the key twice. You may however find multiple meanings under that key word. Lets think of another scenario where you might want to use a dictionary. What if you wanted a data structure where you could find a state name based on abbreviation? Like NY (key) for New York (value), or CA for California. We are not using an index here. We might access it like this instead state[“NY”]. We are using a unique identifier to refer to a particular state. This is when we use the dictionary data structure. Dictionaries are also referred to as maps, and may be the preferred word to use depending on the programming language. Dictionaries, associative arrays, maps, … they all mean the same thing! We will be referring to them as maps from now on.
In the previous post on singly and doubly linked lists, recall that the collections last nodes next pointers were always NULL. This is because they had nothing to point to. But what if this is not what we wanted? What if when we get to the last node, we wanted to point the next pointer back to the head node, like a photo gallery application (when we get to the last picture, the next picture should be the first). This is where circular linked lists come from (they allow us to rotate through our collection). This means that circular linked lists have no end. One must be careful if they are going to iterate through the collection, or you could end up in an infinite loop.
So in a circular linked list, there are no nodes with a NULL pointer. For eg, in a case where there is only one node (the head node), the next pointer points back to the itself. Remember in previous posts that i said when a collection is empty and you add a new node, their next and previous pointers are NULL? Well in this type of linked list, they point back to itself, well until we change its pointers.
What about the previous node of the head? Remember it was NULL in previous posts? There is another type of linked list called doubly circular linked list (i know, the names are getting ridiculous). In a doubly circular linked list, the previous pointer of the head points to the tail node. Lets look at a diagram. Read More