 Hi everybody. In the last video we talked about hashing and hash tables and in this video what I want to do is just code a very basic hash table to put some of these concepts down into practice and then also this is something these concepts will be something you can use again in a future assignment. So I'm going to be coding here. What I would like you to do is just kind of watch and follow along and every so often I will pause and let you know I'm going to pause and that would be your indicator to pause the video and then kind of catch up with whatever you see on the screen. All right? So let me code up first and just kind of follow along with your eyes first and then you can type in shortly. Okay so the first thing I'm going to do is define a class called hash table. This class, every class needs to have a need to, but it should have a class constructor. Okay so I'm creating a hash table data type that I will be able to use from within my Python code. Now under the hood of the hash table I need a place that's actually going to store the values. It's going to have those slots where I can put things into. Now really the way I wanted I can do this in Python is by using an array list. Okay so an array based list. But I don't want you to think about this as a list. I want you to think of it as an array as a continuous block of memory that we're going to take advantage of. Now what I need to do though, remember because a hash table is a nonlinear data structure we're not going to put items in this thing adjacent to one another. We would need to have empty slots and then our hash function is going to determine where in the table we start putting the data. Right so it could go an index 0, it could go an index 11, it could go wherever. But what I will do is I will initialize this list to be empty by saying I want to put the value none in every slot. Okay so how do I do that? Well Python has some syntactic sugar where if I put none in brackets, okay that's saying create a list with the special value none in it, and then I multiply that by an integer. Okay this will make 20 copies of none in a list. Right let's see what this looks like. Let's create a method so that we can print out our hash table and actually see that this is the case. I'm going to define my stir method, my stir dunder method, and all I want it to do is to return the string version of this list. Okay all right so I'll pause a second, let you catch up here and you can pause the video if you like. All right so now let's try this out. Let me create kind of the main area for testing this. So a good practice is to do it like this. Oh terrible typing today. Okay if underscore underscore name equal equal underscore underscore main. This is a way of saying that if we import this module, import this hash table dot pi module into another file, we only want that we don't want this code to run. The code we're about to type in here will only run if we're running this file specifically hash table dot pi. Okay so let me make a new instance of my hash table and I'll print it. Okay and what I should see down here is a list of 20 something nuns. You know what I should move myself so you can actually see it. How's that? So here down here is my hash table and you can see it's kind of just a list. All these slots are empty. Okay but we've got the space there but what would be good is if we could configure the size of our hash table. Right so what I will do is instead of fixing the hash table size at 20 is I'm going to make this a parameter in the constructor that defaults to 20. Okay so this is a default parameter and it defaults to 20. So right now because I'm not calling it with a value I still get size 20 but I could change this. Say I want a hash table with 10 slots. Well here we go hash table with 10 slots. Say I want a hash table with 10 24 slots. Well now I got that too. Okay so um let's just go back to using 20 for now. All right so I've kind of got the structure there. It's ready to go. Now I need to put something in my hash table. Okay so what I will do is I'm going to define a method called put. Remember our goal here with the hash table is we want to put things in the hash table so that we can later get them out in big O of one time. So those are the two operations we care about. Putting things in getting things out. That's really it. Okay and then later also we may want to check to see is the thing in there without getting it. Okay so but first we got to put stuff in. All right. All right so where in our array in our self.table are we going to put something? Okay so put takes a value and where in the world are we going to put something? Well we have to write a hash function in order to figure out which index in the table we want to put it. Okay so let's write that hash function. First thing that we will do here in our put method is we got to hash the value. Okay and that's going to tell us the index in the table where we put it. All right well I need to write this hash method. Whoops excuse me it should be self.hash. Here we go. Of course self.hash does not exist yet. So I'm going to write. Okay so I'm going to hash a value. So what hash method do you want to use? Last time we talked about three hash methods. We talked about modulo, the folding method, and the mid-square method. Let's just do the simplest one. Let's just do modulo. Okay so how are we going to write this? We want to mod the value by the size of the table. Okay so how do I mod the value by the size of the table? Well one of the things I can do very simply is to do return. The hash needs to return something. It's going to return this index of where I need to put it, the hash value, value modded by the length of self.table. Right? This is the modulo function as we defined it. Okay so I'll pause here for a second. Let you catch up this far. All right so now this should give us our index. Now notice we've written our hash function here and it takes a value. This value we're assuming is an integer. Okay that's a pretty big assumption. Right so right now we're just making a hash table that the only thing you can put in it are integers. If we try and put in a string or a float or something else this is going to break. That's okay. Again we're really usually hash tables are only dealing with numbers because almost anything in a computer can be represented as a number or as an integer if you want it to. Okay so now I've got my index back and what I'm going to do is I'm going to I need to put the thing at the index. So that's not so hard. Self.table subindex gets the value. Easy peasy right? Let's try it. Okay so let me let's go down here. Let's put in the value five. Okay I'm going to put in the value five and then print out my hash table and I should see that five has been inserted into slot number five. Right because I hashed the value five, five mod the length of the table. The length of the table is 20 by default. Five mod 20 is five so then self.table sub five gets five. Zero let's go down here to our table. Slot zero one two three four five. There it is. All right let's put in a more interesting value. Let's put in something bigger than the length of the list. Let's put in that. All right remember what a hash function does. It takes something from a great big space potentially infinite number of integers and condenses it down into a fixed space. In this case it's hashing to a value between zero and 20. Let's see where it puts this one. There it is. Slot number one right. Slot zero slot one. Okay so everything's great until right we need to we put something in that's maybe already occupying one of these slots. We don't we don't really necessarily want to overwrite any values that are already in the hash table. So what we should do here before we assign anything in our put method we should check to make sure that the slot is empty first. Okay so let's do this. If self.table sub index is none right that means the slot is empty. Save the value. Okay however there could be it could be the case that all right well if it's not none then there is a value here right. There's a value in this location. It could be that that value is the same one you're trying to insert right so if I call like ht.put5 and ht.put5 that's okay right. We're going to in this case allow it because generally in most implementations in fact I think in yeah in most implementations a hash table can only have one copy of a particular value in it. Okay there are some tricks you could do to have more than one value in which case this would kind of become a bag as the type of data structure that is but usually we only want one copy of a value in a hash table. Okay because remember the main purpose of a hash table is to search and to search in big O of one time. So if the thing's already there fine what we can do is just sort of say else if self.table.index uh equal equal value um well you know what if if the value is already in there you can go ahead and overwrite it right. There's really no harm in that slot is empty or the same save the value. There's not really a ton of harm in this right you might be overwriting something every once in a while but you'll only be overwriting the same value right. If I run this again here's my five he's in still in slot five even though I've put it there twice no problem. The problem is when you encounter a hash collision right so when you've got two different values that map to the same index right so for now let's just print out a warning hash collision oh no right let's make this happen all right so I'll put this up here and I'll pause for a second so you can catch up if you need to okay so uh hash collision well let's see I've put this in my hash table and it winds up at slot number one let me put in one right because of my modulo function when I put one in here that should index to this place so this is a hash collision this guy is already here let's run it hash collision oh no you can see here that when we print it we have not overwritten that value right now what are we going to do when we have hash collisions we still would like this value even though there's a collision we would still like it to be stored in this hash table so what are we going to do we'll talk about that in the next video for now though let's write the other method that we need to write for our hash table which is get right so we want to get the value getting the value is essentially the search right hey give me this value if it's there I should get the value back right if I call get five I want to get the five back but if I call get on a value that's not there what would you expect to get well you would expect to get none okay so this is what we hope to achieve all right this is really easy all you need to do is once again hash the value you're looking for and then return whatever is there so I'm defining get I get my hash value of the thing I'm looking for and I return it right so if the thing is in the hash table I'll get it back if the thing is not in the hash table I'll get none and I know it's not there and by the way the only thing I'm doing here is calling self.hash.value which calls these mathematical computations very fast they go over one okay so let me print out um ht.get five right so what do I expect to see well I should see five when this prints right and here it is I got my five out let's call print ht.get let's say six right six is nowhere in this hash table okay so this should return a none for me and here it is okay cool well how about if I print ht.get one what do you think is going to happen oh I got this well why did I get this well you know my hash value returned slot number one here what's in slot number one this guy huh so ht.get one is not returning what I thought it should okay so why don't I make this a little smarter if self.table subindex equal equals the value that I'm looking for then I found it right return this thing else let me for now just print this warning and I'll say oops value not what I expected so the other value that is okay to return is of course if that uh index has the value none right so if I get back either of these things that's okay but if I get something back from the hash table and it's not what I expected in that slot and it's not none that's a problem so let's run this okay so let's look here so first here's my hash table here's what the values are in it first I got five which is good and I got six which is ooh not so good um nothing there that's okay again we're just doing a check is this thing here then I call get one oops that is not the value I expected right why is this printing none because of oh yeah because because this function what is a function return if it doesn't specify return value it returns none um so why don't I instead of printing that why don't I return that string there we go that's a little bit better um all right cool so this is kind of the basics of a hash table but you know it's not sufficient yet because I've got this problem of hash collisions so the next step is going to be how do I resolve hash collisions and we'll talk about that in the next video