CS50 x 2024 Notes Data structures - 07
​⑴Now, what about other combinations of arrays and linked lists ? We can really start to mash these things up and see what comes out of them.Dictionaries are another abstract data type similar in spirit to stacks and queues in that you can implement them in different ways. A dictionary is a data structure that stores keys and values. And those are technical terms, keys and values. The analog in the human world would be literally a dictionary that you’d have in a classroom, a dictionary with words and definitions, more generally known as keys and values words. So that’s all a dictionary is. It associates keys with values.So, for instance, you could think of it almost as like two columns in a spreadsheet, where on the left you put the key, on the right you put the value. Or, specifically, you put the world in a dictionary and the definition thereafter. And that’s roughly how the printed pages in a dictionary are laid out.So dictionaries associate words with definitions or more generally keys with values. But it’s an abstract data type in that we could implement this in a bunch of ways. We could use maybe two arrays, one array for the keys, one array for the definitions. And you just hope that they line up. Bracket i in this one maps to bracket i in this one. But an array is not going to give us the dynamism that we want. You might run out of space when Merriam-Webster or whoever comes up and adds new words to the English language. You might not want to be using an array. You might want to use a linked list. But, again, linked lists then devolve into big O of n. And that’s not good for dictionaries and spell checking. If you have to check every possible word to find something, getting something that’s a little faster than that is compelling.So let’s consider how maybe Apple, maybe Google, maybe others are actually implementing contacts. Because even though I implied in week 0 and maybe outright said, it’s an array - - it’s a big list of all of your names of contacts maybe of some fixed size - - they probably better be using some variant of a linked list, otherwise you could never add more friends potentially. You’d max out. And they’d say you have to unfriend someone just to fit it. As an aside, this is sort of true in the social media world. Once you have 5000 friends on Facebook, you can’t have 5001. Once you have some number on Linkedln you can’t have more connections. That’s not necessarily that they’re using arrays. But it is the same implication that they’ve chosen some finite size for memory. So how might we consider implementing a dictionary specifically for your address book or your contacts.So you can store the names of everyone ideally alphabetically but also their phone numbers and maybe anything else ?Well, ultimately, we want to be able to get at someone’s name and lead to their number. So the keys and values for our discussion here will be names are the keys and phone numbers are the values. But the values themselves could also include email address and a mailing address and all of that. But we’ll keep it simple, names and phone numbers.​So heres how you might think about this or draw it. On a chalkboard, two columns or in a spreadsheet, left and right. But how could we actually implement this in memory ?Because, ideally we dont want it to devolve into something linear. We dont want to have to look through all of my friends and family and colleagues to find someone whose name starts with z, for instance, or anything else. It would be nice to have something logarithmic with binary search. But with binary search again, we have to maybe use a tree instead. But now we have to use two pointers instead of one theres a lot of trade offs here. But lets see how else we could solve this same problem.Because wouldnt it be nice - - and weve not really talked about this before - - if we instead aspire to this Holy Grail of algorithms ? The best algorithm out there is surely one thats big O of 1, like constant time, because what that means is it doesnt matter if you have 1 friend, 10 friends, 100, 1000, a million, a billion friends - - it doesnt matter how big n is, your searches will always take you the same amount of time. It is independent of n. And thats why its sort of the ultimate goal for performance.So can we get to this aspiration ?Well, a couple of building blocks. Theres this notion in computing known as harshing. And hashing is a technique, literally a function in math or in code that actually takes any number of inputs and maps them to a finite number of outputs. So if you think back to high school math, domains and ranges, you can take an infinite domain with any values in the world. But it reduces them, a hash function to a finite range of specific values.So, for instance, its no accident that we have these four buckets on the stage, now, each of which has a suit from a deck of cards.We got for visibilitys sake the biggest card we can. These are the super jumbo playing cards. And in this box are a bunch of randomly ordered playing cards. And, typically, if you were to ever play some game or you wanted to these for some reason, how would you go about sorting them by suit and also by number ? Odds are if youre like me, youd probably take some shortcuts and maybe pull out all of the hearts, pull out all of the spades, pull out all of the clubs, or you bucketize it into categories. And that term is actually technical.Here are four buckets to make this clear.And, for instance, if the first card I find is the five of hearts, you know what ?Just to make my life easier, Im going to put that into the hearts bucket.Or here we have 4.Here we have 5.Here we have 6. And notice that Im putting these cards into the appropriate buckets. Why ? Because, ultimately, then Im going to have four problems but of smaller size, a 13 size problem, 13, 13, 13. And frankly, its just going to be easier cognitively, daresay algorithmically, to then sort each of the 13 cards in these buckets rather than deal with four suits somehow combined all together. So if youve ever in life made piles - - if youve ever literally used buckets like this, you are harshing. Im taking some number of inputs, 52 in this case. And Im mapping it to a finite number of outputs, 4 in this case. So harshing, again, just takes in inputs and harshes them to output values in this way. So beyond that terminology, lets consider what we can now do with hash functions thats a little more germane to storing things like our friends and family and colleagues in dictionaries.A hash function is just one that does that I as the human was just implementing or behaving like a hash function. But technically a hash function is actually a math function or a function in C or Scratch or soon Python or other languages that takes as input some value, be it a physical card or a name or a number or something else, and outputs some value.And we can use harshing as an operation to implement what well call hash tables. And thats what that dictionary was if you think about how I drew it on the screen as two columns, its like a table of information keys on the left, values on the right. So what is a hash table.The simplest way to think about it is that this is an amalgam, a combination of arrays and linked lists right. We borrowed some ideas of linked lists a moment ago to give us trees in two dimensions. What if we stick with this idea of having two-dimensional worlds but now use an array initially ? So we get the speed benefits of arrays because everythings contiguous. We can do simple arithmetic and jump to the middle or the middle or the middle or the first or the last very easily. And then you know what ? Lets use the horizontal part of the screen to give us linked lists as needed.So, for instance, if the goal at hand is to implement the contracts in my cell phone or my Mac or PC, let me propose that we start at least in English with an array of size 26.Of course, its 0 index. So its really location 0 through 25. And for the sake of discussion, let me propose that location 0 represents A, location 25 represents Z. And then everything else in between. Why We know from C that we can convert thanks to ASCII and Unicode from letters to numbers and back and forth.So in constant time, we can find location A.In constant time, we can find location Z. Why ? Because were using an array just like in week 2.All right, well, suppose that I want to think about these more as letters of the alphabet, the English alphabet rather than numbers. So its equivalent to label them A through Z. And suppose now I want to start adding friends and family and contacts to my address book. How might this book ?Well, if the first one I want to add is Mario - - Marios name starts with an M. And so thats A, B, C, D, E, F - - Ok, M goes there.So Im going to put Mario at that location in the array.After that, I add a second person, for instance, how about Luigi ? Well, L comes just before M. So it stands to reason that it goes there in the array.Meanwhile, if I go and add another character like Peach, shes going to go there a few spots away because her name starts with P.Meanwhile, heres a whole bunch of other Nintendo characters that happen to have unique letters of their first names. And theres room for everyone, room for everyone on the board A through Z with some blanks in the middle. But you can perhaps see where this is going. When and where might a problem arise with this array-based approach ? Yeah, so when we add someone else whos name colides with one of these existing characters, just because by accident, they have a name that starts with the same letter.So, for instance, theres Lakitu here who colides with Luigi potentially.Here is link who colides with both of them. But Ive drawn a solution to this along the way. I could if I was Kronion just remove Luigi from the data structure and put Lakitu in or remove and then put Link in there instead. But thats stupid if you can only have one friend whose name starts with L. Thats just bad design. But what if we now on the off chance I have two friends whose names start with the same letter, well, Ill just string them together, link them together, no pun intended, using pointers of sorts.So my vertical here is an array. And this is just an artists rendition. Theres no actual notion of up, down, left, right in the computers memory. But this is my array always of size 26. And each of the elements in this array are now not a simple number. But its a pointer to a linked list.And if theres nothing there, its just NULL, NULL, NULL, NULL.But, otherwise, its a valid address that points to the first node. And you know what ?If we have multiple names with the same letters, we can just string these nodes together, together, using pointers as well. So a hash table then as implemented here is an array of linked lists. And that allows us to, one, get some speed benefit because look how fast we inserted or found Mario, Luigi and Peach.But it still covers the scenario where, ok, some people can have the same first letters. Some of these names will colide. So collisions are an expected problem with a hash table, whereby two values from some domain happen to map to the same value.And frankly, youll see this here too. So these buckets are technically a finite size. Theyre definitely big enough for 13 cards each. But you could, imagine a world where if Im using 2 decks, 3 decks, or 4 decks, Im going to run out of space. And then my data structure cant fit any more information.But were not going to have this problem here, because the linked lists, as weve seen, can grow and even shrink, as much as they want.In the world of Nintendo theres actually lots of collisions. And these arent even all of the characters. So thats then a hash table. So with a hash table in mind, how fast is it ? Did we achieve that Holy Grail of constant time ?Well, for some of these names if I back up, yeah, its kind of constant time. Yoshi and zelda, boom, constant time, location 24, location 25. Some of then, though, like Luigi, Link, its not quite constant time because I first have to get to Luigis location. And then I have to follow this linked list. So technically then whats the running time of searching a hash table ?Sometimes youll get lucky. But sometimes you wont consider the worst case. Big O is often used to describle worst case. So what would be the worst case in your own context ? And so to summarize in some weird scenario like all of your friends and family and contacts could have names that start with the same letter. And then it doesnt matter that this is a hash table with an array of linked lists. For all intents and purposes, if your friends names only start with the same letter, all you have is a linked lists. Much like with a tree, if you dont keep it balanced, all you have really is a linked lists. So technically speaking, yes, hash tables are big O of n, in the worst case, hash tables are big O of n. Why ? Because it can devolve into this perverse scenario where you just have lots and lots of collisions all at the same values. But theres got to be a way to fix this. How could we chip away at the length of these chains so to speak ? Could I decrease the length of these linked lists. So that with much higher probability theres no collisions ?Well, maybe, the problem is that I started with just 26 buckets.I mean, 4 buckets here, 26 buckets here. Maybe the problem is the size of my array.So what if I instead just give myself a bigger array, and its too big to fit on the screen - - but what if I instead have a dollar for names that start with Laa and Lab, and Lac, Lad, do, dot, dot, all the way down ?Now, when I hash these names into my hash table, Lakitu is going to end up at their own location here. And so now I dont have linked lists. I really just have an array of names. So now Im actually back to constant time. Why ? Because so long as every letter of the alphabet has an ASCII value I can get that in constant time. And we did that as far back as week one. And so I can figure out what the arithmetic location is of each of these buckets just by looking at 1, 2, 3 characters or the total number of letters that I care about, which is just 3 in this case. So this feels like a solution. Even though I havent drawn all the names, it feels like weve solved the problem. But whats the downside or trade off of what weve just done ? Memory.So not pictured here is the dot, dot, dot, and everything above and everything below. This just exploded in terms of the number of locations in this array. Why ? Because if Im taking into account not just the first letter but the first, the second, and third, thats 26 to the third power, 26 times 26 times 26. And even though theres going to be a crazy number of names that just dont exist - - I cant think of a Nintendo character whose name starts with Laa - - you still need that bucket. Why ? Because otherwise, you dont have contiguousness. You cant just arbitrarily label these buckets. If you want to be able to use a function that looks at first, second, third letter and then arithmetically figures out where to go, whether its 0 to 25 or 0 to 26 to the third power minus 1 being the number of buckets there - - So theres a trade off there. Youre wasting a huge amount of memory just to give yourself that time. But that would then give us constant time. So in that sense, if we have an ideal hash function whereby the function ensures that no values colide, we do actually obtain that that Grail of big O of 1 because it only takes one or maybe three steps to find that names location.

相关新闻

核心语法—数据容器

核心语法—数据容器

一 、概述什么是数据容器?根据这三种标准,将数据容器分为五类二、列表list1、介绍列表是数据容器的一类,是一次性可以存储多个数据(元素)的特点:可以存储不同类型的元素,元素有序、可以重复、元…

2026/10/19 2:21:15 阅读更多 →
Apple设备录音后怎么区分发言人?科会通使用手册

Apple设备录音后怎么区分发言人?科会通使用手册

很多人在Apple设备上用系统自带录音功能完成多人会议、访谈记录后,导出音频才发现所有对话混在一起,无法区分不同发言者,逐句手动标注耗时很久,这是日常高频出现的实际问题。核心功能说明以科会通为例,AI声纹智能区分模…

2026/10/9 13:03:23 阅读更多 →
“我可以”的术语大全的庖丁解牛

“我可以”的术语大全的庖丁解牛

总纲:“我可以”不是一句单纯打气的口号,是自我效能感的语言载体。它分为表层情绪呐喊与底层能力确信。很多人误以为“我可以”就是盲目自信;真正的“我可以”,不是认定自己一定赢,而是相信自己有能力面对这件事、扛住…

2026/10/10 22:32:06 阅读更多 →

最新新闻

PyCharm 安装激活全流程避坑指南:从版本选择到环境配置

PyCharm 安装激活全流程避坑指南:从版本选择到环境配置

简介:面向初学Python编程语言或需要重新配置开发环境的人群,这份PyCharm安装教程以Word文档形式,完整梳理了从获取安装包、安装选项配置到激活授权的整个操作链路。文档采用分步骤讲解,先介绍在浏览器搜索入口找到下载页面&#x…

2026/10/19 2:20:36 阅读更多 →
算法分析底层拆解:大O、递归式与平摊分析实战

算法分析底层拆解:大O、递归式与平摊分析实战

简介:这是《数据结构与算法分析(C语言版)》第二版配套的习题解答手册,面向使用该教材学习数据结构、准备考研或希望强化算法基础的程序员与在校学生。全书按章节组织,覆盖算法分析、列表/栈/队列、树、哈希、优先队列、…

2026/10/19 2:20:36 阅读更多 →
8086机器语言解码:字节级译码手记与指令编码实战

8086机器语言解码:字节级译码手记与指令编码实战

简介:这是一份针对8086机器语言解码的浓缩型学习笔记,主题聚焦于为汇编器编写者梳理指令编码规则,适合对x86底层机制、机器码生成或汇编工具实现感兴趣的开发者参考。笔记系统覆盖8086指令格式、16位寄存器、五种寻址模式、操作码与立即数概念…

2026/10/19 2:20:36 阅读更多 →
自动化立体仓库规划:先算清库存、频率与堆垛机周期

自动化立体仓库规划:先算清库存、频率与堆垛机周期

简介:聚焦物流规划领域,这份自动化立体仓库的规划与评估专题文档,面向物流规划工程师、仓储管理人员及相关专业学生,解决立体仓库从方案设计到落地评估的关键问题。文档系统梳理了高层货架与巷道堆垛机作业的核心优势,…

2026/10/19 2:20:36 阅读更多 →
数据结构期末试卷精讲:图、树、查找与排序考点全解析

数据结构期末试卷精讲:图、树、查找与排序考点全解析

简介:湖北大学数据结构期末试卷(2022—2023学年度第一学期A卷)是一份面向“信息安全”专业本科生的闭卷试题,适合备考期末或系统复习数据结构核心章节。卷面设置判断分析、简答与应用分析三类题型,其中判断分析题要求说…

2026/10/19 2:20:36 阅读更多 →
ASP.NET Core 6 Web API 实战:从 CRUD 到 JWT 认证的完整落地指南

ASP.NET Core 6 Web API 实战:从 CRUD 到 JWT 认证的完整落地指南

简介:这是一份面向 .NET 开发者的 ASP.NET Core 6.0 Web API 入门示例资源,演示如何结合 Entity Framework Core 与 RESTful 风格构建数据接口。项目完整包含 Program.cs 服务配置、WeatherForecast 模型、Controllers 控制器、Migrations 数据迁移以及 …

2026/10/19 2:19:36 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →