斯坦福-CS106A-B-L-X-编程入门笔记-十-
斯坦福 CS106A/B/L/X 编程入门笔记(十)
【编程抽象方法 cs106x 2017】斯坦福—中英字幕 - P2:Lecture 02 - Functions - 加加zero - BV1By411h75g
好啦,我们何不现在就开始呢?欢迎回来看你,我有点糊涂了,我想我星期一已经说得很清楚了,你也应该离开这里,当你还不能,任何理智的人都没有理由留在这个班,但我很高兴今天有你们这些疯子和我在一起,嗯快速宣布。
星期一我有一件事没有说清楚,你知道我们每周有一次讨论,你下周要去开始,我也没说过你是怎么进入这些的,你怎么报名参加那些,你不能通过正常的在线系统这样做,就像访问或简单的注册,我们有自己的表格。
这将从明天开始在我们的网站上公布,星期四,当它上升的时候我会给你们所有人发邮件,我会在周四到下周一之间在我们班的网页上发布一个公告,你需要进入那个表格,你需要告诉我们什么时候,你可以去部门。
我们会把你分配到,所以事情就是这样发展的,明天就上去了,我现在会给你发一封关于这件事的电子邮件,你什么都不用做,如果你想和某人合作,在这门课的结对作业中,你应该试着和他们进入同一个区。
因为搭档必须在同一个区,所以我们的表格会问你,如果你有朋友,我们会试着把你和你的朋友放在同一个区,好啦,是啊,是啊,所以我想继续上次我们谈论的地方,C加加我没走多远,我今天要努力弥补。
所以C++加上很多语法和Java没有什么不同,我知道这里不是每个人都懂Java,但如果你做了很多,这对你来说就像Java,我想说,如果你仔细寻找差异,我想你可能会注意到,有一个东西说谷歌。
那在Java中叫什么,你知不知道,意思是它和逻辑数据类型完全一样,真假,你可以用它来,if语句或while循环,或者这种东西,他们称之为C++规则,C++通常有较短的名称,Java有很长的名字。
C++加上循环的短名称,如果语句,很多都是完全相同的语法,我是说这不是巧合,爪哇大部分是剽窃的,他们的语言很大程度上建立在C++的基础上,这就是为什么它们是如此相似的循环,如果语句结束,OR等于。
不等于,除以返回参数函数,许多语法通常对您来说应该很熟悉,所以我们开始写简单的程序,我们开始的程序。
让我让我去可爱的创造者一秒钟,所以这是一个典型的程序,你会说,看出去,你好,CS一零六x,然后你会说结束l和l是这条线的结束,这是一个典型的最小c+程序,我们讨论了大部分的作品,这是你的主要功能。
这是一条将输出发送到控制台的语句,罚款,这些陈述我讲了一点,我想再多说一点,所以它们包含的语句很像。
Java或Python中所谓的导入语句,或者其他很多语言,这是当您想要将库连接到您的程序时,嗯,有两种图书馆,有语言库和项目库,语言库就像是C++语言的一部分,如果安装C Plus Plus编译器。
你得到这些库,项目库是我从斯坦福大学给你的,所以我们有一个稍微不同的语法,它告诉编译器在哪里查找它们,它应该在您的项目文件夹中查找吗,或者它应该查看c plus编译器安装文件夹,我尽量把它说清楚。
当我向你展示一些语法或库功能或其他什么时,我会试着向你展示你必须包括的确切库,为了得到这些特征,所以有两种语法,有点奇怪,但这就是它的工作原理,例如,有一个内置的语言库叫做i o stream。
有透视功能的,您必须包括它才能打印到控制台,还有一个来自斯坦福大学的图书馆,叫做G窗口,你必须把它放在引号里,如果要弹出图形窗口,好啦,包括图书馆,在节目的顶部还有另一个声明,也就是说。
使用名称空间STD,名称空间是变量的作用域,哦耶,问题继续,你得先指向目录,所以我们要去工作,问题是,如果是本地图书馆,我必须像斜杠一样写目录吗,不管是什么斜线,嗯一般没有,它将在您的文件目录中查找。
如果它不在同一个目录中,您可以为它指定要查看的其他路径,我们设置我们的项目来查看特定的文件夹层次结构,因此,当您下载要处理的项目时,所有这些都应该为您设置,但如果你从零开始,你可能得告诉它目录在哪里。
对于您拥有的库,所以这个命名空间的想法,名称空间基本上是名称作用域的分离,函数名称,变量名称,类名称,我们在C++语言中有这个概念的原因是因为你知道。
C++有很多简短的标识符,比如see out,你知道的,如果C输出是用来打印东西的,这意味着您不能将变量C命名为,因为这会与,你对同一个名字的使用会有冲突。
所以C++试图通过这些不同的名称空间来解决这个问题,可以在两个不同的名称空间中使用相同的名称,一切都会好的,在这门课上,你不必想太多,您可以使用need空间在程序中编写语句,所以你要把所有的名字。
在那个命名空间中的东西,您希望在您的程序中可以访问它们,例如。
这个名为um see out的标识符是它的全名,其实是性病结肠,冒号c是那个变量的全名,它是一个名为c out的变量,位于STD命名空间中,但如果我们要经常用这个,这真的是一个主题。
如果您说使用名称空间STD,有点像进口,从某种意义上说,我不必写那个命名空间的名称,在那个面前,所以我认为有一件事让学生感到困惑,那就是,为什么我必须说这两个,好像他们在谈论同样的事情。
它们都涉及到把一些外部的东西带到我的程序中,我想说的是这包括,这样我就可以在所有这些使用语句的情况下使用c out,这样我就可以用更短的,我不用写那么多字,所以我们通常会把这两个都写在我们的代码中。
是啊,是啊,这是否意味着一次只能使用一个名称空间,或者你可以有几个空间,然后像这样的线条在顶部,是啊,是啊,您可以使用多个命名空间吗,我想你可以用不止一个,问题是什么,如果两者都有相同的变量。
他们可以冲突,所以这有点复杂,我不想详述它的所有细节,但是是的,我是说你可以做到,事实上,我可以在代码中编写自己的命名空间,你知道我可以做一些,你知道的,命名空间foo,然后我可以说像int x。
然后在缅因州,我可以说foo冒号冒号x,现在这是一个只存在于foo中的x,但如果我只写X,它不会和那个X冲突,现在可以有两个X,所以我的意思是我不想走得太远,使用这些名称空间,但这就像是语言用来允许。
重用函数、变量和事物的名称,而不使它们相互冲突,using名称空间语句只适用于块范围还是望远镜,一旦你在档案里这么说,文件的其余部分现在可以访问该命名空间,由于汇编的工作方式。
有时这意味着其他文件也可以看到命名空间,所以有一个常见的bug发生在你有两个文件的地方,其中一个说使用名称空间,另一个没有含蓄地说,希望使用命名空间,因为他们都在同一个项目里,它的工作原理。
但是如果你把一个文件和另一个分开,突然相同的程序不再编译了,所以有些规则有点奇怪,嗯,它可能是,事实上,有C++程序员有一个规则,他们从不写使用语句,他们总是把所有东西的全名都写下来。
但我只是我不能让自己这么做,所以我不是,我不是这样滚的,但不管你知道什么,如果我把使用语句拿出来,我再编译一次,它其实,我不知道你不能读这篇课文,但它说看看它是如何不在这个范围内声明的。
所以我可以通过说性病出来来恢复工作,然后它就起作用了,我也有性病,所以我可以让他们有全名,相比之下,如果我拿走了包括,但我的使用声明也不起作用,因为就像现在,它甚至没有把我和大海图书馆联系起来。
不管我叫它什么,它不在那里,所以这有点像,这两件事经常同时发生,好啦,所以这些是进口和使用,是啊,是啊,只有在有两种可能的情况下,我们才不必使用名称空间,两人都是对的,你不必写性病前缀。
如果您写了一个using语句,如果您没有使用语句,你一定要写得像,如果我删除第7行,我无法看到外面,它不会明白的,只有写这个,它允许我在没有前缀的情况下提到性病的成员吗,我将始终使用名称空间STD。
我将包括图书馆,所以我不打算用冒号冒号语法。
但我只是想让你知道,它在那里,所以我们讨论了,查看打印语句,我不打算呆在这张幻灯片上,因为我们已经谈过了,所以一个简单的例子,就像你可能想写的一个小程序,你知道的,问用户谁得了多少币。
然后打印谁赢了足球赛,或者类似的东西对吧,所以这个蓝色的部分就像,我提示用户键入一个值,类似于控制台的输入,所以如果你胡乱猜测,如果我使用C输出,你认为我用什么来输入,你们前任真聪明,是啊,是啊。
我是说这是对的,有一个C,但我有个坏消息要告诉你,CN烂透了,这和看到外面没有什么不同,我是说你看,你要这么做,你说再见你说,请告诉我你的年龄,然后你说看,然后你告诉它什么变量,你想把它储存在。
它会从用户那里读取p,并把它放在那个变量中,有趣的语法,嗯,很多学生在坐网上混了,但就像箭一样,你知道的,进入那个变量,我不知道,我不知道你想用什么记忆法,但这很有效,你叫他们输入年龄。
它等着他们输入年龄,它将其存储在那个变量中,然后打印值,它打印出他们输入的内容,所以它说气馁,我还没解释为什么,是这样的,但这个有用这个可能有用,是啊,是啊,你颠倒操作员的顺序和方向,所以颠倒一下。
你能变老吗,然后是小于小于,啊,我看得很像,也许把这两条线变成一条线,你看到了吗?没有,我稍后会讨论这个问题,在今天的讲座中,你必须声明一个变量,然后你必须把c写进去,在这个变量上有一个箭头。
你不能喜欢,在同一上声明这一点,同一行上的这个变量,你想储存在里面,这和,所谓的参考变量,我一两分钟后给你看,但这是一种方式,你必须说出来,如果你想做C N小发明,嗯是的,可以继续看看,处理它。
如果你传错了,它是做什么的,如果你打错了,一种价值,就像你不输入你的年龄,你输入马蒂什么的,它不是int,它是做什么的,是啊,是啊,这也是为什么不鼓励这样做的部分原因,所以让我,呃,回答这个问题。
尝试正确,所以我们应该说他们得对了多少分,所以这并不难。
所以就像,你知道的,看出去,站第三分得分问号,我不会结束我,因为我希望光标与,所以我会像在斯坦福一样,逗号卡尔,然后在斯坦福看到对吧,然后也许我会做,然后我想做什么就做什么,如果斯坦福比卡尔大。
看到了耶,我不需要其他人,因为我们永远达不到那个案子,我不知道,我们不浪费任何时间在一个零六X,我们不需要写别的,但就像这样,我运行程序,哦对不起,其实我想给你看点东西,所以如果你有锐利的眼睛。
我运行了程序然后在这个小盒子里,上面说斯坦福的分数,因为这是默认的,像C Plus的控制台,这并不奏效,而且不是很灵活,所以我们实际上有一个库,我们链接到,在我们所有的项目中,你会想要使用。
我们说包括控制台点H,这是一个很酷的图书馆,只是把它包括在内,这就是你现在要做的,你运行相同的程序,控制台弹出作为自己的窗口,那是斯坦福的小发明,这就是为什么它有引号,而不是上面的括号,所以无论如何。
那是斯坦福的事,但我们要利用这一点,上面说斯坦福的分数,所以我打字,你知道的,15分,卡尔得了7分什么的,耶,我们赢了所以现在,我来回答他的问题,斯坦福积分收获满分,似乎接受了卡尔分数,我不知道十个。
你只要把a作为第一个输入,然后这个,是啊,是啊,所以实际上,我试着打字,它甚至不让我给卡尔打分数,因为在幕后,它读到了斯坦福大学的分数,和卡尔的分数一样多,你说的是什么?嗯,让我们一探究竟。
让我们一探究竟,到卡尔,你知道的,我只是在重复他们打的内容,那是很简单的事,所以让我打很多点,比分是0比3 2,我不认为的是,所以他们的跑位不是很好来吧,呃,你什么意思,所以它是,它是。
它给了我这些奇怪的价值观,基本上长话短说,如果你把错误的值放进去,它无法转换,因此它不会在这些变量中存储任何值,所以这些语句失败了,没有分配任何东西,所以这就提出了一个有趣的问题,嗯,这些有什么价值。
如果你不给他们任何价值,我给你看看这个,什么,如果我把这个评论出来,所以我从来没有读过任何东西,所以让我们看看我们得到了什么,比分是0比1,等一下,什么,什么什么,呃,让我们,我们再试一次,嗯。
比分是0比1,嗯,基本上,如果你不在C中初始化一个变量,另外,它有一个随机的垃圾值,所以我们从不储存任何东西,我们只是打印,我们得到各种各样的东西出现在屏幕上,所以不管怎样,听着,这个节目很好。
但它处理得不太好,用户正确键入虚假值的情况,所以让我给你看一些更好的东西。
哦耶,问题,在你知道之前就去吧,在任何函数中定义变量和全局,它有默认值,差不多是零,是吗,是啊,是啊,问题就像在某些语言或上下文中,变量将获得类似于默认值的值,就像在一些语言中的零。
比如Java和其他语言,这是真的,这是真的原因是因为它在C中不是真的,加号加号,当他们制作Java时,这是如此令人沮丧,他们就像啊,使所有变量为零,求求你了,所以这种语言没有,你说得很对,在Java中。
如果你不初始化东西,它们有时会得到默认值,他们会得到零什么的或者空,这种东西C++,当你做一个变量,我想你们可能还记得变量就像一小块记忆,某处,这个想法就像在你的程序出现之前,在那段记忆中还有别的东西。
所以不管那里有什么,我们只是把它当作一个int,这就是你的价值,如果你不给它一个值,它只是用它作为值,所以我的意思是无论如何,C++不会为您初始化东西,因此它们包含随机垃圾。
有时如果你重新运行相同的程序,你得到同样的随机垃圾,因为您的程序碰巧加载到与以前相同的内存地址中,但是是的,未初始化的变量是坏的,反正,cn有很多问题,哦耶,问题继续,我想如果你为整数写字符串。
然后取第一个字符并使用它,哦,好好利用ASCII值,您可能会想到C语言中的C语言,有一些字符到整数的转换,今天晚些时候我要谈谈弦,我也许能解决这个问题,嗯,我是说,长话短说,如果你这样做。
他们不打在里面,只是中止并且不给,这就是为什么,有一些背景,在那里会发生一些奇怪的事情,就像你在问,我们可能会稍微讨论一下,但我只想说总结是,我认为你不应该这样直接用cn,我觉得你应该做的是。
我们在斯坦福有个图书馆,称为简单,伊诺,有这些功能,你可以像get整数一样调用,得到实数,或者像个替身,得到一条线,就像一根弦,不同的人得到一个恶霸,我说是还是不是问题,它将重新提示,直到它得到一个值。
那是正确的类型。
然后它会把它还给你,所以如果你想让这个总是得到有效的分数。
与其这么说,你实际上把这两条线都替换掉,提示消息的打印和答案的阅读是,你说,斯坦福得分,实际上说国际斯坦福,然后我会说int cal等于,获取整数,卡尔得分很低,然后耶,所以实际上要做到这一点。
我得把这个舔狗,IO点H所以现在我编译,我跑步,我得了多少分,那是个非法整数,好啦,八十七卡怎么样,你知道他们有保险什么的,好啦,所以它不断地提示,如果需要,所以说,那是我的建议,现在呢。
我会说有些学生不喜欢用东西,那不是语言的一部分,这是斯坦福的事,如果你到了现实世界,和新的C+Plus,你没有这个功能,所以如果有人说我不想那么做,我想做真正的事情,那很棒,但我的意思是。
如果要读取整数并重新提示,你基本上编写了我们为此编写的确切代码,这不是很有趣的代码,所以如果你想看看这东西是怎么工作的,去吧,没那么有趣,我不认为这是我想在这门课上关注的,我只想继续讨论更有趣的问题。
所以是的,问题是有一份斯坦福大学的名单吗,我们可以在线访问的本地目录。
是的,所以我有一个幻灯片,让我看看这是不是在下一张幻灯片上,所以在班级网页和顶部的链接栏上,有一个链接说斯坦福图书馆,我无法加载Web,但不知何故,我的互联网今天坏了,所以你必须,我要跳一段。
这里的互联网是什么样子的,所以嗯,去班级网站,顶部有一个链接,上面写着斯坦福图书馆,它有一个列表,列出了我们所有不同的功能和所有不同的库,如果你想看的话,这是同一个文档的直接链接,所以如果你想看的话。
都在那里。
好啦,是啊,是啊,所以我想继续前进,上一节课的幻灯片讲完了。
看看我落后了多远,但是哦,好吧。
所以我想谈几个新的话题,我今天想谈谈函数和字符串,我想你们可能都已经知道函数和字符串了,用你自己喜欢的语言,所以我会试着把注意力集中在,C++中的这些东西有什么不同,如果您不知道什么是函数或方法。
也不知道什么是字符串,那么这些都是话题,我希望从你那里得到必要的知识,所以你得去看看,如果你想读课本的第二章和第三章,好啦,所以函数,你们知道函数和方法非常有用,对呀。
我的意思是你可以把一组语句放到一个函数中,然后调用函数,它运行的语句很好,你可以把参数,你可以退货,C++中的语法或函数与C++中的语法非常相似,用另一种语言,就像Java中的Java。
可能会有一些其他的东西在左边这里右边,就像Java中可能存在的东西,公私静态,喜欢修饰语,像那样的词,如果是Python或其他语言,你可能会说像def,或者在这里工作,或者类似的东西,但是是的。
在Java中,你在这里放了更多的修饰符,但是你知道,如果你把这些剥掉,在这个上下文中,C++之后的语法看起来非常相似,没有一些公共和私人的概念,完全一样,所以你可以写一个函数,然后你的main函数。
所以这很简单,你们知道调用函数,其中一点o向上变成r,它做计算,它在这里返回结果的来源,因此,作为回报,预告片的行为方式与您对Java的期望相同,暂时,在C加+中,在程序中调用函数后,是否允许定义函数。
是啊,是啊,我会告诉你,你问的是定义函数的顺序,在顺序上更重要,C++比Java,所以我得给你看我的下一张幻灯片,我想我们会解决这个问题,让我给我点时间,我给你看,我们知道平方数,你能平方一个数字吗。
啊,有一个平方函数,有一个,有一个指数,我只是还没给你看,所以说,我不想喜欢惊喜的功能,我从来没有提到过,当然就像,如果你想做r乘以r的次方,有一个幂函数,因为这样你就可以通过。
你能把函数作为参数传递吗,是啊,是啊,这是很酷的东西,那个Java没有那个,C++确实有,有函数指针,我会谈谈他们,我今天不打算谈他们,虽然,因为那是在更远的地方,但是是的,那是一个强大的东西。
你说的地方,这里有一个函数,我想让你稍后帮我调用这个函数,是的,是的,回电是一种术语,当您定义一个类或强进程时,可以是私有的或公共的,是啊,是啊,我要进去了,我觉得,第三或四周,我要和你们谈谈类和对象。
当你做一个类,您可以用C++创建类,当你做的时候,你可以把事情公之于众,你可以把事情保密,但在某种程度上,我们称之为自由浮动的功能上下文,像这样,我们真的没有私人或公共的概念,它们只是功能。
所以我们在这里不用这些词,但我们会在其他时候用这些词,是啊,是啊,所以要不要用那个,你传递的值是1而不是一个零,它仍然被视为魔鬼或被视为,是啊,是啊,我想很多语言在这里都有非常相似的类型转换规则。
就像如果你只说一个int,但它知道如何自动将其转换为一个点零的倍数,所以有些语言超级挑剔,他们会给你一个错误,这更像Java或Python,它会帮你变成双倍,所以一切都会好的,所以这是一个函数。
这应该会很冷,挺好挺好,好像这并不让你惊讶,我没有想太多,嗯,让我们进入不同的东西,所以C++允许你做所谓的默认值,对于参数,当您声明函数时,你可以在等号后面加上一个值,这将意味着,当他们调用函数时。
然后给出对函数的调用,如果他们不提供价值,它将使用您的默认值,有点酷,所以这是一个愚蠢的例子,但这就像印刷品一样,对齐,多少份,什么字好,不管你告诉我多少份,我要印那个字,所以如果你说打印第七行,问号。
它会打印这个,如果你说打印第五行,但你没说是什么角色,它会印星星,如果你什么都不说,它会假装星星,嗯,这个语法有一点微妙之处,就像你不允许有一些带有默认值的参数,然后一些没有默认值的。
然后一些有默认值的人,比如你不能这样做,因为它很难找出哪个值映射,到哪个参数,就像所有默认的,有这些相等的,必须位于函数参数列表的末尾,但这是c的一个可爱的小特性,再加上,再加上,Java没有这个。
布彻,如果你有两个,默认情况下,是否有一种方法可以省略第一个,但仍然给出一个值,是啊,是啊,不幸的是没有,如果这两个都是默认的,没有办法通过这个而不通过那个,你只要写一个十,基本上,所以我的意思是。
这是其中的一件事,就像有些语言有办法做到这一点,但是c+没有,因为参数值仅由它们的顺序指示,所以它无法消除这些,还有别的问题吗,或者同样的问题,好啦,只是为了检查调用参数是否应该在,是啊,是啊。
就像如果你有八个参数,你想要其中的两三个是默认的,你把这两三个当成最后一个,两三个,好啦,现在有点酷了,几分钟前,您有一个关于声明函数的顺序的问题,所以是的,这是个问题,这是我的第一次展览。
在控方的案件中,c+很烂,你知道我几乎从不发誓,所以我不会这么说,如果你把函数放在缅因州之后,愚蠢的编译器找不到函数,它实际上不会编译,它会说这里没有叫圆的函数,就在那儿,但我找不到,所以嗯。
这真的很糟糕,我只是不敢相信他们搞砸了,这太蠢了,但一切都得先声明或定义,它用于垂直遍历代码,所以你,如果你用Java或Python什么的。
事实并非如此,C++就是这种情况,就像,例如,在这里,就像,我只是要把我所有的例子都转储到这里的同一个文件中,基本上,但是你知道,如果我有某种函数叫做,你知道的,虚空之歌,它只是打印一首歌的歌词。
你知道的,天翻地覆,我不打算打这首歌,我保证,所以无论我打印一些歌词,如果我上来,我说这首歌看起来很好,但我编译了它,它说你不能读它,但它说宋不在这个范围内声明,哦,天哪,所以你可以做的一件事是。
你可以把这个剪下来贴起来,上面的main使这个函数是第一个,但我不喜欢那样,因为我喜欢先吃主食,我喜欢选择自己的顺序来申报事情,我真的很喜欢打开文件看看主要的。
所以没关系,你能做到的,但你只需要做一个小小的改变,也就是说,你必须把一个叫做函数原型的东西放在上面的文件中,原型是函数的标题,在这里写出名称、参数和返回类型,但你不能把大括号或身体,你只要加一个分号。
这就像是给编译器的借条,我保证以后我会写这个函数,这允许编译器向前移动,如果我看到你有一个圆的面积,在这里保证,那么如果你叫圆面积,我相信你,最终,啊,有一个圆形区域,好吧,酷,然后代码是OK的。
我真不敢相信你要这么做,这太蠢了,但事情就是这样。
就像这里一样,如果我想调用这首歌的函数,我可以上来,我的意思是,我总是做的是,我只是在卷曲之前抓住这个部分,然后我只说分号,现在事情汇编,现在它运行,它打印了歌曲的开头,可能是的。
问题是我有一大堆函数原型,你能把它们放在另一个文件里吗,然后向右,所以有些人做的就是,如果它们有一大堆功能,接下来发生的是,您的文件顶部以,就像一大堆这样的原型,看起来有点丑,你知道不是同一个。
但许多不同的开始变得丑陋,所以有时候你开始把东西分成多个文件,你把所有的原型放在一个文件里,该文件通常以点H扩展名结尾,这些是函数的标题,这是它的来源,我今天不打算那么做,但那是你。
如果你写一个更大的程序,你肯定会这么做,把它分开,所以当你把不同的文件,如果连顶点都是这样,为什么不直接像导入函数一样,啊,原型有什么意义,就像,如果您有两个文件,并且导入另一个文件。
我想给你一个挥手的解释,就像,基本上发生的是,如果喜欢这个文件导入那个文件,它实际上复制了所有函数的第二个副本,如,包括字面上的复制粘贴,它从字面上进入这个文件,复制所有的行并粘贴在那里。
所以最终发生的是,如果你有两个文件,第一个包括第二个,然后将它们绑定到一个可执行文件中,你实际上有第二份文件的两份副本,这不起作用,因为他们彼此冲突,只是很奇怪,就像这种愚蠢的东西。
C++完成二进制数据的编译和链接,就像我只是我讨厌陷入杂草,这是你在七个中的一个做得更多的事情,挺有意思的,但这大多只是一种痛苦,因为您的程序没有正确构建,或者别的什么,所以我们最终做的是。
我们用这些原型,所以每个人都可以调用函数,然后其中一个文件写入函数的定义,当编译器将所有这些链接在一起时,一切都解决了,所以是的,问题,如何在,哦,可选的,如果您有可选参数,就像你知道就像。
也许你说喜欢,像这样的国际时代,对于int i等于零,您想打印多少次,我比i加+的次数少,所以我会打印这首歌,不管你说多少次,然后你知道你可以说我想让这首歌出现十次对。
所以在这里你有时会说这样它们就会互相匹配,但是如何执行默认参数,如果你把原型和身体分开,你只在原型中设置默认值,你就是这么做的,然后这里,如果我说,无参数歌曲,它将印刷这首歌的五份副本,一个原型。
你知道正常的函数可以在这两种情况下定义为默认,如果你有一个原型和一个身体,我可以把等于5的数字放在这里吗,我相信它有一个错误,如果您重述,你也会认为你可以在这里说等于5,但我想它会生气,是啊,是啊。
它说已经给出了一个默认参数,什么的,是啊,是啊,它不喜欢那样,所以我不知道,我是说你看,这是一种愚蠢的语言,我是说,对不起,我讨厌C加+,我们会活下来的,我们要用它,教这门课不会是我的第一选择。
但没人问我,所以显然我得教你指点什么的,所以我得教你C++,但我不喜欢C加,我不用c加,赚大钱的人,不需要知道C加加,但它是一辆车,我们要学一些很酷的东西,刚好是c+。
好啦,所以这是一个原型,这里只是,这是一种随机幻灯片,就像有一个数学库,里面有一堆有用的数学函数,你问我如何平方一个数字,而且是的,你可以,如果算上C数学,你可以做力量,不管这个指数。
所以所有这些函数都取这些参数,他们返回结果,你知道他们大多数人都把双倍作为他们的参数,但你可以通过它转换的瞬间,所以我不会在这上面花任何时间,因为无论你学什么语言,您可能已经在Java中做过类似的事情。
我想你说数学点战俘,数学点腹肌,就像,基本上是一样的想法,你只是不说数学点,你只要说腹肌,是呀,让我们说那些事情,是呀,问得好,你问了命名空间,其实呢,那是我的幻灯片并不总是很清楚的一个地方。
所有这些函数都在std命名空间中,就像C调一样,如果我没说用,我不得不说性病结肠腹肌,性病结肠,怎么会呢,我已经习惯了使用性病命名空间,因为里面有很多东西,来自标准库,就像。
基本上他们所有的东西都在里面,就像我一样,你知道的,所有这些东西开始给你错误,如果你把这句话去掉,所以好吧,哦耶,问题是的,去吧,所以这是否意味着如果你有,假设我有命名空间必须在我的一个文件中。
我进口它,这是否意味着它与所有其他性病名称空间合并,我不知道我是否完全理解你的问题,我是说使用名称空间不像复制粘贴,就像include是复制粘贴一样,使用名称空间更像是一组快捷方式,它明白还是不明白。
如果您的一个文件说它使用STD命名空间,另一个有,它们不会以不好的方式相互复制和碰撞,这只是意味着这两个文件都可以使用那些较短的名称,引用那些变量和函数,如果一个文件使用了性病而另一个没有。
另一个可能不会用那些短名字,所以我不知道我是否正确地回答了你的问题,我是不是有点没听懂你的意思,你应该多拍马屁,像你聪明的回答一样,不是我问题的答案,不不不帮帮我,但告诉我伙计们。
所以你是说我会你包括蒸汽,这些都还在性病名字空间里,所以这是不是意味着像,也像一个IO流,这些也是肯定的,那也是,如果这些是在不同的文件中定义的,那是不是意味着他们都是。
它们都具有所有这些部门的名称空间std,右右,如果你打开这些的源代码,它们从一行开始,上面写着名称空间STD,卷曲制动器,然后这些函数的所有实现,然后最后一个卷曲,两个文件都有。
现在我想我知道你在说什么了,两个不同的文件都有名称相同的命名空间块是可能的,它会把它们结合在一起,又不是说,其中一个是命名空间,另一个不是,或者它们碰撞,它们都成为其中的一部分,谢谢夸奖。
我永远不会离开你,所以在这种情况下,你只需要解释两个独立的库,宣布你的书将进入同样的空间,C Plus如何解决命名空间冲突,C Plus如何解决名称空间之间的冲突,我是说我要告诉你。
我真的不记得所有的规则,但这也应该让你感到安慰,我不该安慰你,我不称职,但这是什么,我从来没有关心过,这就是重点,你可能也不必在乎,东西很少碰撞,因为,就像和性病名字冲突的人,他们就像,哦,天哪。
每个人都使用命名空间STD,所以我不想和它发生冲突,所以他们取了一个不同的名字,那么它实际上是做什么的呢,我忘了,我想如果它模棱两可,这是个错误,但有些情况下他们中的一个赢了,所以它用那个,坦率地说。
规则有点疯狂,就像我有一次,我就像啊,去他的,我不知道,有时这取决于什么顺序,你说你在利用他们,有时这取决于什么文件链接到什么其他文件取决于符号是什么,看情况,如果它能消除他们之间的歧义,有点乱。
所以有些人真的,你知道的,把这些都弄到杂草里去,我不觉得把所有的东西都背下来很有趣,所以如果我有问题,我只是诚实地查了一下,所以我不,我其实不是这样的,如果这里的所有这些函数都在STD命名空间中。
那为什么还要用现场,如果你说使用命名空间,那并不意味着,我想将该名称空间的所有内容带入我的程序,意思是如果我碰巧提到一个名字,编译器在我的文件中找不到那个名字,它还应该检查STD名称空间。
看看是否有那个东西,但如果我不包括CMAT,这些函数没有附加到我的代码中,所以它不会在那里找到他们,所以这有点微妙,但这就是它的工作原理,你申报一个,你们喜欢命名空间,你知道吗,我从来没有见过他。
不是我们所有人都在那里,我从没见过这么专业的人,我喜欢它,你们喜欢把一切都分开,我打赌你们宿舍里都有独立的冰箱,这是我的命名空间,别碰我的东西,对不起,呃,所以我想你是在问,您可以有多个命名空间吗。
还是全部放在一个全局命名空间中,我是说,如果你不申报,您是全局命名空间的一部分,这就是我们一直在写的所有程序都是全球性的,如果您确实有一个带有卷曲的命名空间块,然后该代码将位于该名称空间中的单个文件中。
您可以在这个命名空间中拥有一个部分,在命名空间中的一部分,其中一部分是全球性的,你可以混合搭配所有这些东西,我觉得总的来说,我不打算问,你们写了很多命名空间的东西,在本课程中。
您必须对名称空间有一点流利的理解,包括你将要使用的其他地方的东西,但是编写自己的命名空间会更,如果你在一个更大的项目上工作,你会做的事情,你有很多文件,很多人你会想把事情分开,不管怎样。
我想谈谈值和引用语义,你们知道这个,但你可能不知道它的名字,值语义意味着当您传递参数时,它复制值,所以如果我有一个交换函数,你给我A和B,我就换了它们的值,我移动结束,我说的值就是这些值。
然后我把温度放回B,所以我交换了这两个值,对呀,那么下面我可以有两个,我也在他们身上,然后我把它们打印出来,它没有交换,你看它还是一样的,我知道你总是看不到幻灯片的底部,但基本上没有,它没有做到这一点。
交换在缅因州不起作用,原因是,我想你们应该知道当我传递x和y作为参数时,它不喜欢将这个函数链接到我的变量,为什么它只是获取这些变量的值,它把这些值放入这些,然后它使用这些值运行函数。
这就是价值语义学的含义,你已经做了一千次了,认为这是理所当然的,当你像这样传递参数时,它总是这样工作的吗,什么时候不是这样,是啊,是啊,对于多种语言中的对象,如果将对象作为参数传递。
则对象具有不同的行为,就像数组列表之类的,如果修改函数中的列表,您将在主右看到更改,所以这很有趣,那是另一种叫做引用语义的东西,所以在很多语言中,当涉及到什么样的变量时,或者是什么样的参数。
我们会用什么样的语义学,这是由您使用的数据类型隐式规定的,如果您使用像int这样的原始值,您将使用此值复制语义,如果使用复杂的对象或数组,它将转而使用这个引用语义。
所以它是由语言和类型系统C Plus为您决定的,你想做什么就做什么,所以如果你想传递一个int,使用这些对象样式引用语义,您可以,这样做的方法是在它后面加上一个符号,这意味着我想要一个int的引用。
如果你看过,这有点像指针,但不完全是,所以这个小变化会让它,如果你把x和y传递给这个函数,它将把这个变量a链接到这个变量x,他们将是彼此的化名,如果你换一个,它会改变另一个,同样的y变成了b所以在这里。
如果我在缅因州交换这些,它真的会交换他们,我会看到区别,那有点酷,在Java中你不能这么做,人们一定想知道Java是在C Plus之后出现的,Java的设计者肯定知道这个美丽的特性,但他们选择不包括它。
嗯哼,我想知道这意味着什么,我不知道,嗯,好吧,我告诉你,我来回答我愚蠢的问题,好极了,这是一件很酷的事情,这是一个强大的东西,但它可以被滥用,我告诉你,如果你看一个C++代码,就像,想象一下你只有主。
这东西在其他文件里,所以它不在你的屏幕上,你只有我,你也可以看到这个叫做x逗号y,我是说,也许你可以推断出一些东西,因为这叫交换什么的,但就像你不知道,不管是引用还是传递的值,所以现在你不确定。
如果这个函数会扰乱变量的值,因此,很难对C++代码进行推理,它能做什么,当你调试时它不能做什么,你需要做的一个关键的事情是限制程序部分的表面,可能是导致窃丨听丨器的原因,你知道我知道这不是问题所在。
我知道这不是问题所在,可能在这里,在某些地方,像这样谈论C++代码更难,因为你有所有这些,比如引用周围漂浮的东西,这些东西可能会改变,这很难,是啊,是啊,问题,在Ruby有少量工作经验。
他们在方法上有感叹号,这些方法实际上可以修改值模式,C++有任何类型的命名约定,是啊,是啊,这是个好问题,就像你在红宝石里说的,你有突变的感叹号,用于修改,它帮助你直观地看到你是否可以改变一些东西。
是啊,是啊,嗯,C加+并没有真正的,呃,我是说,这是一种古老的语言,当他们成功的时候,他们基本上不认为,所以如果你想交流,那是你喜欢的,你有时可以在这里加一个小注释,说突变或引用。
或者在这里你可以把评论之类的东西,但是是的,这在某种程度上取决于开发人员是否有选择地指示类似的内容,所以我的意思是,不幸的是,否,语言没有这些东西,坦率地说,像Ruby这样的语言,做你所描述的那些事情。
他们这样做是因为他们从中吸取教训,基本上和这个不匹配,是啊,是啊,引用和引用有什么区别,魔法和指针,引用和指针有什么区别,所以我的意思是,我不认为这里有人知道指针是什么,但是,对于你们中的一些人来说。
做指针基本上和这个想法是一样的,但是指针需要对语法进行更多更改,这是对程序的最小更改,然后它做我想要的--一个指针,我得用星号,我必须在更多的地方使用星号来获得正确的行为,指针的安全措施也较少。
而且更有可能导致撞车,引用是相当简单和有界的,更容易正确,所以这是指针概念的演变,它的目的是取代许多,与这些指针特性一起使用的C程序,就像我会在这门课上和你们谈论指针一样,但这超出了好的范围。
所以这些是引用语义,我想提到的是,任何类型的数据都可以通过这种方式传递,在双A弦中,任何事情,所以这有点取决于程序员,值是否作为副本传递,或者它是否作为引用传递,有点酷,这里有一个例子,很多时候。
引用参数被用于我们所说的输出参数,所以我不知道,如果你听说过这个XKCD漫画,有一个,有一个漫画说,嗯,什么年龄段的人,好吧,在它变得令人毛骨悚然之前约会,因为你在这个时代太与众不同了,别担心。
你们远远超出了我的范围,我们很酷,但这里有一个公式,比如他们的年龄只有你的一半再加上七岁,没关系的,或者他们老了,你知道你的年龄减去7乘以2,没关系的,我的意思是,只是个玩笑,但如果你想打个招呼。
我这么老了,最低和最高年龄是多少,我可以和他们约会的人,也不会令人毛骨悚然,这就像是我想要的一个函数,我想通过年龄,我想把这两样东西还给你,C++和Java,很多语言就是没有办法返回两个东西。
但你可以做的是,你可以有两个参考参数来存储东西,这提供了两个输出,所以这有时被称为输出参数,输出参考参数,所以实际上,如果你看看主,我宣布年轻人和老年人,四岁八岁的第九个呼叫年龄,实际上,如果你注意到。
我甚至没有得到任何价值,我甚至不初始化它们,因为你是怎么被安排在这里的,当敏指年轻时,当Max提到老的时候,它设定了它们的价值,所以我不必说等于零,或者我只是不离开,我不把任何价值放在那里。
所以这是一个通过使用引用参数返回两个东西的例子,是的,这是我提到的输出的主题,Gra,啊,是啊,是啊,把这些放在最后,或者别的什么,嗯,我不知道松散地,我是说,也许我会说函数和参数有很多不同的情况。
我不想给你的东西,关于这一点的过于严格的规定,我要说的话,虽然你不想把一切都作为参考,就像我可以在与号时代做这个一样,但没必要那样,因为我不喜欢,我不想修改后面的仪表,所以如果你不需要它作为参考。
你不应该把它作为参考,你应该少用这个,当它是有帮助的,而不仅仅是到处都是,你不把它作为参考,因为它就像复制一样,啊,啊,啊,你在问我是否通过一个物体,但它不是对对象的引用,是啊,是啊。
我以后会教你关于物体的知识,但是有一些有趣的规则,比如如果你有一个物体,就像一个学生,一个银行账户,一个数组,或者其他什么,把它作为一个没有与号的参数传递,它会完整地复制这件事,这很奇怪。
不是Java会这么做的,我现在不打算详细说明这一点,但是是的,我是说这是我们想解决的问题,我们想很快再来,不过,请便,跟进,是啊,是啊,所以它真的更像密码引用,哦,你说了那个词,你说效率,什么更有效率。
嗯是的,所以我只是在戏弄你,因为很多X程序员关心效率,什么使用更多的内存,什么使用更多的运行时,我想要一个快速精益的程序,你知道,我也很在乎,但我更关心的是大规模的而不是小规模的。
所以就像有些人走得很好,我为什么不把这个年龄作为参考呢,因为那样我就不用抄了,所以我节省了大约四个字节的内存,哈哈哈哈,做这种事的人,是那些从地上捡起便士的白痴,没关系没关系,你知道的,你不需要这个。
省了这么少的钱,对嗯,3。我认为没有必要为了提高效率而将其一笔带过,现在你说的不是那个,你说的就像一个大物体,如果我把它作为参考,我不必抄袭这个更有效的大东西,尤其是如果你是一个充满数据的巨大阵列。
我不想把整件事都抄好,我们以后再说,但是是的,一件大事是,你想通过引用传递,有时为了效率,但不是很少之类的,只是澄清一下,如果不想将数据类型像对象一样放置,你知不知道,C加加。
当它复制并为非原语类型做一个深度时,就像一个物体,就像,说一个物体,那是它的另一个物体,是啊,是啊,我想回来,我是说我会到达那里,我想我们有点领先了,就像引用其他对象的对象一样,如果你复印。
你可以做深度复制,或者你可以做一些肤浅的副本,我认为默认情况下,东西是肤浅的复制,所以如果有两件事指向某个地方,他们指向同一件事,或者其他任何东西,除了可能做更深的副本,我来解决。
我今天不想在那个方向走得太远,反正,好啦,所以我总结一下,这里是关于参数的,你可以退货不止一件事,您可以避免制作对象的笨重副本,但这使得对这个代码的推理变得更加困难,如果我通过ABC,它会改变一个。
B和c,它们是参考文献吗,它们是价值观吗,我不知道,我得去看看foo函数才能弄清楚,引用可以更慢,不是暗示,但在某些情况下,它们可能会更慢,因为你必须设置这些记忆指针之类的东西,不能传递文字值作为引用。
你必须传递对变量的引用,关键是,你指的是一个记忆位置,你指的是一个变量,所以如果你在这里说三十九,如果那是个参考参数,它不会编译,所以在前面的例子中,你呀,对所以实际上,如果我改变这个来得到参考年龄。
我就过不了四八,在我这个年纪,等于48,然后过了我的年龄,因为你指的是一个int变量,不仅仅是字面上的值,一种微妙的区别,但是是的,好啦,所以我还有几分钟,我只想利用我在这里的所有时间。
关于函数的一件事,你知道我没有写任何非常大的函数或非常有趣的函数,在课堂上和你一起生活,但是当你写一个大程序,你最后把它分开了,把它分解成许多功能,我想说总的来说你想让缅因州推动这个项目。
Maine调用了大多数其他函数来完成这项工作,现在呢,有时这个函数调用方法,但有时它会叫另一个,所以我不是说刻薄,所有的召唤,但意味着管理事情,一种常见的风格,我看到学生们这么做,我想我想劝阻。
main调用第一个函数,然后第一个函数调用第二个函数,然后第三个函数调用第四个函数,等等,主线就像一条线开始,然后我们再也不回来了,我把这叫做锁链,而且风格不好,因为它把这些结合在一起。
我不能把这些单独处理,我不能只调用方法二而不把我的四和它一起调用,所以还是让我来管理比较好,我后面有一些例子,在幻灯片中,我可能不会够到,不过,好吧,所以等等,让我们做最后一件事,因为我没时间了。
我将在星期五演奏弦乐,但是让我们来谈谈这个例子,想象我想要一个二次方程求解器,你知道二次方程,x的平方加上8 x的平方加上bx加上c等于零,你想找到它的根源,你用这个二次公式,有两个根。
一个是这里加号一个是这里减号,你们知道这些东西,所以我想把我正在解的二次方程,我想把这些根拔出来,所以如果这是等式,我现在想离开这两条路线,不是每个二次方程都有两个实根,但也许现在,让我们忽略它。
让我们假装我们在和这样做的人打交道,我可以把这段代码写成C++,但我想更多地谈谈功能的设计,函数的标题应该是什么,参数应该是什么,回报值应该是什么,也许是我没叫过的穿黄衬衫的人,是啊,是啊,你说呢。
应该接受数字,作为一种手段,系数,是啊,是啊,A、B、C,好啦,因为我们返回两个不同的值,我们也许应该做那些,作为,好的很好,所以这些a和c应该是值或引用,这些都是价值,回答双倍,我们不修改它。
我们只需要他们的价值观,然后这两个根就是你,你再说一遍出去,这些是对我们将存储为退货的数字的引用,基本上是对的,那么函数的返回类型应该是什么,我想是虚空,我们不喜欢回来,从字面上看,归还任何东西。
我们是输出参数,把这两样东西还对了,是啊,是啊,难道不清楚喜欢,哦,当然,当然,另一个设计是返回列表,根的数组,所以我们有两个元素或其他什么,这也很好,我只是在抄写,因为我还没教你这个,也没教你加薪。
但如果我知道加薪,那将是另一个有效的解决方案,我认为你刚才说的是一个很好的解决方案,以a b和c为正则值参数,把这些作为参考参数,把这些填了,这种结果会被发回给,所以这是最后一个问题,然后我们就回家。
是啊,是啊,现在,我们假设二次入侵有两个不同的根,所以如果我们考虑的是一个一般的亚得里亚海方程,我们能不能回到一个时代,回到真正的根的数量上,是啊嗯,如果你想处理没有两个真正根的。
我相信如果你看这里是一个歧视者,确定这个D,我想他的信号是零负正会告诉你有多少根,所以我赌了一把,啊,无系统问题,我在这个例子中提到了这一点,但这就是解决办法,好啦,我要就此打住。
但如果你是一个热切的海狸,你想向前看,我发布了一个早期链接到我们家庭作业的一部分,如果你想看,但我周五会正式布置家庭作业,所以我会看到你们。
【编程抽象方法 cs106x 2017】斯坦福—中英字幕 - P20:Lecture 20 - BFS, Dijkstras - 加加zero - BV1By411h75g
好啦,让我们这样做,呃,第八周,今天是星期三,我们还有几节课要讲,然后我们可以和家人一起休息一周,或者你休息的时候要做什么,我知道我们都很期待,今天我们将继续讨论图表,上次我们讲的只是一般的概念和术语。
您可能会关心图形的原因,诸如此类的事情,我们使用了C++库附带的基本图形类,关于那堂课,我要提到的一件事是,关于基本图,我们用它编程,那真的是,如果你看了很多编程语言,您将发现它们没有表示图的类。
他们没有基本的图形,或者他们没有类似的东西,其实呢,我想我在这节课开始的时候提到过,我们正在学习的大多数斯坦福图书馆都是等价的,或者类似于C++附带的stl库,我们有我们的矢量STL,也有一个矢量。
你知道我们有地图,还有一张地图,所以,我们做的大部分事情,这些斯坦福系列相当于C真正附带的东西,基本图不等价于STL中的任何东西,我可能会在周五谈论更多关于这一点,但基本上长话短说,图表是复杂的。
它们是变化的,有很多不同类型的图,很难写出一个适用于所有这些的图库,所以大多数语言甚至不尝试,但不管怎样,不管我们尝试了什么,我们写了一个,它有点管用,我们上次讲到的是,我们在讨论这些路径搜索算法。
如何在图中找到路径,我们谈到了深度优先搜索,有人能给我,就像用一句话描述深度优先搜索是如何工作的,你说你基本上在图表中尽可能地走得更远,除非你走到死胡同,否则他们不会得到什么,然后你回溯,尝试另一个。
一直这样直到你们找到彼此,是啊,是啊,这是正确的,如果你想找到一条从A到B的路,你选择一个邻居,你往那个方向走越远越好,看看你能不能到达目的地B如果你做到了,那你就停下来,如果没有,你就倒退。
你试试别的,你就是这么说的,所以你一次又一次,你在这条路上深入探索,你在这里选一个邻居,你选择一个邻居,你试着去探索,你是否能从那个邻居到达目的地V2,所以这意味着什么。
深度优先搜索是你不能保证找到最佳路径,最短路径,边缘重量最小的路径,这些都不能保证,但它会发现图中是否有一条从起点到终点的路径,你最终会找到的,所以这很好,我想深度优先搜索相对来说并不难实现。
而且它不需要那么多的数据和那么多的复杂性来做到这一点,它是一种简单的路径搜索算法,这是它的主要好处,所以我想从那里恢复,我想谈谈,啊,我想提到的另一件事是,有时在你用完DFS后,深度优先搜索,你说。
好的,好的,嗯,我发现了一条很棒的路,路找到了耶,但就像,这条小路是什么样的,你知道的,我需要知道要访问哪些节点才能正确地遵循路径,所以就像,我该如何写一个版本来告诉我道路是什么,这是一个递归回溯练习。
就像你们周一说的,所以当你做递归回溯时,你怎么知道,我是说,你选择正确的这些顶点,就像,我们如何知道算法选择了什么来呈现给用户,当我们在一般情况下完成时,因为我们在跟踪我们已经访问过的节点。
所以我们没有得到相同的,所以当我们到达终点的时候,我们访问过的所有节点中最少的一个,是列表是路径,是啊,是啊,所以我们正在访问的这些节点,如果我们能记住我们访问过的所有节点,那基本上是我们的团队。
或者是的,所以就c+中的一些力学来说,也许你可以把这样的东西传过来,你传递某种这是伪代码,但就像你可能会传递一个矢量或其他东西作为另一个参数,我们用回溯来做这个,你把你做出的选择和正确的东西传递给别人。
所以传递一些矢量,那是你的路,然后当你标记人们访问,它发生在那个矢量上,如果你知道,查找路径数组,嗯,如果它现在在你的矢量中,但如果你找不到路,也许你选择把它从路径上移除,所以是的,这是基本思想。
我在这件事上有点含糊其辞和伪科迪,以防万一,假设,如果你必须实现这个,也许我不想放弃所有的权利,但这是一般的想法,嗯好吧,所以我已经谈过这个了,呃,这是对,Dfs,找到一条现在找不到最好的路。
我想走另一条路,搜索算法,我想把它和深度优先搜索进行比较,这个叫做广度优先搜索,Bf s,所以我的意思是,只是我觉得这个名字暗示了一点算法,它搜索的范围很广,而不是很深,所以一般的想法是从你的起点开始。
如果你想到达目的地,你一个一个地搜索,看看你能找到的任何地方,如果你不能到达目的地,然后你两个人搜索,看看你能到达的任何地方,如果这不能让你到达目的地,你只要一直重复这个。
你一次又一次地扩大你的搜索范围,直到你到达目标,现在还没有足够的细节来实现一个算法,但这就是我的想法,对呀,嗯,所以如果你想从A到I,你会看看所有的近邻,看看他们中是否有人,我和如果是,那你就完了。
但除此之外,你现在开始观察所有这些人的近邻,看看他们是什么,就像,我只是写在这里,在算法中,顶点的顺序是什么,你看着一个,然后你看BD,然后它们的直接邻居是,看看他们的直接邻居,你会得到c或者i。
你会把我看作目的地,然后你就会停下来,你会发现在D H I,与深度优先搜索相比有一些不同的属性,然后呢,它最重要的属性之一,它总是返回最短路径,现在我是说,你应该一直持怀疑态度,每当我告诉你一些事情。
因为你知道我知道的不多,另一件事是我有点喜欢对你们撒谎,只是想看看你会不会上当,但就像这样,如果我告诉你这样的事,我觉得你应该经常质疑我,你怎么知道你知道,就像,你确定吗,嗯,你的直觉是什么。
那会让你相信我没有骗你,它必须返回最短路径,你怎么知道那是真的,是啊,是啊,因为当它搜索产品时,它基本上定义了所有其他可能的较短路径,就像在深度搜索一样,在这里可以跳过一条较短的路径,你可以下到每一关。
是呀,是呀,你说的对,嗯,如果你拿一个,零,我们的三门或几门理论课,你学习证明技术,就像,你如何用一种逻辑上合理的方式来证明事情,证明事物的一种常见方法是通过矛盾,对呀,所以你可以说,嗯。
想象一下这没有找到最短的路径,想象一下,有一条比这个发现的路径更短的路径,关于那条路等等,什么是真的,你清楚地表明这将是一个矛盾的状态,那不可能是那种,矛盾的观念,这里是你先看所有长度为1的路径。
如果他们中的任何一个能让你找到目标,你停下来,我们没有停下来,所以我们继续到长度为2的路径,我们看所有的路径,如果其中任何一个能让我们到达目的地,我们停下来,他们不会,我们继续过去的第三点。
所以我们到了第七个长度的包,我们找到了目的地,然后你想知道有没有更短的,因为在你明白我的意思之前,我们已经检查了所有的路径,就像我们会找到它一样,所以算法不会这么做,所以不管怎样,这是个好主意。
它在图中找到这两个顶点之间的最短路径,所以现在就如何实现这一点而言,呃,你不能同时看到这三个元素的跳跃,但你可以按照你看东西的顺序排序,所以一般的算法是这样的,如果你在寻找一条从B1到Two的路径。
你有点事要做,还有一些你要看的东西,最初你的待办事项列表是顶点一,起点,所以你重复直到队列为空,从队列中取出前面的元素,您将该元素标记为正在访问,然后将所有相邻的元素插入队列,稍后处理,你重复。
直到队列中弹出的是目的地,所以我的意思是,你可能会说这听起来不像你在上一张幻灯片上说的那样,但如果你只考虑代码的影响,这将是我在最后一张幻灯片上说的,它将是这个队列中出现的第一件事,将是起点。
接下来从这个队列中弹出的将是邻居,起点的近邻,接下来的事情,我们会调查所有这些人的邻居,等等等等,所以这个算法现在将实现广度优先搜索,上次我们谈到深度优先搜索时,我说嘿,是不是很眼熟,房间里有人说。
像是回溯算法,对呀,这看起来眼熟吗,你以前在哪里见过这个,字梯程序,这正是你在单词阶梯程序中所做的,它实际上是相同的算法,你把只有开头单词的小堆栈放入队列中,然后你反复地拉出一叠。
把所有邻居都放在那堆东西上面,把所有相邻的书堆放到队列里,对呀,你就是这么做的你就是这么做的,你只是没有把它作为一个图形问题来做,但是你用同样的算法,所以如果你让那个程序起作用。
我想你知道你找到了最简短的词,两个字之间的梯子,对呀,所以这是一个图搜索问题,基本上,当然还有,如果这是一张图表,顶点是文字,如果它们相差一个字母,边缘就会是,如果他们的邻居,然后他们之间有一个边缘。
对呀,这是一张数据图,所以是的,这就是如何实现广度优先搜索,所以我是说我不知道还能说什么,这是这里的主要想法,现在我认为主要的事情是,当我还是个学生的时候,当我第一次学习广度搜索时。
我觉得那个好像比另一个好,为什么你会想要深度优先搜索,它找不到捷径,它找到了一条又长又怪的路,你为什么不一直用这个,我的意思是我认为这是一个合理的问题问,但我想简短的回答会是,有时候你不在乎。
如果这是最短的路径,有时这可能需要更长的时间,仅仅因为它必须操纵Q和Q DQ,所有这些不同的事情,运行这个可能需要更多内存,运行这个可能需要更多的时间,也许这样做的好处对我来说并不重要。
在我试图解决的问题的背景下,你可能会说为什么你不想要最短的路径,嗯,有时路的长度并不重要,就像,如果你想把电网连接到一个城市,确保每家每户都有电,那你就知道了,假装它是一个图表,房子是顶点。
电力电缆是边缘,是的,这并不重要,如果你有一根短的电力电缆连接到你的房子或一根长的,我是说,我想如果它真的很长,可能会有危险什么的,但就像一般,只要你连接,你连接,所以我只想确保他们都有联系,我不在乎。
如果短,你知道的,所以你并不总是希望这一切的好处结束,Dfs,你有问题吗,是啊,是啊,所以这是有什么意义的,那个,我们标记它们的原因,因为我们只想看看这里未被拜访的邻居,我想你在单词阶梯中做到了这一点。
事实上,你们中的一些人可能有这种错误,因为你们没有这样做,你需要保留一组你以前见过的单词,记住这一点,你是用字母写的,当你看单词的时候,你把它们放在那里,如果你不做那一套,或者忘了把东西放进那一套。
我想你可能发现你的算法花了很长时间,它从来没有停止过,你们有没有过那种虫子,所以说,嗯是的,我是说,基本上,很多这些算法会说这样做,到每一个未访问的顶点,这是为了确保,因为很多图都有这样的循环,哪里。
如果你走这条路再回来,你可以回到你开始的地方,你不想让图表像旋转一样寻找,嗯,是的,FS给它引入了随机性,那还会是FS吗,还是总是始终如一,哎呦,DFS随机选择要走的路,是啊,是啊,还是DFS,我是说。
我想你会发现如果你实现dfs和dfs,使用我们的图书馆,所以你会得到一个一致的结果,但它一致的原因是,只是因为我们的曲线图把你反馈给了邻居,通常足够的联邦秩序,但是是的。
如果你把这些邻居按不同的顺序洗牌,再进行处理,你得到不同的结果,运行路径搜索的不同时间,但这仍然是一个想法,或者BFS,这不会改变搜索的性质,我是说,您可能会发现您的dfs碰巧选择并突出了最短的一个。
但这只是因为有了国家,所以你知道总的来说,每当你实现这些东西,你可能想知道路径是什么,就像dfs一样,所以DFS,我们计算路径的方法是沿着一个矢量,我们把访问的顶点放入向量中,你不能在这里做同样的把戏。
因为从概念上讲,从技术上讲,你是一次一点点地尝试一堆垫子,与DFS相反,你在尽可能地探索一条路,然后后退,这样你就可以把唯一的一条路径表示为一个向量,在这种情况下,所以我的意思是,你看。
我们所做的是记住单词阶梯中的路径,你把这个复杂得可笑的结构,就像一个充满单词和字母的提示,就像它是一种愚蠢的结构,你有所有这些线索和堆栈到处都是,这是因为这些堆栈中的每一个都代表着一个类似的局部探索。
你看到的是一条路,一旦你找到目标,你说过,哦好吧,然后这是这个选择的堆栈,这是所有单词的堆叠,对呀,嗯,这样很好,只是它需要大量的记忆,所以我们让你在任务二的时候,因为那是我们目前能找到的最好的了。
但最重要的是,如果你有一个很好的图形库,你会做什么,就像这样,而不是保持一个QA堆栈或向量队列,每次你访问一个顶点,每次你喜欢市场被参观,你也会记得,我是怎么到这个顶点的,所以如果我标记,你知道的。
如果我在Q中做第一个,然后在一个我做BD之后,我会记得b和d和e都来自,所以我会像存储以前的节点一样存储,上一个指针,以前的东西代表,所以最终如果我能击中目标,就像一个对我是我正在寻找的。
然后我就会记得我以前的是H和H,因为前面是d,d是前面是a,所以如果我想要从a到i的路径,一旦我找到i,我只是走在前面,上一次,以前,这就是我的道路,倒过来了,但这是正确的道路,如果有同样好的路。
有两个相同的最小长度,这个算法会找到其中一个,他们中的一个没有更好也没关系,或者比另一个更糟,所以我想它会找到按字母顺序排列最少的最佳路径,是啊,是啊,所以之前,是啊,是啊,就像,前面的故事在哪里。
我是说这取决于你用的是什么图书馆,但基本上你需要一些方法来问那个人的前任是谁,所以我的意思是,如果你没有很多支持,这可能是字面上的,从字面上看,这可能是一个向量或顶点到顶点的地图或其他东西。
你知道它可以是任何东西,或者如果你的图书馆有帮助,也许它让你坐下嘿,你以前和你一样,也许它可以让您以某种方式将其存储在图形对象中,取决于图书馆给你的东西,所以是的,我是说,但只是在抽象的意义上。
你需要想出一种方法来记住对于给定的顶点,我想以某种形式记住他们的前任是谁,这可能是字符串到字符串的映射,也可能是顶点星到顶点星的地图或类似的东西,你知道的,就是这个意思,同样的事情。
当我谈到将一个顶点标记为访问时,同样的概念也适用于那里,就像,如何将顶点标记为已访问,“好”是什么意思,我不知道,比如把参观过的东西做成一组放在布景里,你知道,就像你想出了一个方法,如此正确,就像。
图表并不神奇地,像你做的那样为你做,你知道的,想办法记住你以前访问过这个顶点,但是,这就对了,那个算法大部分是有意义的关于dfs的问题,他创建了一个包含,当然,我想如果你对图形库有设计控制。
你可以说我希望我的顶点有一个小布尔标志,在里面,或者访问过的东西真假,或某事和真实的替代,所以是的,我是说,如果你有能力决定这些事情,然后你可以让你的图书馆帮助处理这种事情。
我想我要小心的一件事是寻找一条路,是你可能想用图表做的十亿件事之一,这不是你唯一想做的事情,如果您过度自定义图库以方便路径搜索,对其他事情可能没有那么好,或者它可能会臃肿什么的,所以这取决于你想做什么。
其实呢,如果你想让我离题一会儿,就像我曾经参加过一次工作面试,我在微软的一个行业工作,你知道他们会问你这些编码问题和益智问题之类的,那家伙说,我想让你写一个图形库,或者至少告诉我如何编写图形库的设计。
比如它有什么方法,它能做什么,我开始写下所有这些方法标题之类的东西,然后在某个时候我停了下来,我就像,哦等等,其实呢,你打算怎么处理这张图表,因为你知道,我需要访问的布尔值吗,我需要以前的地图吗。
你知道的,就像,你打算怎么处理它,因为我想,不管我是用这个还是这个,这取决于你要怎么处理它,他说,好啦,那是正确答案,让我们继续他想让我说的话,曾经是,你打算怎么处理这张图表,因为不管怎么样。
我应该直接问他的,这样我就不用知道答案了,在那里吗,另一只手举起来,有人,是啊,是啊,所以这就像,即使你有深度搜索,你还是要像以前一样发送,你不需要以前的,呃对于DFS来说,因为如果你传递一个胜利者。
就像你是一个递归调用堆栈,一种是你的路,你在哪里,你在看哪里,就像如果你存储在一个向量中,比如您在当前递归调用中访问的位置,如果你找到目标,那个矢量有你的路径,如果你找不到目标。
你只需在返回的路上取消选择并从矢量中移除,所以不同的,你这样做的原因是,你只探索一条路,尽你所能直到你放弃,因此,一条路径可以在向量中,什么地方什么的,但这个你隐含地探索了很多道路,一步一个脚印,因此。
你不能只把一条路径作为矢量,因为你做的这些事,所以你知道我的意思,就像你不能把所有这些路径都扔进一个向量,但我有一个问题,就像你说的你可以在地图上,就像这个之前那个,但是这个案子呢,你以前有很多可能性。
如果你有多个预览,但你不在这个算法中,因为就像在这个算法中,每当你把某人作为别人的邻居添加到队列中时,你从队列中拉出来的,所以你就像,我从他那里得到了他,所以它结束了之前什么的,所以这就像。
虽然确实可能有多个,就像你可以从h或c得到i,或者其他什么,但我从H那里得到了两只眼睛,就像,这就是我要储存的,其他可能的方法,我不会储存那些,因为这不是我的算法遇到的,你知道的。
如果您想返回所有可能的最短路径,因为另一个很容易修改,你只是不停地寻找,但在这个问题上,你不知道你的,你想要所有最短的路径,是啊,是啊,我是说,那是,我想你知道,我不想在那上面花太多时间。
但基本上简短的回答是,如果你曾经,我想实际上伪代码中缺少的是当你停止,就像你停下来,如果你看到目标像B2或其他什么,但我想你会做的是,如果你看到V 2你,你庆祝,你用前面的指针给出你的路径。
但在庆祝并打印出来或返回或其他它正在做的事情后,你不会立即跳出你的循环,你继续循环,直到你把所有和那个一样长的垫子都用完,但是一旦你到了你的路径比这更长的地步,你会想停下来,你知道的,蜂蜜,你知道的。
既然我们没有,我们只跟踪我们当前在哪个节点上,以及它以前的节点是什么,嗯,我是说你必须决定要修改算法来记住,可能我的前任就是他,它走了两三步才找到我,或者任何你能做的。
您可以将任何顶点与任何其他信息相关联,你喜欢用地图,所以我必须绘制地图我每跳两下,我得到了高和三跳,所以是的,一旦你停下来看到顶点,你得用它跳三下以上,你就会爆发。
因为你会说我现在受够了所有伟大的三个啤酒花垫,好啦,好啦,所以这就是BFS,我还有什么没说到大O,我将主要谈论大o在星期五,但这些算法中的大多数,BFS和DFS有一个大O,与顶点和边成正比。
两者都是线性的,所以我们说它是v加e的大o,我不想大谈理由,情况就是这样,我想把它保存下来,但就像它是什么,我们可以以后再谈,我是说,这种直觉是,你不会多次访问一个顶点,你知道。
因为你不会多次拜访它的邻居,这也意味着你不会在边缘旅行不止一次,所以我的意思是它有一种直觉,你最多看一次东西,但不管怎样。
无论我想继续前进,我想跳到我的另一个滑梯上,还有更多的算法来搜索路径。
我想告诉你另外两个,我不知道今天能不能全部吃完,但我想谈谈一个叫做贝克算法的算法,如果我们有时间,我说的是一个叫星星的,这些算法是对广度的进一步改进,首先搜索,试图让他们跑得更快。
因为你知道我用这些小图表给你看的例子,从a到b从b到c,这些都是非常小的图表,我是说,但我有八九个顶点,或者如果你有一张所有城市和道路的图表,你知道你在试图绘制街道地图,或者有很多顶点,有很多边缘。
你缩小,你拥有整个美国,有很多顶点,更不用说其他的了,就像社交网络,这些图表里有数十亿人,你知道它的顶点太多了,所以这些算法真的需要加快速度,我给你看的那些有点快,但也许我们可以做得更好。
所以这些算法还有另一个缺陷,除此之外,他们不考虑边缘重量,BFS被优化以找到最短路径,这是伟大的,但有时我不想要最短的路,我想要总成本最低的,这些并不总是相同的权利,所以我想我的例子是。
如果你从一个到一半,那么最短路径是正确的,那是,呃,两啤酒花,这条路的成本和7加2是9,但我想你能做到,有几种方法,你可以以较低的成本到达那里,好吧,如果你去一个B E F,那是四加二加二,那是八。
所以少了一个,我想这不是真的吗,如果你一直绕到底部,比那个还要便宜,不是六个吗?就像有更便宜的垫子有更多的啤酒花,有时这就是你想要的,是的,我是说我们已经讨论过一些现实世界中的类比,就像飞机票一样。
如果你愿意飞四件东西的航班,听起来很可怕,但如果你愿意花六百块,而不是花900块坐两站飞机,嗯,你是个挨饿的大学生,你可以接受这笔交易,我不知道,你可以想到很多这样的例子,对呀,所以有时候体重很重要。
好的,好的,所以dijkstra算法是以edgar dykstra的名字命名的,他是个很酷的家伙,你应该去查查他的维基百科什么的,他,你知道我可以继续谈论他,我只想简短地说。
他是计算机科学和逻辑学史上的重要人物,嗯,然后他,你知道他想出了这个算法,戴克斯特拉算法,以及许多其他聪明的计算解决方案,他在计算语言学方面很有影响力,在编译器中也是如此,在操作系统中。
我们领域的各种领域,一个才华横溢的家伙,他获得了图灵奖,就像诺贝尔计算机科学奖,嗯,很酷的家伙,我喜欢他,因为他的名字在一行中包含for循环变量,我JK,太酷了,这是很酷的财产,你知道的,嗯。
他还几乎单枪匹马地杀死了去指挥,这是有史以来发生的最糟糕的事情之一,在编程语言中这个命令被称为,转到您可以跳转到程序中其他任何地方的地方,立刻,这几乎就像调用函数一样,但是你可以直接跳到一个函数的中间。
或者跳到任何地方,你可以说去那里,现在呢,你在那里,嗯,那是强大的,但它使调试变得不可能,因为你不知道自己从哪里来怎么来的,只是很糟糕,他写了一篇很有影响力的论文,打电话去认为这是有害的。
有一次他说每个人都像,哎呦,他说得对,所以他们停了下来,我是说,他不是单枪匹马杀了珂图,但不管怎样,那家报纸超级有名,不管怎样,他是个很有趣的家伙,他在计算机科学方面做了很多工作,我通常不谈论CS的人。
但他是我的人,所以他想出了这个算法,你也知道,我觉得有点好笑,因为就像学校里的人第一次听到冰斯特拉的名字一样,你知道的,但这可能是他的两个七,对我们领域最重要的贡献,你知道我的意思。
但不管这是以他的名字命名的,所以这是一个算法,在图的两个顶点之间找到一个最小权重路径,从技术上讲,你可以找到所有的路径,但不管怎样,嗯,这个算法的基本思想是,很像闺蜜,您使用优先级队列而不是常规队列。
记得我们说过,我们把东西排队,我们把它们拿出来,看看它们什么的,而不是做一个正常的队列,我们使用一个按边缘权重排序的优先级队列,如果你做到了再加一点魔法,然后基本上你最终会用算法找到最小权重路径。
还记得我说的逻辑吗,我们知道广度优先搜索,我们会找到最短的路,因为我们观察所有较短的路径,在我们看任何更长的路径之前,对呀,直觉上这将是找到的最短路径,这个算法有点像,只是它查看了所有低成本的路径。
在它研究所有高成本路径之前,因此,如果你找到了通往目的地的道路,你会知道这是到达那里的最低成本的方法,我拿给你看,所以有点复杂,伪,但也没那么糟,相信我,嗯。
所以德克斯特的算法是将每个顶点与成本关联起来,所以我们在讨论,如何映射到以前的,你是怎么记住一些啤酒花的,你呀,你可以有地图什么的,从顶点到双倍或它的或任何成本,你知道的,假设每个顶点都有代价。
你从它们都有无穷大的代价开始,那只是意味着我没有任何办法,我不知道有什么办法能到达那个顶点,然而,所以说,如果我有办法,比无限还便宜,对呀,就是这个意思,除了起始顶点,你已经从那里开始了。
所以到达那里的成本为零,现在您将所有顶点放入优先级队列中,你们知道优先提示,病人提示,对呀,好像你知道似的,所以按优先级排序,一开始把v1放进去,现在这个算法和BFS基本相同。
你拔出一个顶点市场就访问了,把他的邻居关在里面,变化意味着这里有很多词,但变化是,当您将东西添加到数据结构中时,你必须把PQ加上你放进去的值,就像顶点一样,你得增加一个优先级,那么你使用的优先级是什么。
您使用的优先级是到达顶点的成本,你现在看到的是我称之为V的,加上从v到邻居的边的代价,所以如果我能以零的代价得到v1,那么到达邻居的成本就是他们的直接边缘成本,然后到达所有邻居的成本是第一个优势。
再加上第二条边以此类推,所以你储存了一些成本作为优先事项,你们还记得PU把东西弹出来,从优先数到最高,所以那些低成本的会先从那里出来,所以我们要先看看它们,所以我们要先看看更便宜的通行证,以此类推。
就是这个意思,再一次,我们有重建路径的想法,使用以前从BFS借来的指针,一旦我们找到目标,我们以前以前以前,直到我们找到它回到商店,现在我想有一个例子和一张图片会更容易,所以让我们谈谈幻灯片都在网站上。
所以如果我在找Dijkstra的算法,从A到F的路径,你知道,我记得所有这些人都有无限的代价,但我的星形顶点成本为零,我要在这张图上做一些颜色编码,我要在这里放一些黄色的东西,如果它在p q中。
在某个时候会被看到的,我要把它涂成绿色,如果我把它从PQ里拿出来,我把它标记为已经访问过了,那将是绿色的,所以最初当算法启动时,你把起始顶点放在PQ中,代价为零,好啦,所以这就是事情的状态。
我在寻找一条通往F的道路,所以下一步就是把人拉出来,你把他们所有的邻居都放进去,所以我拿出一个,标记他为访客,然后我把他所有的邻居都放在PQ里,我把它们放在优先级上的成本。
我把它们放进去的是边缘重量从一个到那个人,对呀,所以这家伙和这两个人在一起,这家伙拿着一个,所以在排序正确的PQ中,所以有一个的会在前面,所以他要先出来,是啊,是啊,那么,以无穷大为代价。
使其他一切都变得像有什么意义呢?是的嗯我的意思是,只是在概念上,如果你曾经,如果你,我是说我们马上就会看到有时你会到达一个顶点,多种方式,你想知道哪种方式更好,所以你总是想知道,如果你。
如果你还没有到那里,那这种方式是无限糟糕的,所以你还想要什么,但是那种,你知道的,所以我的意思是,您不必总是在代码中存储无穷大,只是概念上,你觉得这就像,我不知道怎么到这里。
所以我认为它有无限的成本去达到,或者别的什么,你知道的,我看过你们这么做,就像你试图找到最小的东西,所以你把它设置成,最大值什么的,是那个黑客,你知道你这样做是对的,所以好吧,把这些家伙放进去。
边缘重量是优先考虑的,对呀,所以我们只要重复,所以我们把人拉出来,这将是,我知道这是在幻灯片的底部,硬C,但是PQ首先有D,因为它的成本最低,所以我把D拉了出来,现在很多事情都变了。
因为我把那个标记拿出来,我标记了他所有未拜访过的邻居,我把它们都放进去了,我把它们放进去的成本,就像他的优势一样,是什么的成本,加上这两个,加上八个,加上这四个,加上这两个,就像C和三个一起进去。
E和三个一起进去,F加9,G代表五,而且有点,又排序了,像往常一样,现在,你可能会说等等,就这些了,我在找F,我现在停下来,对不对,你不把F拉出peq就不停下来,标记他被拜访了,因为如果你现在停下来。
您将选择ADF作为您的路径,我们会发现这不是最好的选择,就像你还不想停下来,如果你看到了,所以好吧,这就是现在的情况,只要按Q的顺序,现在最便宜的是Beam,两个人的费用,对呀,所以我把他拉了出来。
我看着他所有的邻居,他的邻居是D和E等等,即使我已经有了D D或者我想我已经去过D了,但是e在p q中,那么问题是通过b得到e更好吗,比我以前的方式,就像我已经把他看成一加二。
他在里面用那个作为他的体重,但现在我找到了另一个接近他的方法,如果找到他的新方法,那我可能想用那种方式,但在这个特殊的例子中,情况并非如此,就像二加十,那更糟,所以看着他,我把他标记为被拜访过。
但到目前为止,它没有更新算法状态的任何其他内容,但有时如果你能找到更便宜的方法,它会更新东西,所以好吧,我检查B,现在pq中的下一个是c,所以我弹出C,我把他标记为访客,从c i可以到f。
我现在正在看C的近邻,我可以用更便宜的成本达到F,因为之前我有F在那里,九个的成本来自,你看到这个了吗,这就是我的算法到目前为止所发现的,所以我有f和9,现在我在看C。
我实际上可以通过这种方式达到这一点,所以我继续,我更新了,在P Q I升级病人,从9分到8分,蜡上蜡下,嗯是的,所以这和升级PU的一个元素是一样的,把它移到比以前更好的优先级F成本现在是8。
所以下一个从山顶出来的,这里是前面这里,三个人的费用,e的邻居是g,我想我以前为吉恩付出了什么代价,我现在有一个相等或更差的成本,如果我如果我从,是一加二加六,那更糟,所以这不会更新任何东西。
PQ的下一个是,如果我看,这实际上更新了我现在的成本,因为我会再回去,F在里面,花了八个钱,往这边走,但如果我加G,我访问,然后我可以花一个钱去G,加4等于5再加1等于6,所以现在更新到六个的成本。
这是以前的,你看到了吗,所以这就像你在前进一样,你只是在回忆你见过的最好的方式,去到每一个顶点和它从哪里来,你从哪里来得到最好的道路,所以基本上在某个时候,当你最终DQ F目的地,你把他标记为访客。
在这一点上你应该确定,因为您在使用成本最低的方法后所达到的算法的属性,是啊,是啊,问题确实使,我赢了,因为我觉得你不会去一个节点,你知道的,如果得到戴克算法的方法不起作用,如果图有负边权,它会。
我相信它会很好的,如果你有零重量的边缘,但是负权破坏了算法,你只是不能作为先决条件,它假设没有负权,行不通的,所以如果喜欢喜欢来自G,如果你有一个,你有树,像其他人一样,没有什么是我没有连接回F。
然后算法必须喜欢,就像这里有一堆垃圾一样,那没有帮助,算法就像卡在这里,看着这群人,在它发现不之前,我想我的意思是,也许我应该稍微改变一下这些幻灯片,因为我想在这篇文章结束时,我已经看过了每个节点。
但在另一个例子中,如果有脏东西,我不一定要看所有的节点,您查看节点的顺序是相对于权重的,所以如果这里有一个节点,它的成本是3或其他什么,然后他就会以一加四加三的方式参加队列,你不会把他拉出来。
除非那是你还没看过的最便宜的东西,所以就像,例如,在这一点上,算法f在这里有6,所以他就像下一个被预订的,所以说,然后我停了下来,因为我找到了他,但你知道吗,如果有人,你知道一个花了一个。
然后E又花了两个,所以我有三个人来这里,然后这里还有一个东西花了一个,我会看着那个,因为那样更便宜,因为你永远不知道这家伙可能会付出代价,其次是1到F的成本,我得检查一下,我得看看那个。
但如果这家伙花了12英镑,它将以很高的PQ数进入,在他来之前我是不会去看他的,所以我根本见不到他,因为我会看到如果我发现那是我想要的,我只是停下来,所以基本上如果这里有污垢,你只会看着它。
如果是低成本的垃圾,在这种情况下,你需要看看它,所以如果一个高成本的污垢你会,不会被看到的,所以说,D级二级,好啦,等等,等等,等等。
我很乐意回答这个问题,但让我让我现场直播,我们会现场直播,你们收到推荐信了吗,A到B要花一个钱,他们就像D和E,然后他们就像,好啦,就像一步的成本和成本,嗯哼,所以那会更多,所以你要做的是。
当算法开始时,你把成本为零的一个放进去,所以你没有把他从马克和格林那里拉出来,然后你会让邻居排队,你用1做q b,用2做d,然后你重复你的循环,所以你总是挑最便宜的,所以你先看b,你说谁是B的邻居。
你说,啊,我可以花两个钱去D,但我已经花了两个钱了,所以你就把它,你不会改变它,你要花11英镑买D,但是是的,好像你不会改变,你可能会做什么,虽然就像,如果这就像花了四个,所以就像你把他和一个。
你让他带四个人进去,你先去看他,你发现你可以花两个钱到达D,因此,您将更新d的成本为2,而前面的成本为d,但它不会破坏算法或任何东西,只是意味着你会更新,然后我们在这里做了类似的事情。
有时我们储存一个数字,后来我们找到了一个更好的号码,所以一切都很好,如果你那么做了,不是这样的,我们实际上可以正确地更新,我想当我描述BFS时,几乎就像,它在某种程度上是平行的。
就像它看所有的路径一个长度和所有的路径两个长度,但它不是它必须按顺序看它们,因为它是一种顺序算法,从概念上看,它看着他们,它一次移动一个,但是这个算法总是把一个元素从pq上移开,更新任何必要的内容。
然后在PQ上再重复一次,是啊,是啊,是啊,是啊,问题嗯,我有个关于负重的问题,那么为什么这不起作用呢,我们就不能把最低值加起来,就像负5一样,这些都是有趣的问题,呃,为什么不管用,让我这么想。
我是说基本上发生的事情是,就像我说过的这种可能性,如果这里有15英镑的东西,它就像顶点一样,X或其他什么,好吧,那么我的算法可能永远不会看到,因为它会做所有其他的工作,它会把东西拉出来,PU它从来没有。
它从来没有到过15英镑的东西,它找到f然后说,哎呦,我知道我找到了最便宜的方法,因为没有什么是15英镑的,你知道我不需要看十五件事,因为我发现一条路比十五块便宜,这让我想到了F,但是如果x对f有一条边。
它的代价是负12,然后哎呀,喜欢抵消十五,哎呀,现在我应该看看十五,现在我得看看一切,有点打击,算法的效率,基本上,这意味着我必须看看每一个,我是说你在问什么,如果这里有脏东西,算法不必看污垢。
如果它的重量太高,但是负边会破坏这种性质,所以现在,是呀,你说的是,我可以加一个,如果最坏的负边,负十二,我可以,在所有的边缘成本上加上十三,我觉得你能做到,我想这只是字面上的东西不能有负数在里面。
所以我觉得没关系,我想那会解决,我忘了,我以前没有这样做过,但是但是是的,不是你不能这么做,只不过,如果它真的是负数,你知道算法会做自己的事情,是的所以如果我们试图从情况中获得数据。
这个算法仍然像搜索所有其他节点一样,即使只有一个节点,是的,如果我想从A到X,我以前会看很多其他的东西,我实际上跳到X,即使我能看到去那里的路,因为我得确保,如果有一个边在这里花4英镑。
那么一个边在这里花1英镑或类似的钱,我想我做反了,但是像什么,如果是四个然后两个然后一个,啊,这比十五或四个,然后两个,然后五个,然后一个要好,那比,所以我得先检查所有这些,以防他们中的一个跳到X。
我不知道,我做不到,我不喜欢窥视前方,知道你知道你有,我是说,我有,但我想如果你仔细想想,知道这基本上是我所做的花费和成本,所以说,就像如果它不止像一个,跳开,我只需要喜欢,看全图,基本上是这样是的。
问题,所以我想知道,嗯,所以这看起来像是,我们将此与一般搜索区分开来,或者像缩小,计算成本,这和广度的主要区别,首先搜索的是广度,首先搜索找到最短路径,最短边数,这个找到了成本最低的路径。
所以你可以把更多的边缘,我想我在这里做的是,我走得很好,我把边缘的数字,但我会撤销你让我做的事,宽度优先搜索找到的最短路径是f,但戴克斯特拉会发现,因为它的成本较低,所以这是一个不同的结果。
针对不同因素进行优化,这是一个重要的区别,你是对的,否则他们很相似,但它们生产的东西在产量上有一个重要的区别,好的,好的,回到a到d是1,b,d是1,db,这将使它,所以有两条路通往相同的目标。
代价相同,对呀,其中之一是一条更长的路,因为PQ的实现方式,会的,不是吗?每次都选短一点的,因为它总是先做A和D检查然后再检查,是啊,是啊,我想那是对的,呃我,你知道的,我不敢夸大,好像有办法扭动它。
在那里你不真正看东西,好像我不确定,如果它产生给定的最短的,是否需要使用,总是最短的路径,是啊,是啊,我得考虑一下,但我认为在这样的例子中,你说得很对,但是这个和这个长的,因为这个方法,排序。
也就是看东西,但我不确定,如果这是一个属性,我可以假设我的意思是看,我想说的是如果你在运行Dijkstra的算法,你关心的是总重量,这才是你关心的,如果你不得不跳,一次额外的得到。
或五倍或一百倍的额外得到,你来吧,所以你知道你说得很好,会是一个吗,跳得短或长,我能假设这条路有多短吗,这不是为了短,我不在乎短,我是说有时候这很好,如果一切都是平等的,也许我想要一个短一点的。
但如果我这么做,因为体重是我想担心的,你知道的,是的,就像数据x从x到a,向后搜索,从X开始,就像做相反的算法,搜索,因为你在说,因为到这里的路不多,而且是的,我是说,戴克斯特拉的算法有很多不同的变体。
我想你会发现,如果你炮制了一个具有某些性质的图,你可能会说,等一下,你可以这样做,你知道的,但是如果你试图写一个对每个图都有效的算法,有各种形状和大小的图形,你在一个图表上使用的任何类似的小技巧。
对其他图形来说会更糟,所以这对任何图都有效,这是一般的,挺快的,啊,啊,所以嗯,如果图表中有循环和循环之类的东西呢,嗯,我想你没事,因为这里面有一些循环不是,这个图中没有循环,是呀,是呀,是呀,A、C。
所以你可以有周期,没关系的,但那是另一件事,如果你有负重边,你可以像哇负能量,你知道的,现在它让我付出了代价,它是,这就像,你看过超人电影吗露易丝·莱恩死了,所以他喜欢飞上太空,他让地球向后旋转。
它让时间倒流,然后她就复活了,然后他说嘿,好像不是那样的,所以如果你喜欢在图表中旋转,试图获得负重,所以你的道路会更好,因为它不是这样工作的,所以嗯,是啊,是啊,我觉得没问题,如果有,如果有循环。
再回答几个问题,今天到此为止,是啊,是啊,所以建立一种向后的开始和退出,你就不能说,好啦,嗯,从终点开始,哪一个有更多的节点连接到它,然后选择一个比较少的,哦从哪个起点,嗯,我是说你看。
Dijkstra算法有各种变体,我没有时间一一谈,我的意思是有一个特别的变化,我确实想谈谈,就像,你们认为,嗯,等一下等一下,我能用一些关于这个图的直觉让Dijkstra变得更好吗。
这就是我星期五要首先报道的内容,它被称为恒星,它使用,这叫做启发式,一种引导,哪条路,它先看一下,基于对图表的一些估计,关于顶点,关于边缘,而这些事情,所以我将向你展示一个相当聪明的优化,就顺序而言。
这可以让事情变得更好,它看东西,我们星期五去,嗯,我能给你们看一下吗,我有这个的动画,我可以给你看看吗?我知道差不多该走了,但让我们看看,作业在哪里,我要把这个分配给你,所以说,这是去年的,不过没关系。
嗯,就像你们要写的这些图搜索算法,所以像什么,这里是中土世界,是你知道的,指环王什么的,所以如果你说喜欢,我要从霍比顿去末日山,我让它慢下来,然后它走得太快了,基本上它选择,哦,现在它走得太慢了。
它基本上选择了一条路,它尽可能地朝着那个方向发展,看它往那边走,哦不,那很糟糕,回去,我们走那边,我在末日山找到的,哦,我先去黑门,所以它选择了那条路,它就像捡东西一样,尽它所能。
你知道如果你做了一个BFS并运行它,挺顺利的,甲板上的下一个是谁,你们这些家伙,好啦,我去找你,我去找你,黄色在排队,绿色在参观,所以这有点像访问节点,再往前一点,再往前一点,在每个岔路口再往前一点。
有点你知道,最终它会找到通往厄运山的路,它将是通往末日山的最短路径,所以这可能意味着他们会走这条路,因为它是,它马上就会告诉我,在那里,所以它去了那边,因为那是最短的,我觉得边缘的重量。
走那条路有多危险,比如有多少埃里克·罗伯茨制作了这张特殊的地图,他说你不能从南方来,直奔艾森花园,疯狂,你得穿过颠茄河,我很好,那是,这就是为什么我不会走那条路,但是如果你用戴克斯特拉的算法。
它先看便宜的,它看着之前的三十个,或者那个很便宜,但它看的是以前便宜的边缘,它看的是昂贵的边缘,所以我相信这个Dijkstra电话会给我们最低的总数,所以结果就是这样,所以它不同于BFS产生的。
这对小弗罗多来说更有可能,从《怪奇物语》里出来的那个人,反正,我要让你们知道,因为我们练习残羹剩饭的时间。
我们星期五见。
【编程抽象方法 cs106x 2017】斯坦福—中英字幕 - P21:Lecture 21 - A Kruskal - 加加zero - BV1By411h75g
什么事?他们是这么说的,年轻人就是这么说的,是呀,我现在听起来年轻很酷吗,因为你,伙计,这个讲座会被免费的,我是说,我有,我确实给我发了一些很酷的话,我以后可以融入我的白话,啊,我知道文学听着。
我去找过罗比,我知道这件事,我都不知道那是什么意思,不过,好吧,嗯,想想看,如果你提到,也许人们喜欢读他们自己的解释,嘿嘿,所以我想感谢你们,你知道这是休息的前一天,我认识很多人,有些人不来上课。
所以我有点害怕,今天会有我们两个人在这里,所以谢谢你能来,我想这一定是,一定有某种斯德哥尔摩综合症,你们就像,我讨厌上课,但我得走了,他让我,我只是,我很高兴你在这里,谢谢你能来。
我们今天要做更多的图表,今天有个任务,我知道你们可能不会,我是说我一周前才给你一个,你想先听好消息还是坏消息,坏哇,好啦,坏消息是还有很多工作要做,会有第八个家庭作业和期末考试,所以还有很多事情要做。
好消息是今天发出的家庭作业七只是一部分,你知道这些作业总是像两个部分,三分十分随便啦,这个只有一部分,我知道我很好,我一定很爱你们,我知道你上周有个任务,所以不,它不是一个很大的公园,反正是。
这个作业可能没有其他一些作业的时间长,但部分原因是我还是想给你喜欢,坦白说,作业八有点像作业七的第二部分,因为它们在另一个世界都有一个图形组件,我今天可能会把他们两个都分配给。
我可能会提前一点发布任务8,就这样出来了,但不管怎样,我知道七号作业,休息的时候会出来的,我想我上一节课说过,我真的不指望你在休息的时候做什么,真的,我是说,如果你六号作业还没做完。
你可以把它吃完什么的,但就像,我不指望你在七号上工作,当你吃感恩节火鸡的时候,我希望你能等到复出,由你决定,虽然对,周一或周二这里有一个问题,我相信决赛是星期一,哦,所以这应该是11号。
我面前没有时间表,我待会儿再检查一遍,我只是不想,我可不想浪费上课时间,但我以为是星期一,但也许这是说十一号,那么这就是应该说的,是啊,是啊,我再检查一遍,它在访问上写的东西都是对的。
也许它真的在这里考试,十一耶,所以我只需要把课程安排好,好啦,是啊,是啊,问题是第八项作业在最后一天会是什么样子,否则任务8就会出现在这里,然后在这里做,决赛就在这里,它没有出现在下一个日历上,星期一。
好啦,是啊,是啊,这就是我们现在的处境。
这就是我们正在做的,我想把它盖起来,现在就跳到图表上,所以我们学习了一种叫做Dijkstra算法的算法,你能给我描述一下,Dijkstra和其他一些有什么区别,到目前为止我们学到的,就像,就其结果而言。
Dijkstra给了你什么其他公司没有的东西,最低成本,最低重量路径,与最短路径相反,像宽度,先搜索右,好啦,酷,它是如何做到这一点的快速版本是什么,如何找到最小权重路径,在如何使用优先级方面。
它与其他算法有何不同,如果您将不同的路径按OFF排序,所以它沿着最便宜的道路和漫长的道路前进,是啊,是啊,这是一个很好的总结,它使用按成本排序的优先级队列,所以它先看最便宜的成本。
所以它找到了最短的成本,最低成本路径优先,是啊,是啊,完全正确,这就是戴克斯特拉的算法,今天我想从,我想谈谈Dijkstra算法的一种变体,叫做星搜索。
我很喜欢这个算法,我在学生时代就学会了,我用它来实现我正在制作的一个游戏,从那以后我一直觉得很整洁,所以这个算法很像Dijkstra,但它有一个具体的优化,我想教你,所以好吧,我想考虑上下文。
我想想想为什么一些图表会有额外的信息,到目前为止我们还没有考虑过,想象一下这个图代表了一个世界或迷宫,或者类似的东西,所以我要把它画成一个二维的正方形网格,但我想让你把它想象成一张图表。
每个正方形都是一个顶点,如果有一条路,如果你能从顶点走到下一个顶点,但就像这家伙旁边有一堵墙,所以那个方向没有边,所以我不能去那里,甚至不能去那里,我拿到了,所以这是一个图表,所以想象一下。
我正试图从这个起点找到一条路,到这个终点c,如果你使用深度优先搜索,你只要选择一个方向开始四处走动,也许最终你会找到正确的目标或类似的事情,但你可能找不到最短的路径,如果使用广度优先搜索,从概念上讲。
你只是一次又一次地把一个扇开,直到你发现它是正确的,你会找到最短的路径,因为这是搜索的第一个红色,它能找到最短的路径吗,这是很好的dijkstra算法。
如果你在这张图上运行Dijkstra的算法会发生什么,按成本排序,最低费用,路径,它会做什么,不行吗,我是说Dijkstra的算法是关于成本或重量的,这不是一个加权图,我会在非加权图上做什么。
你觉得怎么样,是啊,是啊,只是和,就像在每个盒子里一样,是啊,是啊,这是正确的,我很久以前提到过,如果你有一个未加权的图,你可以假装所有的边缘都有一个重量,同等重量或零或其他什么。
所以如果你运行Dijkstra,它将使用一个p q,但是PQ排序不会很有趣,因为他们都有一条领带,所以它会把它们分类,它会根据你添加它们的顺序对它们进行排序或其他什么,或者按字母顺序什么的,所以本质上。
我想说的是妮塔基本上也会这么做,作为广度优先搜索,它就会散开,因为所有的路径都有一个成本,所以他们会按顺序尝试,所以是的,在未加权的图中,Dijkstra算法向广度优先搜索发展,实际上,如果你仔细想想。
有那么一秒钟是有道理的,因为在图中所有边的权重都是1,最小权重路径,根据定义是最小长度路径,因为重量和长度是成正比的,好啦,所以这就是它现在所做的,我再提一个问题,Dykstra的算法应该做好什么。
我是说,你知道的,如果我们想聪明点,记住什么药品管理局,和一个搜索是要做的,就是,它们会向各个方向散开,直到他们最终找到一条通往这里的路,关于这个图或这个问题的任何直觉,可能比那个算法更好,是啊,是啊。
我想我们的直觉是,我想去那边,我想去右边,至少我是说,如果我知道像一个有坐标一,它的坐标是5,不管坐标是什么,如果我知道我要往东走,最终我的目的地是东方,好像我得走很远才能找到一条路,到达目的地。
但如果是那样就更好了,如果我能走过去,或者如果我能走到那里,然后稍微让开一点,为什么我不试着向右而不是向左,我最终可能需要向左看,但一切都需要平等,如果我试图分散所有这些方式,在走那条路之前。
我为什么不走这条路,在我回去之前再往这边走一点,你明白我在说什么,所以说,让我们利用我们所知道的边缘的空间关系,图表上的节点,这就是这里的直觉,所以这里有一个观察,Dijkstra算法使用优先级队列。
据我们目前所知,戴克斯特拉的想法,我展示了迪克斯特拉的幻灯片动画,我们去过的地方,一组特定的顶点,它们是绿色的,我们也有线索,一组特定的顶点,它们是黄色的,所以被拜访的人,我们知道所有关于。
我们知道到达的最便宜的成本,这就是为什么我们曾经拜访过他们,我们参观了PU,并从PU中拿出了一些东西,并将其作为绿色产品进行营销,这是你能得到的最便宜的顶点,我们确信这些黄色的还在PU里,没有拔出来的。
但那些我们略知一二的,还有一些我们甚至还没有看过,我们对此一无所知,Dijkstra的算法是基于我们目前所知道的,关于如何从起点到中点,我们也许能推断出,从中点到最后一点更有可能发生什么。
回到这张幻灯片,就像如果我从开始到这里,假设这个正方形,如果我从开始到这里,我可以说好,也许通往这两个地方的道路彼此的成本非常相似,从n开始,我喜欢在这里比我喜欢在这里,只是因为它在这里离目标更近。
所以如果你知道这些东西的位置,你可能会,如果你知道一些关于这可能需要多远的估计,从中点到球门,也许我们可以把它合并到算法中,唯一棘手的部分,虽然是像你不确定像,我是说,如果你看这样的图表。
如果我看这个正方形,我去,哎呦,你知道那个方块离目标只有一二,那是个好广场,但实际上他有墙,所以你不能就这么去,你可以绕着走,实际上你可以想象有这样的墙,所以像这样走完全没有帮助,你知道我的意思。
所以我觉得他很好,但他实际上可能并不好,所以它是它是一个,你可以有一种直觉或猜测一条路有多好,或者一个方向是或者一个顶点是,但你不能肯定,你知道的,好啦,所以让我们来探索我们可以说的未知距离,这又是。
如果你想的是一个二维的空间图,三乘四,这些是到达所有这些方块的成本,对呀,好啦,我们想走那条路,所以这条路走错了方向,算法并不真正理解这一点,算法根本没有考虑到这一点。
如果我们能给算法一个提示,让我们来谈谈一种叫做启发式的方法,启发式是个花哨的词,只是估计一下,有教养的猜测近似值,启发式的一个例子是当电子邮件进入你的收件箱时。
一组代码查看电子邮件并给它一个垃圾邮件评分,这条信息有多垃圾,分数是基于几件事,就像,你知道的,寄给了多少人,是谁寄来的,留言的内容是什么,留言的主题是什么,所有这些事情都是对的,基于这一切。
他们给它打分,我们认为这条信息在垃圾邮件量表上是11。6,如果超过一定的阈值,我们现在把它放在你的垃圾邮件过滤器里,你们可能知道垃圾邮件文件夹并不完美,也许你经常去那里看看,有一个真正的信息。
它不应该放在那里,但主要是对的,所以估计,这是公平的猜测,经常是正确的,但并不总是,那是垃圾邮件启发式,有时也叫做贝叶斯滤波器,但是,所以在图的上下文中,如果我们能估计中点在到达目的地方面有多好。
这就像是一个启发式,有一类启发式,我称之为可接受启发式,这些都是小于或等于实际答案的启发式,所以基本上他们过于渴望,我是故意提到这个的,因为我要教你们的算法很重要,所以一个可接受启发式的例子。
如果我回到这张地图,如果我问这些不同的顶点,像这个那个什么的,我想知道这个顶点有多好,我喜欢吗,我喜欢从这里到这里,一个可接受的启发式可能是从这里到这里的距离,就像从一个到另一个的直线距离。
这一个有一定的距离一二三四五六七八九十十一,这个距离是一二三四五六七,也许这个是七个,那个11岁,就优先级队列而言,我更喜欢七一,或者类似的东西,但还是低估了,这是个乐观的猜测。
正确的答案要么是我的猜测,要么更糟,也许有一堵墙,我得绕过去,或者一些乐观的猜测,这肯定会小于或等于真相。
称为可接受启发式,在算法的上下文中,今天我要教你们,能够想出一个可接受的启发式是很重要的,所以这个算法是启发式的,他们总是喜欢关心距离吗,我想这是最容易理解的例子,嗯就像。
我想学生们真的会得到像这样的空间例子,因为这就像,啊,这个顶点比较好,因为它更接近那个,但想象一下,我在两个单词之间寻找单词阶梯,就像你们尝试所有不同的,你先找的面包对吧,所以你可以做一些很好的事情。
如果我把这封信改成那封信,那是一种可能的途径,如果我把这封信改成那封信,那是一条可能的道路,哪一个比较好,如果我同时考虑这两种可能性,这个与目的词不同的字母较少,我不是很肯定,我可以从这里得到目的地词。
但我喜欢这样的开始,因为它似乎离目的地更近了,所以也许在一个单词阶梯的例子中,不同的字母数量将是一个启发式,所以国家的情况是,你能做的,的编辑距离,看起来错误的字符数,基本上你可以把它加起来。
并说最小的变化和跳跃数,我必须从这里到达目标,如果每一个中间状态都是一个有效的英语单词,因此,我不能比这更快地到达目的地,但我可能需要更多的时间,所以这将是一个可容许启发式的例子,基本上,但是是的。
无论如何,空间的是最容易的,我想只是想象一下,你知道的,好啦,所以我只想说清楚,不是每个图都有顶点的启发式,有些人这样做是因为图表代表了一些我们有其他信息的东西,就像这是一个关于迷宫、地图或字梯的图表。
所以我知道一些关于这些中间状态的东西,我可以用在我的推理中,但我只是给你一些随机的图表,节点和边可能有也可能没有这样的启发式,我教你们的算法叫做星形,它是Dijkstra的改进版。
你所做的唯一改变是当你达到这个顶峰时,Q,记住,p q存储顶点是基于到达顶点的成本,你所做的唯一改变就是加入一个启发式,它是到达顶点的代价,再加上一个启发式的有多好,我想顶点是你把这些加在一起。
这就变成了该节点的p q得分,这会稍微调整PQ的排序顺序,并调整pcube的排序顺序,调整签出路径和访问路径的顺序,这将导致算法在某些图上运行得更快,所以在寻找从a到c的路径方面。
顶点是b是PQ中的顶点,它不仅有达到它的成本,从地塞米松,但它也有估计的启发式,它可能要花多少钱,从这里到达目标,我们将这些元素相加,形成您添加的元素的优先级,所以让我试着给你们看一个例子,回到这个图。
就在这里我们已经讨论过了,我是说PU里的东西的成本是字面上的,只是到达它的步数,启发式将是到目标的直接距离,忽略任何墙壁,所以像这样的东西,对于这种特殊类型的图,这将是一个启发式。
每个广场我不需要任何联系人,只是我可以告诉你一个分数,这个分数这家伙有启发式,一分,因为它就在一个广场之外,这个是两个,这个是三四五,但你会再次注意到,就像你不能在三个酒吧里到达那里,因为有墙挡着路。
但在一个完美的世界里,就是这个权利,所以这对这些人来说是一个启发式,当你这个,这是Dijkstra算法的伪码,有点斑点,但基本上是把东西从PU中拉出来,用成本把邻居放进去,这就是这个想法,这是分级的。
因为那是dykstra,恒星是完全相同的代码,但是哎呀。
所以是不同的字体大小,啊,太烂了等等,看起来不太好,如果字体不一样,我以为你和我一样,怎么样,那工作吗?来吧,伙计。
好近啊,但是看这里,它好像动了一下,哦好吧,没关系,就像,这是似曾相识,新零件的蓝色部分,而不是用目前到达它们的成本来储存东西,这就是你所做的,按成本将它们存储在PQ中,以到达它们到目前为止。
加上他们从中点到球门的神奇启发式得分,就是这样,你只是,你只要要求算法包含额外的信息,所以我的意思是,算法似乎没有很大的变化,它对行为有很大的改变吗,它很好,当然可以,哦,天哪。
我真的想在这里遍历这个例子吗,让我做点不同的事,我想像你们必须做的家庭作业7一样跑,开拓者的事,我会运行,我认为这是最好的例子,我可以给你看,这是一张旧金山的地图,我不知道,我不去旧金山。
所以我猜这就是旧金山的样子,它实际上有很多顶点,也许我不会从这个开始,也许我会做嗯,也许我可以画张斯坦福的地图,这个很酷,这里是斯坦福,我也不常去斯坦福,所以说,是啊,是啊,我们在哪里,我们就在这附近。
是啊,是啊,我们就在这里的某个地方,但不管怎样,嗯,加州大火失控,嗯,就像如果你点击顶点,它开始正确地执行算法,所以如果我点击这里,然后我点击这里,它现在开始散开,有点难看,但就像它是这样的。
它往这边走,你知道的,它在探索两者,这很酷,如果我把算法改成星形,哦,它必须访问总共576个顶点,所以如果我把它换成星星,我运行相同的算法,它访问四个八个顶点,因为基本上它就像,它可以选择走这条路。
也可以选择走这条路,就像等待,球门在这里,那么为什么我现在不走那条路呢,如果你有敏锐的眼光,你会注意到它确实朝其他方向走了一点,这并不完全是正确的,有点偏离了道路,但它试图将其最小化,因为它不想。
它认为我想朝着目标前进,如果可以的话,也许另一个例子,我可以用这些迷宫,也是,你们以前玩过迷宫,所以如果我用Dijkstra的算法从,从这里到这里,它现在扩散得很均匀,这是一个未加权的图。
所以堤坝运行本质上是一个粘合剂,广度优先搜索,所以它就像扇形一样,它看起来不像是呈放射状散开的,但那是它在每条路径上散开,它可以径向跟随,它看着一千七百个方块,但是明星会说,嘿嘿,我从这里开始。
我想去那里,所以有点,如果我能往右边走,我想看一下,也许比左边多一点,如果我能下去,我想做的比起来多一点,所以如果我用星星做,而不是看1798个方块,它看着,八四九,所以现在我可以再运行一次,慢一点。
就像你可能会说的等等,看起来一点都不酷,好像走错路了,发生什么事了?我以为你说这样会很好,现在没有办法走那条路,所以它是在挑它能挑的东西,但是你看,你看到现在的情况了吗,它走对了很多,只要能走对。
会这样的,如果它找到一条正确的路,它真的要把它,所以我不知道这很难理解,从这个例子中,让我看看能不能找到一个不同的例子,嗯,让我看看5月7日,哎呀哎呀,停下走,五月七载,好啦,这个怎么样。
我要从这里到这里,你看到它有多想朝它走去吗,如果你仔细观察,它会离你有点远,如果你像每次结束时一样看着这些坏蛋,它会像这样,所以我想知道我到底是怎么想走那条路的,因为这就像,我想我几乎,你知道的。
真的很想走那条路,但那个没有成功,现在它有点喜欢这个,这是最低限度的看到那里,是这样的,所以算法真的像,向球门倾斜,你可以看到它这样做,它访问了五百九十一个广场,有了Dijkstra,它一点也不倾斜。
所以你会在这里和下面看到更多的东西,我觉得,所以让我们看看它有多长,加速一点,所以它只是更多,只是均匀地展开,它的价格是1千4百对5千9百1,所以你可以看到使用星型算法有很大的改进,是啊嗯,自从搜索。
我们就像停在,就像第一条路,我们不能保证,最短路径,嗯,哪里能保证我们有最短的路径,你很好,在这种情况下,这些是未加权图,在未加权的图表中,Dijkster和e星都会找到最短的路径,但在加权图中。
迪克森和一个明星可能想走一条更长的路,如果比较便宜的话,实际上,我认为这个程序将使用不同类型的图表,如果你把这些地形图,这些有点有趣,地形图是,有点难以理解,因为它看起来像一个很大的斑点,就像以前一样。
我有激光,一切看起来都像那样,基本上,但是嗯嗯,这是一张头顶地形图,就像你从太空或天空或其他地方往下看,较浅的颜色就像更高的海拔,就像山顶或山顶什么的,较深的颜色就像一个小山谷或峡谷什么的。
所以这个图的思想是你不能真正看到顶点,因为每个小正方形都是一个顶点,他们都是邻居,在那些,在他们旁边,八个方向,所以这里没有真正的墙,但上坡的优势更昂贵,所以如果你在黑暗中,你要从那边上去。
这些边缘让你付出了更多的代价,所以我想这里的想法是,如果我想从这里到这里,两者之间最直接的路径就是翻过这座山,但我不得不爬上山,走过去,走下去,但也许我要绕着山走一圈,所以如果我用。
如果我用广度优先搜索从这里到这里,让我们在这里说,它就会均匀地散开,因为它是先读的,这正是它应该做的,它就会散开,要花点时间,说下去,布雷特第一,你能做到的,哦伙计,我去把延迟关掉。
现在你可能会说等等什么,这还不是最短的,别担心那个,看起来不大对劲,但基本上死了也算一个,就像直线房子一样,所以其实扭动并不是,即使看起来不对,没关系,这是最小长度,但它就在山那边,基本上是这样。
如果我使用Dijkstra的算法,你会看到哇,太快了吧,我再试一次,戴克斯特拉算法,它是扇形的,我喜欢它,因为它看起来像你把液体倒在地图上什么的,它是不是会扩散,而且会在低处扩散,现在呢。
你会看到它有点不想上山,你看到了因为那很贵,所以它有点不喜欢走那条路,所以它之前在这些黑暗的地方流动,这不是星星,所以它不是想下去到这里,它只是想避免上坡,如果能避免的话,好啦,它试图避免昂贵的边缘。
所以它会散开,它会变得比光明更黑暗一点,它最终会找到最小重量路径,我的猜测是,与其走这条路,像以前一样,它可能会绕着山走,在这里,你可能会发现一个小切口,没有更多的侧面,稍微穿过这座山是值得的。
但可能会更像这样,我猜,让我们一探究竟,是啊,是啊,所以它穿过了一点点山,但它避开了这里最热最宽的部分,好啦,它必须查看11000个顶点才能做到这一点,让我们再看看一颗星星,你现在将要看到的。
不像迪克斯特拉,呈放射状散开,你会真正看到的,想要向球门走去,我想是的,我们试试看,所以我放慢了速度,但看看它在做什么,它下面的液体还在涌出,但涨幅不大,多下去是一回事,有点难看,但是嗯。
如果我再快一点,看看它有多想下去,它并没有像这里一样蔓延开来,更多的是往下走,现在看,它在往上一点,它确实上去了一些,你知道的,因为在某种程度上,去那里总比不去好,所以它找到了相同的路径。
相同的成本路径,但它看着,你知道4000个顶点而不是11000个顶点,是啊,是啊,启发式也是,通常被认为更有方向性,比如当启发式或某种矛盾,实际的喜欢,就像如果它是真实的路径,这实际上是更好的权利。
所以我的意思是我要稍微挥舞一下我的手,但基本上只要你有一个可接受的启发式,它不会弄坏任何东西,我是说,我们主要要注意的是,如果我们认为我们在做一些聪明的优化,但我们实际上并没有找到最小重量路径。
这是不对的,就像这里的重点是找到最小重量路径,我可以直接下去,但这不是最低重量,所以有一些优化会打破这种权利,可接受启发式的整个想法是,如果你的估计小于或等于正确答案,那就意味着它不会打破你的巅峰,问:
如果你估计的比正确答案更糟糕,它会导致一条好路在PU晚些时候走,然后你就不看了,这将对你的算法造成很大的损害,因为也许有一条更好的路,你懒得去看,但是因为我们对目标有这些积极的估计,直接去目标。
会让你达到顶峰,我们不会看着一个不守规矩的人,基本上没问题,所以我的意思是还有更多,但那是本能,这就是它的直觉,你还说了些别的,这些启发式也是,基本上是空间的,就像往那边走,他的问题是关于同样的事情。
我给他举了一个单词梯子的例子,如果我在图表中搜索单词阶梯,你可以选择去一个邻近的词,这更类似于目的地词,比如,例如,我正从,你知道的,猫变狗,所以我可以把猫变成被抓住的被抓住的O,那更接近于狗。
因为它和狗有一个共同的字母,对呀,或者我可以把猫变成老鼠,仍然有三个字母和dog不一样,所以你可以在尝试老鼠之前尝试被抓住,因为启发式地,理论上,两步就可以把被抓住的人变成狗。
而我知道老鼠至少需要三步才能变成狗右,所以这将是单词梯形图搜索的启发式,你知道这是可以接受的因为,我的估计不可能大于正确答案,如果我抓到了,我想要狗,我知道我至少还需要两个动作,所以我的启发式是两个。
所以正确的答案不可能喜欢相似,是啊,是啊,我想说,所以它得到了某种分数,就像有多好,如果你有办法精确地,相对于正确的答案,这个要好多少,这就是你想要的,是啊,是啊,所以我想我明白了法律永远不会。
这是最小到不可能的,就像发生了什么,如果你低估了秩序。
就像命令你搜索一样,就像你还在看低估,但实际上较短的路径低估了小于1的路径,是啊,是啊,是啊,是啊,嗯,我不知道我是否能给你一个答案,那真的会让你满意的,喜欢,基本上,所以我认为你说的就像。
也许我把他们是因为我的启发式,你在担心,也许我的启发式太好了,所以它在pcube中太早了,对呀,所以我的意思是我认为我能给你的最好的本能是,它会让你早早地看着某人,那会导致你过早地看某人。
对或者像这样的情况,假设你是,你的准确性总是被低估了,但接下来发生的事情是它切换顺序就像一件事,到那里实际上需要更长的距离,但它来得更早,好吧,我的意思是我不认为我有一个好的幻灯片喜欢。
我想在视觉上更容易说明,但基本上会发生的是,你可能会导致这可能会导致你走上一条路,这不是正确的答案,但在你到达终点之前,就像你会离目标更近,但你会发现,哎呀,有一些昂贵的边缘我没有考虑到。
这些昂贵的边缘会增加启发式的前成本,你到了哪里,这将导致你在PU后面要去的地方,所以从数学上来说,会让你误入歧途,但这不会导致你完全走上错误的道路,就像你会接近错误的答案,但你会停下来。
因为数字会追上你,现在你的PQ顶点会在后面推,正确的一个现在会在你前面冒泡,所以我的意思是,我不认为我有办法在视觉上,只要给你看,但就像它自己解决了一样,没有打破算法是一种方式,我想看看。
你对此有何评论,你觉得像一颗像一颗星星,哪里像,当然可以,那很好,这样想是完全合理的,Dijkstra是一个对每个人都有启发式的明星,具有零启发式,不是说得太清楚,但如果我在实现算法代码。
这可能是避免两个算法之间冗余的好方法,是呀,另一个评论,是啊,是啊,你有没有一个图表的例子,你开始的时候比我差,我有一个图表的例子,一个明星做得更糟,所以根据定义,它不能做得更糟,如果是这样,它就坏了。
所以如果一个明星做得更糟,意思是你的启发式函数错了,因此你不应该用星星,或者像你的图表没有句点。
所以我就给你看看我们的开拓者节目,在这里运行一个明星是有效的,因为我们有关于身高的启发式,它也适用于运行一个明星。
就像这张旧金山地图,或者别的什么,我可以用这里到这里的直线距离,作为我是否要走那条路的启发式,但我有一些其他的地图,就像我有一张中土世界的地图,中土世界的地图,这里的边不是基于,像x y坐标距离。
那个30岁,那个50岁,那是一条很长的边,但现在是十五,埃里克·罗伯茨教授制作了这些边缘砝码,根据他发表的中土世界的路径有多危险,根据他对,他很棒的方式,你应该多了解他,嗯,加权是基于一些非空间的东西。
对这些重量没有特别的直觉,只是因为我喜欢伊森加德,是个不错的地方,他们要把哈比人带到,那是个好地方,你不知道那首歌,谷歌一下,这首歌有十个小时的版本,嗯,没有办法,你可以直觉到确定有多好。
你可能会说我想走那条路什么的,但是边缘你没有感觉,从你所处的位置看你周围的边缘会有多波浪形,所以这个特定的图在图的信息中,我已经禁用了启发式功能,所以如果你在上面运行一颗星。
你只会得到与灵巧算法相同的结果,仅仅因为这张图表,我无法想出一个真正有效的利己主义,所以你问我,开始怎么样,如果它打破了图表怎么办,基本上如果它能,你不应该使用启发式函数,你基本上不应该有明星。
区分自身与危难,所以它总是必然的,因为它不太为人所知,而不是很好,它可能会访问相同的节点作为额外的在ristic或零,但是如果你尝试像这样应用这个,基本上看,如果你在这里用x y距离作为启发式。
你跑了一个明星,对恒星使用启发式会给你错误的路径,所以我不想那样做,是啊,是啊,所以呃,不管你是在没有启发式的情况下运行这个,或者按你说的做,所以它不会检查更少的节点,威尔,它会做Dexa做的事情。
它就会,它只会找到同样的一半,我也有道理让你点击迷宫,我的问题基本上是,你能做个迷宫吗,你就像挥舞着堆栈,所以它总是向上的,你好像很想往右边走,但你不是真的,所以一颗恒星需要比,啊。
你能让一个明星做最糟糕的事情吗,严格意义上来说是更快还是相等,不错的下降,是啊,是啊,这是个好问题,我觉得答案是,如果我,如果我做了一个迷宫。
好啦,我怎么画,别读那个,如果我做一个像这样的迷宫,我从这里开始,我想走到这里,就像你在一条路上一样,就像那样什么的,你喜欢这个迷宫是个很棒的迷宫,好啦,我想我们谈完了,所以一颗星星可能会更想走那条路。
想象一下我把中间的部分,所以它真的很长,就像,哎呀,就像一条错误的道路,所以我可以想象一个明星会更多地往那边看,这可能是件坏事,我认为最重要的是它找到的路径仍然是最小的,轻量级路径。
所以它不会找到一条更糟糕的路,我想这可能是真的,我最近没想过这件事,但我想这可能是真的,一个明星可能会看到更多,顶点在这样的例子中,这有点歪斜,伤害了一个明星,但我认为明星的部分目标是。
如果你看看我们处理的很多图表,你不可能落得如此可笑的下场,所以你依靠图表不太可能陷入,就像你必须非常仔细地构造一个图表来制作星球大战,你知道它在所有的图表中都要好得多,你可能会看到,是啊,是啊。
在这个例子中,当戴克也必须经历,是啊,是啊,我想Dikstar会去所有这些方向,所以我想Dijkstra会在某个时候来这里,所以它不会成为一个大明星,因为在明星搜索中,女性的任何路径。
似乎德威尔在搜索之前也搜索了一下,是啊,是啊,我想这可能是对的,我还没想过,如果你从来没有见过这么多带有星号的顶点,那是真的,我不知道今天的对抗性图表,但我明白你的意思,在本例中。
我想迪克斯特最终会把这条错误的道路检查到正确的地方,所以我想我的例子还没有击垮德克斯特,所以我得多考虑一下,虽然,你对,我想到了一个例子,也许有一个开始,有点来来回回,离那时越来越近。
不管是什么它都会试着往下走,因为它比,是啊,是啊,我是说,也许我们把它放在桌子上,呃,我会考虑的,我得喜欢,试着画一些邪恶的图表,看看我能不能引诱它,我觉得最重要的是,不过,你不会在恒星中走更糟糕的路。
只要你有一个有有效启发式的图,你会没事的,这不会让你得到更差的结果,那很重要,所以好吧,嗯,那现在是明星了,我之前想给你看另一件事,我们今天没时间了,等等,在哪里?
它在哪里,这个呢,我想谈谈一种完全不同类型的图算法,叫做生成树,今天差不多有时间了,接下来我会做得更多,打破它后的星期一,但是生成树是我们作业最不需要的,所以我想教你们什么是最小生成树。
我想教你们一个找到它们的算法,称为克鲁斯卡算法,所以这里有一个特殊的动机应用程序,假设我们有一个迷宫,迷宫是一个方根的方格,你知道屏幕上的二维正方形,我们的顶点就像迷宫中的小方块,我们在它们之间有边缘。
没有墙在它们之间行走,所以这些就像,这不是迷宫,因为没有围墙,基本上,但是如果你把墙竖起来,就像嗅这些边缘一样,从概念上讲,你会有一个迷宫,如果我想喜欢呢,生成随机迷宫,嗯,你知道我想要的基本上就像。
如果我剪掉一条边,就像这里,我现在基本上在这里创造了一堵墙,你们几个星期前就知道了,我在骗你,因为我基本上是在给你一个图表问题而没有告诉你,这就是我的一个洞,我喜欢强迫你做作业七。
家庭作业前的材料方式七,所以基本上生成迷宫的一种方法是,如果你把迷宫想象成一个图表,尝试生成图的生成树,生成树是当你把一个图,你把它的边缘子集,所以在图中所有的顶点都是相连的,但没有任何循环,你还记得。
循环是你绕过并回到你开始的地方,所以如果根本没有循环,你有一棵生成树,就像,下面是一个生成的示例,对不起动画不太好用,但是这里有一个左边图的生成树,我刚刚嗅出了这张图的一些边缘。
每个人都与每个人联系在一起,你接触到每个人,但没有循环和循环,你不能,你不能回到你在这个图表中开始的地方,一个完整的连通图是一个每个人都可以到达任何地方的图,这就是一个完整的图。
从每个人到每个人都有直接的优势,所以无论如何,这就是生成树,迷宫是两个D图的生成树,如果你剪掉一堆边缘,我是说如果有一个有循环的迷宫,但如果你嗅出边缘,直到你有一棵生成树,这确实是一个很好的迷宫。
是生成随机迷宫的好方法,所以好吧,这就是生成树,生成树的变种称为最小生成树,它是这样的生成树,在树的所有边缘中,你有最低的总重量,那是可能的,我的照片没什么帮助,因为我想我应该换这张照片。
但基本上这个想法是看到,我是如何嗅出某些边缘来得到这棵生成树的,但我本可以保持D而不是E对,你看,我本可以保留d,删除b,那也是一棵生成树,他们同样好吗,这个想法是,如果d的速率低于e。
我应该尽量给你买最便宜的,同时让每个人都有联系,如果你一直这么做,这叫做最小生成树,从技术上讲,它是一个生成树,没有其他可用的生成树,对于权重之和比它低的图,我的照片很烂,所以我没有在边缘写重量。
但我想我要跳过这张幻灯片,我将跳过这张幻灯片,所以我想举一个不同的例子,所以有几个例子,可以用来在图中查找扩展树的几种算法,我想教你们的是Kruskal算法,这相当简单,你在几周前的家庭作业中学到了。
你把图的所有边都去掉,您根据成本将它们放入优先级队列,然后当PU不是空的时候,你把边缘拉出来,如果那条边的端点没有相互连接,但你把边缘放回图表中,这基本上就是你在家庭作业中对这些集群所做的,对吧。
你把事物的顶点聚集在一起,这就是这个算法,基本上,所以这里有一个图表,你知道,我只是它是相同的算法,但是用一种更生动的方式写的对吧,所以现在我得到的是所有的边缘都有名字。
然后它们有与之相关的边缘成本边缘权重对吧,所以如果我把这里所有的边,算法要先看哪条边。
一种权利,好啦,所以让我们一起做吧,所以P Q是对的,所以我们从PQ中抽出一个,我想在图表中保留A吗,是啊,是啊,好啦,我们留着吧,我们有一个,所以这两个家伙现在是有联系的,我们把b从p q中拉出来。
我想留B吗,B在哪里,在这里,你想留着吗,是啊,是啊,你想留C吗,是啊,是啊,我当然想留下D,是啊,是啊,我没有那个顶点,基本上任何顶点我还没有,我会保持他的优势,好啦,我想留B不,因为我已经有办法。
我能把它擦掉吗,啊,全部组合在一起,等一下等一下,我可以,让我们看看,取消分组,我可以点击一个边缘,如果我只是删除它呢,哦耶,不要保存此行文件,不要保存它,所以我只是我删除了e,我不留e,我有F,做。
我想确保,我们留着吧,因为我还没有这个人,呃,那么g do呢,我想留着G不,我已经得到了这两个顶点,我已经可以联系到他们了,我不要那个,呃,我想要H,我想我知道,因为这里的这些人聚集在一起,对了。
这两个在一个集群里,这些团块还不能到达彼此,所以让我们保持h do,我想要,I,加上这个新来的家伙,当然,我会留意的,J do,我想要J不,好啦,这是一个新的顶点,所以我会保持他的权利,十二点在那里。
是或否,否,我已经够到他们两个了,他们已经有联系了,我十三岁,我想那样吗,我想没有,因为我所有的人现在都连成一团,难道他们不喜欢我,如果我,如果是M,把这家伙和这家伙联系起来。
我可以一路绕着这里到达目的地,所以我不需要我,好啦,那n呢,我不要,因为我已经可以联系到那些人了,哦十五,我不需要那个,我可以绕过去,P在上面,我还没抓到这家伙,所以我会保持PQ是17,我不需要那个。
因为我已经可以到那里了,然后我们有我们的,我想我不需要弧线,因为他们已经联系在一起了,这就是我的最小生成树PowerPoint风格,我们知道根据算法的性质,我们知道这将是最低重量,因为它先看便宜的边缘。
所有这些东西,所以你们基本上已经实现了这个算法,所以我不会在这上面花那么多时间,对吧,但现在我们正在重新考虑,作为一个图形问题,现在呢,它的许多实现挑战仍然是一样的,跟踪集群,但你们之前已经考虑过了。
所以这对你来说应该不难,但如果我给你一个基本的图形对象,我想让你做最小生成树的事情,你可以做对的,这就是克里斯奥尔的算法,如果我再运行那个开拓者程序。
它对算法的作用是,如果你说我想要一个随机的迷宫,它将在一个连接的迷宫上运行kruskal。
我不知道为什么它做得这么宽,但你想看到一个巨大的迷宫,让我们做一个随机的色调迷宫,巨大的迷宫,哇塞,让我们在这东西上看到一些星星,所以无论如何,你要在这些图表上写Kris Gal的代码,你要移除边缘。
直到生成一个随机迷宫,最终要花很长时间,因为我认为既然它是一个最小生成树,我想这意味着实际上只有一条路可以到达出口,所以一种方法可能就像真正的迷宫,它没有停止,它还在工作,它是,情节扭曲从地图上消失了。
是啊,是啊,就像那样什么,那个愚蠢的谜题是什么,就像,你得到了九个点,你应该用四条线把它们连接起来,你走右边,什么事?你就像一个,你最终会在那里,好像我做错了,你是做什么的,你就像那样,你得到了所有的。
或者任何权利,你用四条线把它们连接起来,所以嗯是的,那是一回事,所以无论如何,那是克鲁斯卡的算法,所以你的任务,我是说你看到了所有这些不同类型的图表,就像小地图,你看到了迷宫,你也看到了那些地形高程图。
你的代码不关心这个,我只是给你一个基本的图形对象,可能与这三件事中的任何一件,所以你不必担心它是哪种类型的图,然后我只要求你运行深度第一搜索广度,第一搜索Dijkstra算法,或者上面有星星。
你只需要实现那些算法,我们已经全部了解了,然后第五个函数你答对了,你得创造一个随机的迷宫,利用克里斯·斯凯尔斯的算法,所以这就是作业七,我想你们应该能处理好,嗯,还有更多,我将在周一休息后谈谈图表。
但在第八作业之前我们不需要剩下的,所以我就到此为止,希望你们感恩节假期过得愉快,去休息一下,见你的家人和朋友,玩得开心点,一周零几天后见。
【编程抽象方法 cs106x 2017】斯坦福—中英字幕 - P22:Lecture 22 - Inheritance, Hashing - 加加zero - BV1By411h75g
最近怎么样?人们欢迎好的回来,这是呃,星期三,现在是第十周,我不知道你们做得怎么样,你们把休息算作第九周,今天是第十周,所以这是第九周,你们这些家伙,是呀,我不在乎什么,你数数,我的日历上写着第十周。
所以现在是第十周,这是第九个,真实周,我想是的,不管要看情况,无论你是从零开始数还是从一开始数,计算机科学的东西,我们一直在做图表,在这一点上,我们基本上完成了图表,当然,关于图表,你可以说得更多。
但我们得把它留到改天的其他课上,我们也谈了一点关于继承的问题,今天我会多讲一点,第八个也是最后一个家庭作业现在结束了,昨天涨了,这是一部份,我知道你厌倦了这些多部分的任务,所以最后两个任务。
你们只有一部分,每个家庭作业八个被称为斯坦福,一二三,你得做一个电子表格,它基本上是一个非常普通的矮胖版本,像Excel或谷歌工作表,或者类似的东西,嗯,作业中最难的部分是重新计算所有的公式。
就像如果细胞互相引用,就像这个等于那个乘以那个什么的,你得计算出所有这些值,这些值之间存在依赖关系,我想让你代表电子表格中的单元格,使用图表,基本图对象,所以作业规范谈到了所有这些。
单元格中也有不同类型的值,可能只是一个数字,也可能是对单元格的引用,也可能是一个公式,也可能是一系列细胞的功能,单元格中有这些不同类型的值,这些值被表示为继承层次结构中的对象。
你必须实现这种行为的一小部分,的值,所以这里面有一点遗传,不管怎样,你可以晚点再看,下星期五到期,所以这是应得的,你知道在这里,我只想澄清,你知道你可能不想交家庭作业,我建议晚点。
因为那个周末是你准备期末考试的时候,也就是下星期一,所以如果你在八号任务上迟到了一天,你在浪费期末考试的学习时间,所以我不推荐,还有一件事,因为我们得给作业打分,我最多只能让你用一天的时间做家庭作业。
我不能超过一天,所以说,不管你是否还有迟到的日子,星期一六点以后就不接受了,所以我想就像,如果你想过危险的生活,你可以晚一点做作业,你可以在12月11日星期一上午参加期末考试,十一点半你可以跑回家门口。
你有大约六个小时完成家庭作业,在翻页被切断之前,我不赞成这种想法,但是嘿,你知道的,你们中的一些人喜欢生活在危险中的刺激和冒险,是啊,是啊,嗯好吧,无论如何,所以说了这么多,我们今天和明天要做的是。
我今天要做更多的遗产,然后我将继续讨论哈希集合是如何实现的,和哈希集哈希图,我今天的目标是深入一点散列,即使它被列为明天的话题,我只是想在这方面先行一步,本周你的部分也会有一些关于继承和哈希的问题。
好啦,所以让我们回到我关于继承的幻灯片,我们已经知道什么是继承,它是类之间相互关联的时候,当他们建立在彼此的基础上,一种亲子关系,基类和派生类,我向您展示了继承的一些语法,你还记得在C++中。
如何指示一个类是另一个类的子类,你怎么说你只是把一个冒号,然后将父类名称正确,就像我们有一堂课叫。
啊,这个不对,我们有一个叫雇员的班,员工看起来是这样的,只是用一些非常简单的方法来获得假期和工资之类的东西,然后嗯,然后我们发现如果你想写一门叫律师的课,律师说它用这个冒号延伸员工,对呀。
所以这是大部分,另一件事是我教你虚拟这个词,这是怎么回事为什么我需要知道,当我做遗产的时候,那有什么用,是呀,我们可以允许方法被类覆盖,基本上,它只是向编译器表明你可以,如果子类重写此方法。
如果你真的想知道更多,这里有一个叫做动态方法绑定的概念,有时称为虚方法绑定,这个概念的意思是,这个程序是否应该弄清楚,在编译时和运行时执行哪个方法,长话短说是虚拟手段,在运行时选择方法。
这真正意味着如果你有一群员工,但他们中的一些人是律师,他们有些是医生有些是秘书,它实际上在运行时,询问每个对象,你有什么方法,我到底该叫哪一个,而不是调用同一方法的公共基版本,但不管怎样。
不管是什么简单的版本,如果你说虚拟,它允许子类重写方法,我想我在上一节课简单地提到过,但即使你不说虚拟,编译器将允许您重写方法,它将允许它不会犯错误,但问题是在很多情况下,它实际上不会使用新版本的方法。
您在子类中编写的,所以它基本上不会做你想做的事情,我会试着说明这一点,我还没有一个运行的程序,为了说明其中的一些事情。
所以好吧,这就是我们目前的情况,那我在哪里,所以我们讨论了重写一个方法,我们讨论了如何让这个关键字虚拟,好啦,好吧接下来是,如果您想要一个子类构造函数,调用超类构造函数,我们有一个奇怪的语法。
在那里你知道,在这些花括号里,你只会说打电话给超级,然后在括号中,您将传递您想要传递的参数,但在C++中,就像这个冒号,我觉得你应该这样想,当你说冒号的时候,一些事情,意思是这个是基于那个。
所以这个构造函数是基于调用另一个构造函数,有了这些其他参数,在那之后如果你还有什么想做的,你把它放在花括号里,所以我举的例子是。
如果雇员类,雇员类有一个名称,员工在公司工作的年数,然后这些字段在构造函数中被初始化,所以如果我看构造函数,它设置对象的名称,物体的年份等于你在这里传递的这些值,好的好的,所以如果你有律师。
那是雇员的子类,律师也一样,你知道他们的名字和在公司工作的年限,但律师也记得他们上的是哪所法学院,所以也许这三个都是构造函数的参数,所以也许你会有像私立弦乐法学院这样的学校。
或者我想我会把它叫做我的法学院来匹配另一份文件,所以现在在律师构造器中,你所做的就是你说,嗯,此构造函数基于使用此名称和此年数调用该构造函数,所以它基本上用这两个参数调用super,在那之后你会说。
你知道的,我的法学院等于法学院,所以这是这里的部分,那是律师独有的,构造函数,你可能会说很好,我不想这么做,这是愚蠢的,也许我会说我的名字等于名字,我的耳朵等于年,那只是我,直接设置所有三个字段。
它不让你这么做,嗯,因为哦,没有目标是什么,我想我有一些杂乱的文件,我得在这里刷新一下,我再试一次,是啊,是啊,但我想我把那份文件处理掉了,我不是还好吗,那里,我还有其他的问题,我的生活中有很多问题。
但目前这样不行,它不让我直接把那些,你明白我为什么喜欢律师吗,它里面有一个变量叫做挖掘,它内部确实有一个变量,呼唤我的耳朵,因为它从员工那里继承了这些,但是,我不允许在这里的构造函数中设置它们的值。
你知道为什么吗,是呀,因为它们是私人的,更多,是啊,是啊,这是对的,因为这些变量被声明为私有的,在父类中,在雇员阶层,子类不允许访问超类中的私有内容,即使他们有那些东西,他们也不允许看它们。
原因在Java中类似,我们不想让子类违反,类的封装,他们在扩展,所以说,好啦,所以我不能这么做,但如果我可以调用员工构造函数,员工构造函数会为我做这件事,所以基本上这就是我这样做的原因,现在呢。
有些人问得很好,而不是这种语法,我可以写员工的名字吗,把它放进去,使其看起来更像普通代码,或者一些不起作用的东西,因为从技术上讲,它构造了一个雇员类型的匿名对象,然后把它扔掉。
它没有初始化我有那些名字和耳朵的权利,你得这么做,我回放一下,你得这样做,好啦,这就是C++是如何做到这一点的,所以就这样做吧,好啦,是啊,是啊,那么是否与使用相同的语法有关,类似于其他方法,哦。
有没有办法在其他地方使用这种语法,我不认为你能用其他方法做这件事,这个是你可以用这个,即使你不继承遗产,它被称为实例初始化器列表,就像在上流社会,员工超级班,这里没有遗产对吧,它不是任何人的子类。
你可以这样做,你可以做冒号,我的名字,说出我的耳朵,年份,然后这里什么都没有,呃这意味着,基本上把这个初始化为那个,初始化为,你可能会说为什么这比我以前的好,以平等的陈述,某些领域。
尤其是作为引用的字段,必须使用此语法初始化,否则它们不能正确初始化,但这有点奇怪,就像C+加垃圾一样,所以我没有选择详细说明这件事,但基本上您可以在其他地方使用这个冒号语法,但我想让你知道的主要地方是。
从一个构造函数调用另一个构造函数时,因为这基本上是正确地,确保这个律师的所有三个字段都被正确初始化,好啦。
好吧我们继续,所以我想我已经这么做了,如果您有方法的子类版本,就像方法的重写版本,你想把超类版本,您只需编写超类名称,冒号,冒号,然后是方法名,它就会叫它,里面没有喜欢的超级关键词,在这些地方。
java会使用super关键字,其他语言有其他关键字来表示这个概念,C加+没有一个,所以只写类名就是这整个,就像你想要的如何构造这些属性,是因为你继承了,就像法学院的情况一样。
就像这里,是啊,是啊,我必须这样做的原因,是因为被称为我名字的岁月的名字,我在私人变量方面的岁月,我没有宣布我的超类在我的超类中做的那些,从那个超级类继承,我有那些变数,超级阶级要求他们只对他们保密。
所以即使我有他们,只有该类才能编写操作它们的代码,所以我必须调用他们的代码来设置他们的值,而我在法学院的律师课堂上宣称,所以这就是为什么我可以直接修改它,是啊,是啊,当你打电话给员工指导员时。
你能做几年减一年吗,或者像一些函数调用,是啊,是啊,当然,我可以用年乘以二减三,或者你知道一些表达,我基本上是把这两个参数传递给员工构造函数,它使用这些值来初始化,所以是的,当然,好啦,呃。
你有两个问题,你和你有,我们有一个超级,就像,它叫,在C++中没有super这样的关键字,不幸的是,在这个上下文中,名称和年份是传递给构造函数的这些参数,相对于在员工中,田名是我的名字和矿工,我的名字。
所以现在因为他们是私人的,律师不能直接接触他们,但是如果超类有返回值的方法,我可以把这些方法,这样我就可以通过调用年数的方法来问我的年数是多少,所以它就像一个只读,这很常见,行动正确,你有一个私人领域。
但是返回该字段值的公共方法,然后你的问题,如果你想打电话给,超类的构造函数,一个太笨拙的表达式,不能写在那里,哦,我明白了,就像你不想喜欢的那样,在…的字符上循环,也许你想喜欢,搭一些疯狂的弦。
然后把那个传过去,是啊,是啊,你在下面写一个叫做helper的方法,就是这样,然后在那里叫结束,所以你所做的,你知道的,是的,是的,是的,是的,所以我的意思是,这些东西是相当简单的,只是有点像。
C++是如何做这些事情的,我已经知道如何在。
Java或Python或JavaScript,或者任何权利,好啦,所以让我们继续一点点,关于遗产我还想说几句,既然我们谈到这个问题,有些地方你不想使用继承,我想有些人一旦学会了继承,他们他们有点结束了。
应用它来解决不同种类的问题,他们说,哦好吧,嗯,我有一门课几乎可以做我想做的事情,但我想要一些不同的东西,或者更多一点的东西,所以我会延长它,有时候,这是正确的想法,有时不是,但就像这里的一些例子。
我会声称你不应该使用继承,因此,假设您有一个存储x和y的点类,它是一个二维坐标,我说,哦,我想要一个三分,我想要一个z坐标的,所以让我们扩展点2d,使一个点3d,我只要加上z坐标,现在我三个都对了。
另一个例子是,我有一个矩形类,它有宽度和高度,正方形是矩形的子集,所以我会做一个正方形的类,我将调用矩形构造函数,我将通过与高度相同的宽度,现在我有一个方形的凉爽,我也不必重写,矩形内部的所有代码。
所以你知道你可以用继承来解决这个问题,或者有些人喜欢,他们想要的正方形的另一种方式,要实现的超类和矩形,或者别的什么,但是嗯,你也可以有一个叫做排序向量的,在那里你知道,你有一个法向量。
您可以在任何需要的地方添加元素,任何你想要的订单,但我想要排序的向量,无论在哪里添加元素,它将始终保持元素的排序顺序,所以我将扩展向量,我会写排序向量,我将重写add方法,你知道的。
把元素放在正确的位置,你知道的,所以我们把,所以说,我的主张是,所有这些都不是使用继承的好地方,即使它们最初看起来是好主意,你知道为什么在这种情况下使用继承是不好的吗?你说这些听起来不错,我喜欢这些。
啊,这里有什么问题,你觉得怎么样,是啊,是啊,几乎所有的方法都要内部,需要做什么,你说方法需要重做,就像如果你在做这些中的哪一个,你在哪里能想到这样的例子,我是说任何时候你用这种矢量,你得注意维持秩序。
任何时候你和第三点D一起工作,你需要和Z板一起工作,喜欢和焦点一起工作,是啊,是啊,我总是想到的例子与点类是像距离,你知道如果你有两点,你想计算它们之间的距离,是xy距离,所以你把dx的平方根。
加dy平方,或者类似的东西,但现在如果你有一个三维点,而不仅仅是这种距离,三点可能在这里,所以你有一个第三维度,不同的公式,但是现在代码可能会混淆,比如你把一个二维点和一个三维点之间的距离。
或者一个三维点和一个二维点的区别,就像有很多奇怪的情况,它可能会做错误的事情,也可能会让人困惑,您可能必须重写代码,它可能真的有虫子,在某些情况下,可能会产生不同的结果,如果你传递论点,这是不同的顺序。
听起来很糟糕,所以是的,这似乎很不幸,我总是想到的,在这个矩形的例子中,矩形有宽度和高度,它可能有一个方法,比如设置高度或设置宽度什么的,所以现在如果是正方形,如果扩展矩形并设置宽度,你打破正方形了吗。
还是设定宽度,也调用设置高度以保持正方形,但就像你可能会说的,我把它修好了,又成正方形了,你知道如果你如果我覆盖设置宽度改变高度二,如果我重写设置高度也更改宽度,现在它总是一个正方形。
它不会打碎任何东西,但我认为一个人被递给一个长方形的物体,但暗地里它是一个正方形的物体,当他们调用set width时,他们不指望高度会改变,令他们惊讶,如果发生这种情况,你知道我的意思,原来你是你是。
你让这门课,对于使用类排序向量的客户机来说,这有点令人惊讶,就像你知道的一样,Vector有一个插入方法,该方法接受索引和值,对呀,好啦,所以如果我给你一个矢量物体,但秘密地作为一个排序的矢量对象。
所以你在索引2调用插入,你把这个值,但现在,就像我重写插入,把它放在正确的排序位置,看来,好啦,我把事情处理好了,所以好吧,罚款,但是怎么了?听起来你要跳进去,你想说什么不好吗,关于那个场景。
就像你把它加到,如果您正在编写代码,知道你把它插在哪里是明智的,然后你看起来更好,它实际上是一种,不会是,是呀,就像,如果我在索引2插入一些东西,然后我立即问矢量,指数2是什么。
我完全希望它是我刚刚插入的东西,然后我插入一些东西,其他人就在那里,就像什么,那是什么,我刚才不是这么写的,所以这些例子会让客户大吃一惊,那是在使用代码,有一个原则叫替补能力清单原则。
谷歌芭芭拉·利斯科夫,她是巡回演出奖得主,我相信她是第一位获得巡回演出奖的女性,我可能错了,但是她,她想出了这些,其中一些重要的操作概念,你知道的,不应该使用继承的地方,对她来说,这个想法就像。
如果你不能用一个代替另一个而不感到惊讶,那是对遗产的不良利用,所以我们所说的这些地方,如果在子类对象中替换,它会做一些奇怪的事情,客户不会,所以你,您通常应该找到一种不同的方法来实现这种功能。
把第三点分开,也许把广场分开就好了,有时人们有一个诀窍,他们把一个超级阶级,像长方形或四边形之类的,然后这两个人都扩展了,所以你可以找到一种方法来共享代码,不用说他们中的任何一个都是另一个的阶级。
所以是的,你基本上只是把这些东西分开,所以在C++中有一种机制叫做私有继承,我今天不打算多谈这个,我只想让你知道,它是你扩展类的地方,您确实继承了该类中的所有代码。
但是没有一个外部代码可以判断您的类与另一个类有关,所以这有点像你得到了代码的副本,但如果有人像律师,私人雇员,你不能把律师放进员工的向量中,因为外面的人不明白律师和雇员是有关系的。
所以这个想法是你共享代码而不得到这些,你知道客户机代码中的继承混淆,我认为这主要是一个不好的功能,我觉得如果你想这么做,你可能做错了什么,所以我不喜欢私人角色,大多数语言都没有这个概念,就像如果你。
如果你继承了,你只需要向全世界喊出来,你必须公开你的超级阶级来自哪里,在大多数编程语言中,随便啦,原来是这样,我在上一节课中也简短地谈到了这一点,所以一个虚拟的,纯虚函数是虚拟声明的函数。
你把它的值设为零,这样做的想法基本上就像把它设置为空,这意味着你的类中没有那个函数,但是您要求您的类的任何子类都将编写该函数,所以这与Java中的特性非常相似,就像一个抽象的函数,如果你做了一大堆。
这就像有一个Java接口,所以Java的这两个特性是同一个概念,您不编写方法的地方,但是您要求其他人稍后编写该方法,现在呢,如果您有一个所有子类都应该包含的方法,这将非常有用。
但是每个子类都将以不同的方式来做这件事,这样就没有意义了,用于超类尝试编写方法,我想如果语言中不存在这个特征,您可以将它设置为一组空的花括号,但什么也不做,但那将是不幸的。
因为这样您可能会有一些子类忘记重写该方法,然后他们没有代码问题的实现,是啊,是啊,一定要零吗,或者如果你是对的,我相信你必须写零,我看到的所有代码都是零,是啊,是啊,不是空的。
因为我想我忘了我们可以很快尝试一下。
当谈到C+时,我有一半的时间是错的,但我们在这里做什么,我们要说,雇员h,我们要说Speak方法被设置为空指针,我想那行不通,是啊,是啊,看上面写着无效,纯说明符只允许零,哦真的好,嗯,我的想法。
如果你说空,就像这个空字面上是一个宏,它被零取代,所以我想这可能有用不不,你得用零,它很挑剔,它让你用零,就像一个零,如果我说,是呀,我抓住你了,它的工作原理,哈哈哈,我们不要再提这件事了,另一个问题。
是啊,是啊,实现多重vis,是啊,是啊,像那样的事情只有权利,所以我想我的下一张幻灯片会谈谈你的问题,嗯,如果你想在Java中,你有这些接口,您可以实现它们,你基本上很像这种功能,你可以说。
我保证我会实现那些超级接口中声明的所有方法,C Plus没有接口,所以如果你想要的只是对子类型的纯粹需求,你必须做所谓的纯虚拟类,假设你要写一个类,称为一堆形状类,好啦,你可以有三角形、矩形和圆形。
还有各种各样的东西,每个形状都有一个区域,双区域和每个形状也有一个周长,但你计算它的方法因形状而异,所以你不想在这里为他们写任何东西,这将完全是Java领域的一个接口,好吧,所以你在这里做的是。
你会说等于零等于零在这里用c加上,但你不能说界面形状,你只要说班级形状,好啦,所以现在如果你想写一个矩形类,你确实喜欢矩形类,你知道把公众形象,然后你必须把这些方法写对,好啦。
但是你知道当你用Java扩展一个类时,您可能知道只能扩展一个类,是的,这也是原因之一,Java有接口,您只能扩展一个类,但是您可以实现任意数量的接口,C++没有接口,因此您可以扩展任意多个类。
让我看看我的下一张幻灯片,它在哪里,C++具有多重继承,您可以扩展一个类,然后扩展另一个类,然后扩展另一个类,然后扩展另一个类,您可以扩展任意多个父类,可能听起来很酷,这是个可怕的主意,因为它很好。
我是说,对不起,并不总是可怕的,只是最终发生的事情,你的代码是,它会极大地增加代码的复杂性,它还会导致令人困惑的歧义,比如,如果您的两个父类都有一个名为get x well的方法,你得到哪一个。
答案是你得到了他们两个,但是现在,想要使用您的类的代码如何区分这两者,真是一团糟,我甚至不想谈这件事,但在某些地方它是有用的,从多个地方抓取代码的概念,把它们放到你的课堂上,这在其他语言中也发生过。
从那时起,红宝石就是一个例子,流行的网络语言Ruby,他们有一个叫做混合的概念,这与多重继承非常相似,你可以从其他地方取材,把它们粘贴到你的课堂上,现在你的类有了这些功能,但无论如何。
这个特性是在C中使用的,Plus Plus库,就像输入和输出流类有一个非常复杂的继承树,它们互相延伸,有点像坦格利安家谱,在《权力的游戏》的结尾,全部或某事,你知道吗,没关系,看看,查一下,但不管怎样。
大多数面向对象的编程语言不支持多重继承,因为它会导致这些奇怪的虫子,它使代码更难推理,在某些情况下,编译器也很难进行优化,所以它被禁止在Java中使用,大多数其他语言不允许,是啊,是啊。
你能建议它收敛到一个超级课程到一个,所以你说,你能建议两个超级的,啊,我看到像,你如何避免这种情况,我不想做好这件事,你看,呃,也许有一件事我没说,这可能会回到我的例子中,就像三个点之类的,就像。
如果你有一个类,你认为类似于这个东西,它有点像那个东西,就像,我应该把这两件事都延长吗。
有一种,这条规则,嗯。
这是另一个,我相信这也是芭芭拉·利斯科夫写的,构图只是意味着如果你像一个矢量,如果你们相似,如果你想做的是,多好的矢量啊,你不必喜欢,通过扩展向量成为向量,只需在您内部声明一个私有向量并使用它。
如果你有点像一个点,如果你的3D点有点像一个点,你想分享代码,宣布你内心的一点,作为私人会员使用,所以我想你说的是,我可以上我相似的两门课吗,我可以合并它们吗,当然,你有可能做到这一点。
但也许他们彼此不一样,所以也许这没有意义,也许我应该宣布他们中的每一个都是我内心的私人领域,所以我经常听到的比喻就像牙医、律师和垃圾,人和东西,就像我想要所有的东西,所以我要去牙科学校和法学院。
我要学习如何捡垃圾,因为我会成为所有这些东西,好像没有,我不需要成为那样的人,我只想拿到那些东西,所以我要申报一个私人牙医,我每隔几个月就得去一次,我可以找一个私人律师,我想起诉某人,所以你知道。
你不需要做那些事,如果你想用那些东西,垃圾,垃圾工是干什么用的?他们捡垃圾,对不起,一个收垃圾的来了,是啊,是啊,机会均等。
所以是的,反正,我只是在这里漫无边际地谈论遗传的不同方面,但我只想让你知道,C++确实有这个特性,我真的不想讨论所有不同的语法,如何消除重写之类的歧义,如果覆盖在,如果继承相同方法的两个版本,如。
我不知道,我真的不想展示所有的语法,如果你好奇的话,你可以谷歌C Plus加多重继承问题,是啊,是啊,当您尝试构造类时会发生什么,它有一个纯虚函数。
哎呦,如果您有一个具有这些零函数之一的类,纯虚拟,然后你试着构造一个形状对象,我几乎肯定编译器会说不,不能实例化纯虚拟类,类本身成为纯虚拟类,它是不可实例化的,基本上它也没有,是啊,是啊。
即使它有一些不是零的行为,它就是不允许你,基本上,它认为它是一个不完整的实体,不完全类,嗯好吧,所以我想,关于这个主题,还有几张幻灯片叫做多态性,但我想跳过一会儿来谈谈哈希,首先。
我可能会回到多态性的问题上。
所以我想跳到我的其他幻灯片。
它在哪儿?哈希,所以这些东西,我们今天做不完,但我只想在部分中介绍一下,然后我们会在周五做更多的这方面的工作,来自书的第十五章,这里的主要话题是,我想谈谈一些集合是如何实现的,我们想把它包起来。
学习我们用的几乎所有藏品,你知道的,了解它是如何建立在里面的,所以我觉得哈希真的很酷,当我第一次得知这件事时,我很难理解,但我没有你们聪明,在这本书的第十五章,所以好吧,让我们来谈谈这个。
我们试图弄清楚的主要概念,是实现一个集合的好方法,我在想像,我们基本上要得到一个哈希集,但让我们集思广益,如何落实好一套,你可以在内部有一个向量或一个未填充的数组,你知道其中一个调整大小的数组。
所以当人们想在布景中添加东西时,您可以将它们存储在最后一个元素中,像这样对吧,只是一种无序或插入的顺序,对呀,有什么大不了的,一套真正需要擅长的三种方法,是添加、删除和搜索,这就是布景的作用。
其他一切都只是在右边上面结霜,那么在这个模型中添加的大O是什么,大开眼界,只需添加到手上,没有移动,如果我必须经常调整大小,没关系,如果他们走了,它就不会断,包含的大O是什么,我让他们所有人都去找对了。
所以这不是很好,对于单个包含的包含O和n,集合需要快速,支票回来了,好啦,移除,那要多长时间,我得再找找,好吧,我们大部分时间都回去,太烂了,这个可以加,但这对你真正想要的东西大多没有好处,好啦。
那不好,好啦,嗯,怎么样,排序数组呢,同样的想法,但我们只是把一切都整理好,如果你说你想添加,你知道四九,我把它放在最后,如果你说要加八,我把它放在这里,只是,我会根据需要转移人员,并把它。
所以一切都井然有序,加进去需要多长时间,平方井,那么我该怎么做呢,我得找个合适的地方把它插进去,一旦我找到了那个地方,我可能需要把人转移过来,然后我把元素放在那里,多长时间有两个任务,找到地点。
然后给东西腾出空间正确的位置需要多长时间才能找到位置,我可以用二分搜索跳来跳去找到正确的位置,对呀,它需要n的对数,你们应该知道,所以这还不算太糟,但如果我发现正确的位置在这里,我得把人转移过去。
转换需要多长时间平均要花N,我可能得把一半的元素,所以是对数加n,这意味着只有N个,所以增加是很大的,n搜索的O,搜索日志需要多长时间,我用二分搜索很好,这样好多了,虽然加法比较慢。
搜索速度的提高真的很有用,好吧,那很好,登录搜索删除,移除需要多长时间,我用日志搜索找到你想让我删除的东西,但一旦我把他带走,我得把人滑过去,所以添加和删除,在这个模型中真的很慢,但是搜索更快。
所以对此有一些赞成和反对,还是不太好,好的好的,然后我们今天的幻灯片上也没有照片,我们还有二分搜索树,对呀,添加删除包含,在二分搜索树中,这些需要多长时间,他们都接受法律,假设这棵树很平衡。
我们已经讨论过了,嗯,这是三个小时的日志记录,那其实挺好的,那是迄今为止我们看到的最好的东西,我想给你看第四个选择,另一个选择,好啦,如果当你添加了一个值,而你添加的值是,我只是把它存储在索引的数组中。
我没事,所以我不是,我不会把每个人都推到左边边缘什么的,只要你说,加七,我把它放在下一个七点,你加上9,我会把它放在索引里,九一一,我把它放在索引一,添加一个元素需要多长时间,如果你这么做了。
它需要所有的一个,因为你知道跳转到数组的索引,即使是一个大指数也不需要任何时间,你只要直接跳到那里,所以这需要一个恒定的时间,搜索查看某物是否在集合中需要多长时间,你只要跳转到索引,看看它是否在那里。
或者如果有一个零,这将需要一个恒定的时间,移除某样东西需要多长时间才能使其归零,哦一个,哦一个,哦一个,哇塞,听起来不错,这个想法有一个小问题,你能想到这个想法有什么问题吗,很多,是啊,是啊,内存不足。
是啊,是啊,当然,我认为这个问题的另一种表达方式应该是,如果你想加个十呢,没有索引,哎呀哎呀,好啦,嗯,也许我会把数组做得更大,所以有一个十,我要做二十号的,十号的放在那儿,好吧,好吧。
现在我可以存储高达20的值,现在你加上一个2 8,哎呀,我得把大小调整到40,好啦,所以我只是把数组做得更大,包含要讨论的所有值的范围,所以如果你的值在一个不太大的范围内,这也没那么糟,但你离开了记忆。
所以我想你的意思大概是,如果我有一个像三的数字,我有一个大约十亿的数字,我必须做一个十亿大小的数组,大部分是空的,所以看起来,哎呀哎呀,这不是很有效的记忆,对吧,所以是的,那是个问题。
那是个相当大的问题,但我喜欢这个又大又旧的东西,所以也许我们可以试着解决这个问题,与其放弃这个奇怪的想法,不像非数字项目,是啊,是啊,我们在这里需要做的是,我们需要找到一种方法来获取我们想要存储的值。
并将它们映射到特定的索引,最好把它们存放在那里,如果我们存储在集合中的值,想出那个映射有点微不足道,因为映射是存储数字,因为指数等于那个数字,但如果这个想法我认为你在描述一个潜在问题的问题呢。
如果我在街上储存呢,如果我在储存双倍呢,如果我存储三点对象呢,这个概念如何推广到其他类型的数据,我想,那是个很重要的问题,我想回来,不过,我们得想个办法,如果这个想法有什么可取之处。
但是这种把元素储存在特定地方的想法,无需寻找任何东西,这个想法被称为哈希,你提出的所有问题都有合理的解决办法,所以如果我们能解决所有的小问题,这是个很酷的主意,好啦,所以让我们继续努力,让我们继续思考。
所以如果你加上更大的数字,也许我把数组做得更大,我想把它拿去无穷大是行不通的,因为你知道有这么大的范围,我们不想要数组,上面有数十亿的索引,大部分都是空的,那是那是个问题,但让我们继续前进。
看看我们是否能解决其中的一些问题,所以好吧,就像我说的,这个想法被称为哈希,哈希是当你映射一组很大的值,更小的索引域,那太小了,所以我们从映射整个int范围开始,到一组数组索引中,因此。
如果要使用数组存储数据,就这样,我们可以将数组称为哈希表,上一张幻灯片上图表中的数组,我们可以称之为数组,哈希表,哈希函数是一个字面上的C加号函数,在那里你传递一段数据,它返回一个索引将这段数据。
那么这东西该存放在哪里呢,将其存储在此索引中,从值到索引的映射称为哈希函数,我们想出的哈希函数有点微不足道,就像这里是int,我应该把它存储在哪里,将其存储在索引中,我们就是这样开始的,但如果你愿意。
你可以有比这更复杂的东西,然后是你被告知要去的实际索引,把我们称之为哈希码的东西,或者你知道,我们就叫它索引吧,如果你想,好的,好的,所有这些术语都是当你在做这种收集建筑时使用的术语,好啦。
所以我们想出了这个函数,哈希代码I存储在索引中,它们的缺点是什么,我们已经讨论过了,可能需要一个很大的空数组,对负数不起作用,因为数组中没有负索引,我们可以有稀疏的,你知道大多数索引都是空的,对呀。
所以让我们改进一下,让它变得更好一点,所以我们可以做的一件事是,如果我们看到一个负数,我们只要取绝对值,如果你想储存一个负6,我把它存放在索引六中,至少那样不会出界,对呀,所以你让我储存一个负2。
我存一个索引给你叫我存三个七,我会把它储存在接下来的七年里,所以我在修补你告诉我的一些问题,我不再有一个巨大的十亿元素阵列了,我会根据容量来修改元素,所以就像,如果你在上面加上一些东西。
我想存储索引大小为10的数组,然后我会把它修改10分,以找出该把它放在哪里,所以理论上我解决了一些问题,我现在引入了新问题来取代旧问题,我对此有什么问题,是啊,是啊,你们两个两个,是啊,是啊。
如果我想存储一个2呢,我想储存到两个,我想储存一千零两千零四千,两个和哎呀,哎呦,现在有人想争夺同一个位置,哦好吧,这似乎是个问题,是啊,是啊,那么我们该怎么办呢,嗯,只是很快地复习一下。
这三个行动都将是大的,一的O,因为如果我们有一个哈希码函数,以数组大小为批号的绝对值,添加,删除和搜索都只是一条线,对呀,所以我只想确保,很明显,这将是一个很大的问题,如果我们能成功,所以好吧。
最大的问题是你所说的碰撞,碰撞是指两个值都想要相同的索引,我有一个二四,我有五个四个,那很糟糕,我需要区分这两件事,所以任何哈希,一个正确的系统,必须有一个碰撞解决机制,必须以某种方式处理这个问题。
很多人花了很多年思考这个问题,所以人们想出了很多方法来解决这个问题,给大家看一下,其中一些方法叫做探测,探测只是去寻找一些其他的索引来存储价值,就像你储存一个24,它进入你体内,你10岁前是24个月。
十分,所以我把两个4放在那里,我有五十四个,所以我试着去这里储存,还有哎呀,它被拿走了,所以我一直期待着一个,直到我找到可用的索引,然后我就把它们放在那里,所以这就像把它变成别人的问题,好吧我不知道。
这在现实世界中的类比是什么,这就像你去尝试去睡觉在你的宿舍,但是你的室友在里面已经很吵了,做一些你不想做的事,所以你去隔壁宿舍,你睡在那个宿舍,但当他们回家时,现在你在他们的床上,所以他们就睡在隔壁。
我不知道,人们就是这么做的吗,我从来没有进过宿舍,我好像50岁了,所以不管怎样,你转到下一个真正的足球索引,这就是你做对的,如果使用这种解决冲突一的方法,这是解决碰撞的一种方法,还有其他方法。
而不是一个接一个地转移到下一个,也许你跳了一定的量,有时你按数字的方块跳,跳一加四加九加十六,你跳过它的正方形,他们并不都挨着,他们散开了,嗯,那么你对这种方法有什么看法,还是你有问题,是啊,是啊。
去吧,是啊,是啊,我很快就会说这是受订单影响的,其中你添加了一个非常晚的探测,导致了不同的指数,这是真的,这确实意味着添加元素的顺序会影响它们的最终位置,但这对我来说并不重要,他们最终会在这里。
只要加上,删除并包含,正确对待此集合的用户,所以如果他们说这一套包含54个,我来到这里,我以前没有看到它,我需要更新我的连续代码,看看他是否在下一个位置,或是之后的那个或是之后的那个。
但如果我把它修补好,只要它给出正确的答案,就像它说的是真的,当我加了一个5-4,上面写着假的,当我没有加50的时候,只要行为得当,我并不特别在意内心,每个人都在那里,只要行为得当,顺便说一下。
你知道当你有一个哈希集并打印它时,都乱成一团了,怪异,你不知道为什么订单很奇怪,它在做,它把你放进去的东西,它把它修改成一些数组的索引,然后当你打印东西的时候,它只是在数组上循环,不管那个顺序是什么。
这是它打印的顺序,这就是为什么它打印像一个奇怪的顺序,反正,随便啦,所以只要它起作用,我想这方面我没问题,但是是的,这确实意味着,如果我们这样做,这意味着我们必须更新添加、删除和包含的代码。
我们必须确保广告向前推进,如有需要,我们必须确保包含向前看,直到需要一个空插槽,和移除可能要期待找到东西来移除它,对呀,嗯,如果你是一个大,哦呃,纯粹主义者,你可能会说等一下,呃,如果我必须喜欢。
到这里,然后开始走在前面,就像,这难道不意味着,我现在有一个,这难道不意味着,它不像以前那么大了,所以你最终会遇到所谓的聚类问题,可能会有一大群人,我应该把这叫做,一零一高速公路的问题什么的。
我不知道你们可能不会开车,别管老人有这些东西叫汽车,有时他们有很多人,所以看起来是这样的,如果你添加一堆元素,所有这些都需要放在哈希表的相同相似部分,他们都挤在一起,这个问题的问题就像,如果你说,嘿嘿。
哈希集,你有七十四吗,那我得从这里开始,没有,不是他,但我得继续找以防他被调查,所以好吧,没有,不是他不是他不是他不是他,他不是他,哎呀哎呀,我终于到了这里,你得把这些东西包起来,如果需要的话。
所以要定义一个点,所以我所要看的,看到这里没有一个74,所以哎呀,一点都不酷,现在情况很糟,这个示例是尽可能精心制作的,破解密码,你知道的,使它有一个很长的簇,嗯主要是,如果你有这样的哈希表。
你不能只做半号的,这是一个不错的初始尺寸,对于向量,或者射线列表什么的,但是一个哈希集你可能会让它有一个更大的,差不多有一百或两百,只是为了给你多一点空间,所以如果你有一个大小为100的哈希集。
这些家伙中的很多人都不想再成为指数四了,你知道我的意思,就像在一个大小为100的哈希表中,2-4会在下一个2-4,三十七就是八三七,大小为100的哈希表,或者即使是20号的哈希表。
你会看到37会在17和呃结束,你知道我不知道什么,但他们会,他们会被分开一点,他们会比这更不聚集,如果哈希表大一点对吧,另一个经常使用的技巧是,你知道我碰巧选了10的倍数,因为我们喜欢10的倍数。
因为我们的小手指和脚趾,但是如果我选择哈希表的大小是73,然后造型和包裹和东西分布不是很均匀,所以很多时候人们为这些数组选择奇怪的大小,使模组在容量上碰撞更少,是啊,是啊,所以我们用。
我们正在影响我们的探测,我明白如果我们只是在,我们知道什么时候该停止看起来像一旦我们遇到了,是啊,是啊,但是如果我们删除像这样的索引,假设我们必须提出十个空格,我们要为我的空间挪点东西,这难道不意味着。
当我们搜索的时候你必须,当我们知道什么时候该停止寻找,是啊,是啊,这是个很有趣的问题,如果我告诉它我想删除,我这里有这个数据,然后我说我想去掉十四个,所以上面会写十四号在哪里,可能还有4分钟,不,好吧。
我去探头,哦,他来了,我会把他送回零,把他带走,这似乎是正确的执行清除,但现在以后,如果我问哈希表是否等待,我选了一个很好的例子吗,我要五四,我把他带走,我把这家伙,所以现在在再次移除并将他归零后。
有人说,这一套有十四个吗?所以我会从它的自然位置开始,那不是他,然后我去这里,我看到一个零,我可能会停止寻找,所以说,哎呀哎呀,我会想念他在那里,所以这实际上是一个重要的bug,如果你真的要写这个代码。
你得做点什么,你不存储零,你储存了一些垃圾价值,就像这里以前有一个五四,但现在是垃圾,就像一个空值,或者一个常量int,那是出界的,或者你必须在这里存储某种值来指示,就像继续寻找,那里。
以前这里有些东西,但现在它被从这里移走了,是啊,是啊,那是一个,这是个好问题,虽然嗯,反正,这个有一些好处,集群的一些缺点现在可能是一个问题,哦,在我走之前,我看到另一个人举手了吗,是啊,是啊。
为什么聚类,再慢下来,为什么集群会减缓事情,因为我们要做的就是,删除或包含在此,我们可以跳转到正确的索引,如果你想知道是否有14个,你只要跳过指数四,呃,这就是为什么它是一个很大的,这就是为什么它很快。
但如果你必须从四点开始,然后任意向前看,找到十四个,然后如果你有很多集群,意思是你在循环寻找东西,这种表示的全部意义在于避免大量的循环,去看,好像如果你有,如果你说像更少的集群。
东西散开得比你要寻找的更多,就是这种病,如果像这样的集群较少,是啊,是啊,你不必绕很多圈,我是说,如果你想找三十七,关键是他不会出现在任何其他索引中,你七点开始,看他在不在,因为七是他的特殊指数。
他的哈希码,会把你送到索引七号,是啊,是啊,它不会把你送到其他地方,为什么你为什么会知道,你为什么知道在这种情况下你不必四处看看,嗯,你知道你不必四处张望的原因是,说我寻找,说我要八十七,我说,好啦。
他的指数应该是87,十就是七,所以我会去这里,你坚持87年,我发现三七不,它不在这里,好吧,那我看看下一个索引,是87吗,没有,是零,如果你看到一个零,你可以停下来,因为零意味着如果有87。
我会把它放在那里,那里没有人,所以没有八十七,任何地方,所以你就开始走到零点,所以这个东西假设,就像你所认可的,是啊,是啊,是啊,是啊,我假设我在这里做线性探测,是啊,是啊,反正。
我想告诉你另一种做事的方式,它不是移动到下一个索引,另一种方法是在每个索引中,而不是只存储一个值,您可以存储值的集合,您可以存储一个值的链表或一些值的向量,不管怎样,这种方法很好。
因为它从来没有一张桌子,你必须查看每一个值或类似的东西,只是如果你去索引4存储2-4,你只要把它们放到链表里,然后如果你想储存54升的东西,您只需添加到链接中,通常你要做的是把它们插在前面,那更快。
但现在加法还是很快的,您不必查看任何其他索引,您只需将其添加到感兴趣搜索的链表的前面,你得绕过去,所以不管它有多长,您的运行时是这样的吗,移除就是,你得去找,然后把它取出来,所以现在比以前快了一点。
从某种意义上说,嗯,你知道的,大多数情况下,这些将再次分散开来,我的照片有一个长度为3的列表,所以这看起来有点糟糕,但实际上有了真实的数据,你有一个更大的哈希表,元素通常更分散。
所以你更有可能有一堆锁链,里面有一两样东西,所以如果链条足够短,即使您必须在两三个对象上循环,那真的没什么,所以这基本上仍然让我们保持在一个大O,所以这就是所谓的分离链,这是在哈希集中所做的。
我们斯坦福图书馆附带的哈希图,这是在STL里做的,这就是Java的功能,这是现在大多数哈希结构所做的,我没时间了,我最后要说的是,你知道的,主要的,还剩几只虫子,也许我们可以在星期五继续。
但我们还没有解决的最大的问题是,如果你不储存它,你如何把其他类型的数据放在这里,您如何想出一个神奇的索引来存储字符串,或者将一个点存储在,或者别的什么,所以我认为这真的归结为一个问题。
你能把物体的状态转换成某种int,那是可复制的,所以你可以为此做各种各样的事情,就像如果它是一根绳子,您可以将所有字符转换为它们的小ASCII数字代码,然后把这些加起来,然后是字符串的数字代码。
那是它的哈希码,然后这个数字mod数组大小是字符串应该存储在的索引,所以你得想出一些东西,把它转换成像那样的int类型的转换,所以无论如何,我就不说了,在这一节中,你可以更多地谈论哈希和哈希外套。
不过,我们星期五再继续,那么到时见。
【编程抽象方法 cs106x 2017】斯坦福—中英字幕 - P23:Lecture 23 - Hashing 2, Inheritance 2 - 加加zero - BV1By411h75g
好啦,最近怎么样?今天是星期五,已经一周了,我想第九周,取决于你如何计数,我想和你们做什么,今天我基本上想继续谈论哈希,我们从周三开始,我也想回去在遗产方面做更多的工作,这两个话题我都做了一点。
通常我会涵盖所有一个,然后所有其他的,我两者都做了一点的原因,现在我要回去做更多的,因为你这周的专栏在这两个话题上都有问题,我只是不想让任何一个话题不被讨论,在各款之前,所以这就是为什么我在按顺序做事。
我正在做,但基本上到今天结束的时候,我差不多已经完成了对这两个主题的讨论,至少现在是这样,所以我先回去散列,因为那是我们结束的地方,所以是的,提醒我,就像,什么只是告诉我,在这里给我一个电梯推销。
就像一个快速的描述,就像哈希是怎么工作的,哈希是怎么回事,如果你必须向你的朋友描述,六个,或者类似哈希的东西,你会怎么跟那个人说,一个伟大的人,是啊,是啊,你拿着某种形式的数据。
将其转换为可以存储的整数,使用,取一段数据,换算成英寸和索引,这就是你将它存储在数组中的地方,是啊,是啊,这是我认为最基本的想法,从数据元素映射到数组索引的某种散列函数,我们周三做的讲座很酷。
我真的不用做很多工作,将数据转换为索引,因为我看到的数据,所以就像珍宝本身,是把它放在,但就像你说的,如果这是一个更普遍的概念,如果是绳子,如果这是一个点,如果是矢量,或者别的什么,不管是什么。
我得想办法把它转换成int数,要知道在哪里储存它的权利,我为什么要这么做,有什么意义,这个愚蠢的想法有什么好处,是呀,如果你不想,哦,一个用于添加删除包含,是啊,是啊,这是这里最大的回报,太快了。
对快是好的,好啦,这就是我们讨论的总体思路,哈希最大的问题之一是你可能会遇到这些冲突。
其中两个值希望位于同一索引处,你对此怎么办,你怎么解决这个问题,是啊,是啊,把东西堆在上面,就像,是啊,是啊,你可以,就像你说的,把值堆叠起来,或者从链表中列出值,而不是只在这里存储一个值,是啊,是啊。
那是一种方法,我们还谈到了另一种方法,在那里您可以跳转到下一个索引,那叫线性探测,或者只是一般的探索,对呀,所以我想我们就到此为止了,我说的地方,大多数基于散列的集合都使用类似的方法。
它们在每个索引处存储一个值列表,记住当你有一个矢量,矢量满了,最终你必须调整大小,使矢量大两倍,如果你在这里这样做,使这个数组大小为20,你知道就像,有点不太清楚,这里的大小调整是如何工作的。
所以我想马上谈谈,例如,如果我调整大小,我何时调整大小,就像在矢量的情况下,你会吃饱,然后你必须调整大小,我什么时候吃饱,我何时调整大小,我从调整大小中得到了什么好处,所以我想一会儿再谈这个。
但我想我先看到了一个问题,是啊,是啊,在这里,而不是使用链表,你能在里面用另一个哈希图吗,所以它就像另一个类似的哈希,是啊,是啊,有一些不必要的,因为你可能想看看它的重量,有一种叫做双重哈希的东西。
就像,如果在这里发生碰撞,然后你有第二个哈希函数,就像你调用哈希函数,它给你一个索引,你试着去那个索引,如果索引被取,还有其他第二个哈希函数,你打电话给你一个不同的索引,所以你去那里。
所以你不是这么说的,但是有一种例外,你现在有哈希中的哈希或其他什么,我觉得你说的更像是,住在这里的东西本身就像一个哈希表,或者哈希集,或者类似的东西,我是说你看。
我认为这个想法的重点是每个索引并不存储一个单一的值,它是价值的集合,具体是什么收藏取决于你,它可能是一个载体,它可能是指向节点的指针,它有一个指向节点的指针,它有一个指针,这就是这幅画所暗示的。
可能是别的什么,我觉得问题就像,你知道的,如果该集合是哈希集合,就像嗯,我正在实现哈希集合,你知道我的意思,所以这就像,我想给你一个自成一体的定义,这并不依赖于任何其他特定的库或其他东西,所以是的。
有很多不同的方法可以存储这些数据,我只是选择把它画成一个链接列表,这就是很多实现实际上所做的,但它几乎可以是任何类型的收藏,只要它存储多个元素值,我是说这可能是一个数组,哈希表可以是一个数组。
那么每个x中的这些家伙可能是指向其他数组的指针,你储存东西的地方,但是当数组满了,你得把它放大,所以它就像每个索引中的向量,你可以做那种事,但我是说这是最规范的做法,所以现在我想指出。
让我们再次讨论大小调整,不过,如果你像这样离开哈希表,理论上你可以添加无限多的元素,从技术上来说,它永远不会满,你明白像,我是说,除非您的计算机内存不足,比如如果我添加一个元素,十个指数中的每一个。
从某种意义上说,它是满的,所有索引都用于存储链表,但从没有更多空间的意义上说,它并不满,对呀,您总是可以添加更多的元素,只需将它们添加到这些链表中,它们变得越来越长,对呀。
所以理论上我不需要调整这个右的大小,那有什么问题,如果我只是离开它,而且这些名单越来越长,是啊,是啊,就像链接列表的长度开始接近结束长度,你可能会说,嗯,它不是n,这只是n的十分之一,那远小于n。
但是n的十分之一仍然是n的大o,因为大O是关于成长的,如果你乘以N的十分之一,所以它和右边成比例,所以是的,那很糟糕,我们不想那样,所以我们要绕过这个问题,我马上给你看,您确实调整了哈希表的大小。
你不能就这样离开,你确实调整了它的大小,但它只基于一次,你得到了一定数量的元素,可能是十个,因为你有10英尺长,也可能比这更少或更大,因为你喜欢,我说严格来说你不会用完空间,所以我们经常有一定的门槛。
东西开始调整自己的大小,所以我一会儿就说到这一点,所以好吧,如果您在此结构中添加、删除和搜索,基本上你做一个新的节点,但你要放的地方通常是在链条的前面,你想让链子指向他们,然后他们指向剩下的节点。
我想我上一节课简短地说过,你想把它们放在你的你的,你看这张照片,你的大脑可能想把新的放在最后什么的,那很好,只是你得走到尽头才能把它放在那里,所以不要那样做,把它粘在前面,链条的顺序并不重要。
你明白他们都必须在那里或者以某种方式,所以你把它们放在前面以提高速度,唯一棘手的是你确实需要查看链条,无论如何,因为你得确保它不是复制品,集合不应该包含重复项,对呀,尽管它确实提出了一个有趣的问题。
如果我没有检查它是不是复制品呢,我刚刚添加了另一个该值的副本,那会是坏事吗,我不知道像什么,如果有两个,如果我有一个二四,然后我又吃了两个四,现在我有两个,两个,四个,如果有什么是好是坏呢。
你以为你刚找到第一个,如果我问你,集合是否包含两个四,你会说是真的,哪个是正确答案,所以可能会导致移除的问题,如果有两个,两个,四个,然后我告诉你,我要你删除两个四,你只去掉两个中的一个。
我叫你把它拿走,它就不应该在那里了,所以我只想指出,您可以继续添加副本,但你必须确保走完这整个链条,然后删除该副本的所有副本,所以这是一个权衡的例子,在这个例子中,你可以更快地添加。
但你会让移除变得更慢,所以唯一的另一个问题可能是,如果你在打印东西,你打印了,你在屏幕上画了两个四的副本什么的,但这取决于您是否希望支持为您的收藏打印,你有一个问题,是啊,是啊,当你移除。
那个事件不是吗,所以不是,坚持到底,和刚刚的凹槽一样的大O,在第一个,你说这些都是移动的大O N反正,嗯,但移除并不是一个大目标,这些都是一次行动的大O,如果我们做对了,你是说大事件吗。
在这个链条上的一个循环的意义上,你的意思是,是啊,是啊,你得走过去,你得走过去,在这种情况下,如果允许重复,只是意味着你每次都要走到最后,而不是让你走路的东西,是啊,是啊,我同意你,你有时可以在。
你只走了链条的一部分,而不是走了整个链条,所以你可以坐在那里,微优化,我觉得最主要的是,这些链条很短,所以希望走着链子的一部分,或者所有的链条都没有太大的不同,所以我想通常我们只是继续走链子。
确保值不在那里,然后只加,如果不是复制品,但我想向你们指出你们可以建立一个有效的结构,那是一套,即使你真的让它有副本,只要使用集合的客户端,看不出有一个复制品,你可以有这种把戏。
这是您存储的内部结构之间的差异,你表现的外在方式,对集合的用户,所以无论如何,这基本上就是如何向哈希集添加内容,使用这种单独的链接,无链接链接,这里的碰撞分辨率结构,所以如果你想做包含,很明显是吧。
如果你只是去杂凑桶找你要找的东西,你从链条的起点走到终点,你寻找它,看看你是否看到了它,如果你看到它,你说的是真的,如果你看不到,你说假的,然后是的,你就像有一股电流穿过所有的节点,那不是。
那没那么复杂,如果要从,只是从链表中删除,要么是链条的前面,要么是中间,要么是末端,或者你们写的从链表中删除东西的代码,基本上是相同的代码,所以这不是很非常复杂,同样的东西。
在你要除掉的人之前找到那个人,把他们当成詹姆斯,邦德的东西或气球什么的,你的类比在这里是一样的,所以现在这并不难,我们现在基本了解了如何实现这三个操作,我这里有一张幻灯片,上面写着,让我们去写一些代码。
我想我不想写,和你们住在一起,但我们可以,你知道我可以把它寄出去,大家可以看一下,如果你想,就像我从照片上想的那样,实施这样的事情并不是那么可笑,但是哦在那里,它就在那里,你走得真好,你读了吗。
你很快就看完了所有的代码,但我想谈谈调整大小,重复,他们称之为重复,呃,有某种玩笑要开,就像我在重复这个讲座什么的,但是嗯嗯,重复是当你必须把哈希表做得更大时,当你必须把它调整得更大时。
所以当你调整向量的大小时。
你让我,哪里是我的。
有一个,我只要一张白纸,所以如果你调整向量的大小,我不知道那是什么样子,但不管怎样,当你把它调整得更大时,你做一个两倍大的,对然后你只要把所有的元素,然后你就做对了,你复制十个元素,现在你有二十个位置。
其中十个是空的,这就是如何调整向量数组的大小,对呀,好啦,如果对哈希集这样做,结果不是很好,那不是正确的做事方式,你明白为什么对哈希集这样做有什么错吗,是啊,是啊,新的哈希函数能够访问所有可能的,因此。
以前利率中的每一个元素都有权利,如此如此,想象一下这就像一张非常糟糕的照片,但像这样的指数是十分之四,好吧,我有三四个储存在这里,对哇,好啦,在这里,我得到了我的三四指数四,好吧。
那么这是一条10号的射线,然后这个20大小的新数组,好啦,我做到了嗯,如果你把3-4复制到这里,记住哈希函数是如何工作的,这就像int mod的值乘以数组长度,对呀,三四mod十等于四。
这就是为什么他是指数四,三四mod二十不是四,是十四点,对吗?所以对于三个,四个不应该存储在那个索引中,在较大的数组中,三四应该存放在索引14上,三四应该是这样的,就像那样,哎呦,太难了。
然后如果我有一个4,四或两个四或类似的东西也在这个链条上,就像他会繁殖到四个,他会呆在那里,你明白吗,所以你不能抄袭所有人,就像你说的,你必须重新应用哈希函数,知道把每个人放在哪里。
所以这就是重复的想法,这是我的照片,我在这里也有同样的事情,我想这些家伙以前在四链子那边,这家伙会在一条链子里,所以一般的算法是,您使新的更大的数组,然后在旧数组上循环,循环旧数组的所有链,较小的数组。
并将每个元素,你要求它的新哈希值,把它放进新链子里,原来如此,做起来并不难,但你只需要意识到这个问题,一个问题,哈希时间的想法取决于那里,数组使用非常稀疏,好像大部分都是空的。
就像一些指数实际上发生在他们身上,所以一旦你对整个事情进行了不合理的长时间循环,我们是不是有一些,比如什么指数把东西放进去什么的,是啊,是啊,这是一个很好的观点,就像如果这真的很大,很多索引都是空白的。
然后我循环了很多,什么也没做,所以很遗憾,也许这应该有一些指向下一个非空索引或其他什么的指针,我觉得,在实践中,人们只是吃性能惩罚,原因是这个数组长度不是,你知道那不好,我是说,相对于,你知道的。
就像N或类似的东西,你基本上最终会做,就像那些空的,你只是很快地向前看,你知道我的意思,就像,实际费用来自,比如制作这些节点复制这些指针之类的,所以它最终不会对你造成那么大的伤害,还有像这样的开销。
以某种方式保持指向下一个或其他什么的指针,只会让你从几次跳跃中解脱出来,通常只有几个空隙,你知道我的意思,就像必须保持、维护和更新的开销,这样的指针足以让它有点不值得这样做,大多数情况下。
我们只是循环所有的插槽,即使是空的,所以就有了这个问题,我何时调整大小,这在矢量中很明显,您调整大小,当它吃饱的时候,这里不太清楚,有很多不同的算法来决定,何时调整大小,何时重述,一种算法是。
如果一个链条永远不会超过某个环节,您可以更常见地重复,你说得好,我会数数我有多少元素的大小,当它达到一定的阈值或调整大小,但正如我所说,门槛是灵活的,不一定是,当数组已满时,因为没有满的。
所以取而代之的是哈希集可以保持自己的度量,也就是所谓的负载系数,也就是初等元素的比例,喜欢它的大小,与哈希表的长度,能力,所以说,例如,如果在十个数组中有六个元素,十分之六,负载系数是零点六。
所以您的哈希集类,你做了一些双常数,那就像,这是我将重复的负载系数,你把它设成零点七十五,或者零点六六之类的,当你重新设定,所以我写在这里,比如七点五或者六点六,这是很多人使用的两个值,你可能会说很好。
为什么不是一个,因为一个零就像满的一样,但请记住,哈希集的工作效果最好,如果它很好,散开,所以就像有一点空间,有点稀疏是好的,使链条变短,所以就像等了很长时间才调整大小,因为你节省了几个字节的内存。
不是我们想要优化的,所以我们提前辞职,是啊,是啊,我在幻灯片底部的另一个东西,幻灯片上的这些图片不是很好,表示哈希表内部的实际外观,因为我一直在用这些漂亮的整数,像十个索引或者二十个索引。
那只是因为图片更容易理解,你脑子里在想什么,这真的很容易知道,34蒙大拿很容易计算,即使你知道,即使我在伯克利做客座演讲,他们通常能做对,通常,但他们通常在哈希集上做的不是十,然后是二十个。
然后是四十个,他们使哈希表大小,就像三七或一些奇怪的数字,不是伯克利,像每个人一样的人都这么做只是为了清楚,嗯,我们这么做的原因是,就像造型和包装是一种更分散的,更混乱,就像那些恰好是全等的数字。
Mod 3 7只是一个奇怪的随机数,不是随机的,但就像数据集的分布,碰巧有很多数字,是一致的,莫德三七还是莫德三,七乘以二或类似的东西很少见,所以我们选择了这些尺寸奇怪的数字,所以成型的包装会更好。
实际上,你知道我一直没有这样做,但是如果你。
如果你去。
在我们的图书馆中设置或映射,我想这是哈希图,我们需要看看,所以让我来看看,我们库中数组的初始大小是多少,是一百零一,上面是这么说的,所以在我们实际的哈希映射类中,我们将数组初始化为有101个元素。
这是一个很好的杂凑,一套斑点狗,我想是的,他们说他们把它存放在这里,我没有写这个代码,但他们储存在这里的比例是70%,这只是意味着负载系数零点七,所以你去那里,然后他们称之为哈希的哈希展开和重复。
所以他们把它乘以二加一,所以当他们调整它的大小时,他们基本上把它翻倍,但后来他们又加了一个,所以尺寸总是奇数,我想是的,他们就是这样调整大小的。
是啊,是啊,有任何关于重复或负载因素的问题吗,是啊,是啊,所以有一些有趣的,如果你只是,如果你想谷歌这个,有一些有趣的论文、文章和链接,人们在那里处理了大量关于这个的数据,他们收集了大量的程序。
使用哈希集和哈希图,然后它们交换具有不同大小和不同负载因子的哈希图,在它们调整大小之前,然后他们只是基准所有的,也有很多理论计算机科学家,他们做了很多很酷的校样和东西,对于一个,你知道学生导读。
但是有人计算过这些数字,他们决定最佳负荷系数为零,点,六个,八,九,三个,或者别的什么,他们通过成千上万的试验来测量,所以是的,质数往往有帮助,这有点取决于数据集,但聪明人会经历这一切,事实上。
有一件事很有趣,如果你刚学会一种新的编程语言,大多数语言都有某种哈希映射,哈希集,散列的东西去看看,如果你能找到像,默认情况下他们的哈希表有多大,他们的负载系数是多少?因为在他们的代码里。
去某个地方看看Python源代码,他们是做什么的,你知道的,看到这些不同库之间的差异很有趣,但它通常是一些奇怪的质数,在六点六到七点五之间,是啊,是啊,这一次有一个负载系数,我肯定有更多的比是的,就像。
我如何确保我的链表不会像,有点大,我想我不能给你一个很好的答案,但基本上你必须非常敌对地制作一个数据集,如果所有这些因素都对你有利,比如奇怪的哈希表大小和调整某个负载因子的大小。
你知道我们正在学习的所有其他技巧,为了有一个数据集,它们最终都在同一个桶里,你真的得仔细选择数据集,这不太可能发生,但这是非常不可能的,另一件事是你可以想象这些数据集是什么,如果我们说的只是暗示。
你知道我的意思,因为你去,啊,如果我选54和14或其他什么,或者即使模组是一百零一个,你去挑一百一两百二什么的,我挑这些,我会不厌其烦地挑选偷偷摸摸的数字,会把事情搞砸的。
但我想你会发现如果你像绳子一样,如果你在做积分,如果你在做其他类型的数据,实际上我马上就给你看,就像你用绳子做的那样,但是很难制作数据集,在那里它们都撞到同一个桶里,现在有些事情我今天不打算谈。
但如果你想谷歌一下,你可以称之为完美哈希,在那里你可以给一个算法一个数据集,有一个完美的哈希算法,你给它你的数据集,它看着所有的东西,它说我会为这些数据想出一个哈希函数,这将最大限度地减少碰撞,事实上。
如果可能的话,我会做到这一点,没有碰撞,我会给你一个哈希表大小和一个哈希函数,您可以在此数据集的每个元素上运行,它们都会映射到不同的桶里,不知何故,这很复杂,我又不知道,我不知道,恐怕我从。
如果我试图在课堂上描述它的寒冷,但这是你可以做的事情,其实呢,你可以在电脑上运行一些程序,为你生成,挺酷的,所以人们,你知道的,担心他们的数据集会有很多冲突的人,他们已经想过这些事情了。
他们制造了工具来帮助避免它,但不管怎样,我想谈谈,如何哈希,其他类型的数据,你们可能已经在课上讨论过了,所以这可能有点老调重弹,哈哈哈,那么如何对字符串或,或者是的,我重复了一遍,我的笑话也是,是啊。
是啊,是啊,是啊,很好地满足了每一个哈希,嗯,那么我喜欢如何哈希字符串,嗯,有很多方法可以做到这一点,但我认为这里的基本思想是,我得把状态,数据元素,我必须把这个状态转换成单个int。
这里有一些品质需要真实,有效的哈希函数,必须具备以下素质,它必须符合平等的概念,所以这意味着,如果我必须让我们说我散列字符串,我有两个字符串变量,如果这些字符串变量存储相同的内容,如果他们有相同的字符。
里面同样的数据,你知道吗,一号线你好,二弦你好,如果我在这两个不同的字符串上调用哈希函数,我必须得到他们两个相同的答案,这很重要,因为这里的类比就像,我稍后将第一个存储在哈希集中。
我问哈希集是否包含第二个,它最好答应,所以答案必须是一样的,因为它们是相同的数据,他们可能是,你明白的,就像等价和等价的区别,就像你可以有两根不同的弦,他们是不同的,但它们的状态是一样的。
它们存储相同的字符,他们是对等的,这两个字符串必须产生相同的哈希代码,好啦,所以这是第一件事,如果字符串不相等,如果我有一串你好和一串再见,我把这两个传递到哈希函数中,它们不一定要返回不同的结果。
但为什么这似乎是错误的,如果Hello和Goodbye返回相同的哈希代码,这似乎很糟糕,为什么这不是,因为这就是幻象和链条的设计,这里的想法是,如果两个不同的字符串或不同的,作为哈希码产生的任何东西。
那就意味着它们会互相碰撞,所以目标实际上不一定是零个人会和睦相处,因为我们刚刚想出解决的办法,当人们互相碰撞时,事实上,如果你仔细想想,一些人相互冲撞在所难免,我怎么知道弦必须变成大头针,对呀。
世界上有多少不同的别针,像大多数或标签一样,不管你们对电脑说什么,好像是2。7,27mil,你很近很近,它很大,这取决于它取决于声明的类型,英特英特右,32位体系结构,三十二位,两到三十秒,大约40亿。
你可以有不同的值,从负20亿到正,二十亿减一亿,所以嗯,这取决于你声明一个短int还是一个int,与长长的,与长的,长int,对抗任何东西,你得到不同的部分,但是有40亿个名字,好的,好的。
有一个有限的数目,C++支持有多少字符串,基本上无限个字符串,对呀,有二十六个一个字母的字符串,只是使用字母表,还有其他角色,但有多少两个字母只写了三个字母,但你可以有一根绳子,所以可以肯定的是。
有40多亿人是对的,所以宇宙中的每个字符串都不可能返回一个唯一的int,那不管用,所以没关系,如果不同的值偶尔返回相同的哈希码,如果不是这样就好了,通常,如果值在整个数字空间中均匀分布,那就太好了。
对呀,好啦,说了这么多,这些哈希码中哪一个更好,为什么会有这样的动画,好啦,这些哈希码中哪一个更好,哈希函数更好,为什么,这就是我看到的是你想要,就像那个答案还是梅毒,你知道对不起,你们说的哪个更好。
为什么一个更好的,是啊,是啊,因为我们给同样的屏幕,第二个是可能的,原谅,是啊,是啊,这可能会给相同的数据带来不同的激情,如果我有你好和你好,我请他们两个进来,我可以得到不同的号码,那只是无效的。
它甚至不工作,这个也很烂,但总比,会发生什么,我的意思是,我可以用这个,这是一个有效的哈希函数,会发生什么,如果我使用这个散列函数,我去拿链接列表,每条小溪都想在桶里放42个,那不是,但在哈希表中。
它想在42号桶里,然后我就变大了,我调整大小,它们又回到了42号桶里,所以我的哈希表都在一个桶里,它基本上是一个链表,我所有的添加、删除和搜索现在都是N的大O,这是不幸的,但这并不是不正确的。
只是分布得很差,对呀,所以A更好,即使他们都很烂,这个怎么样使用RAM中s的内存地址,记忆,两个等效字符串可以有不同的内存地址,所以它不会做正确的事情,所以有一个类似于这个的区段问题,所以无论如何。
那么你应该做好什么呢,怎么样,这个怎么样,你把绳子的长度,比四二,嗯,总比四二好,而且比指针好,但是这样可以吗,对吗,还是违反了我需要什么的定义,为什么,好啦,大约八点,是啊,是啊,如果你通过了。
那不会导致错误吗,啊,如果你只是用引号传递它,是啊,是啊,嗯,它将创建一个临时字符串对象,它会给你地址,但那不是一个很有用的地址,它会编译,但是是的,它不是一个好的散列函数,有几个不同的原因,是啊。
是啊,但是这个长度呢,一是有效,会有用的,但很可能不会,当你调整它们的大小时,是啊,是啊,我是说,这里是短弦这里是中弦那里是长弦,这个不是那个,因为世界上很多字符串都是零到十个字符。
所以你会得到一个相当重的,就像你的散列向左聚集,但它是有效的,相等的字符串在这里会给出相等的结果,所以它起作用了,你知道的,但不是很好,所以这样更好对吧,这就像在字符串的字母上循环,把它们加起来。
把看护人都变成,然后把它们加起来,所以现在它是基于字符串的状态,这是好的,如果你传递相同的--就像两个相同字符的等效副本,它会产生同样的结果,这很重要,我们需要那个,我想这个会散开得更好一点。
因为把这些字母加起来,你会得到一个更大的int或其他什么,所以它似乎会扩散,它不会把每个人都归入前十个指数或其他什么,这个稍微好一点,对,记住,只要记住,如果你把所有这些ASCII字符加起来。
你会得到一些大数字,就像腹股沟数一样,差不多六十到一百,主要是一些,所以你会得到这个数字,大概是856,对呀,不过没关系,因为你根据哈希表的大小修改它,对呀,所以这就是,这是在任何改装或其他之前。
所以这很不错,你对碰撞有什么看法,比如用这个算法会碰撞什么样的字符串,是啊,是啊,就像那根弦,就像小写的一个领主风投在字符串中,小写b,小写b,你看起来很有活力,AC和BB会碰撞,是啊,是啊。
所以加起来正好是,我以为你说的不一样,你觉得呢,只是重新排列相同的字符,就像字谜,或者只是相同字符串的混乱版本将产生相同的哈希代码,再说一遍,这并不意味着你的哈希码坏了或坏了。
仅仅因为你能想到一些会碰撞的值,没关系的,你会有冲突的价值观,但不幸的是我们能想到,可能有很多例子,我们可以认为这有点常见,然后会碰撞,所以说,你知道的,哎呦,我们能让它比这分布得更均匀吗。
所以你经常做的是把所有的字符加起来,但你喜欢把它们乘以奇怪的数字来放大它们,所以这到底是怎么回事,所以不是从零或一开始,然后把所有这些字符,我从一些愚蠢的数字开始,我只是化妆,有点大,有点素。
或者我不知道它是不是质数,但看起来很原始,看起来没有太多因素,你知道的,呃,我对他的刻板印象是他看起来像个质数,不需要,你知道,嗯,然后当我有字符,我把它们乘以一些因素,乘7乘17,三十一岁的时候。
我为什么选三个一,我不知道,只是人们分析了这一点,得出了这些数字,还有这个傻乎乎的公式,让你基本上是把字符加起来,但现在如果它们的顺序不同,那么这个乘法尺度就不一样了,所以字谜和排列之类的东西。
就像经常碰撞一样,我想这也纠正了你的b、c、b、b或其他什么的例子,我认为这个修复现在仍然会有字符串碰撞,但碰撞的常见案例较少,我也很难喜欢,你问的是,我可以制作输入来打破哈希表吗。
所以它们最终都在同一个桶里,很难喜欢,坐在这里,想想有一根弦恰好等于他愚蠢的公式,这实际上是Java使用的哈希公式,当它的琴弦化为灰烬,拉拢等价物,这是C++代码,但这个算法是Java用于字符串的算法。
所以效果很好,这种一般的技术,就像把组成物体的状态碎片,不管是什么,如果它是一个有ID、名称和密码的学生对象,或者别的什么,把那些国家的碎片,将每一段转换为int到某种哈希码。
然后用乘数常数把它们推到一起使其工作,如果你去看斯坦福图书馆的源代码,您将发现具有哈希代码函数的各种文件,他们有这个原则,把所有的州,将每个状态片段转换为某种哈希码,作为一个数字,某种int。
将所有整数与常量混合在一起以放大它们,所以这就是,这就是工作原理,这不是有缺点吗,我不知道有没有更好的方法,这是波巴带在绳子的长度上,哦耶,是啊,是啊,这是个好问题,如果我们能做一个哈希码,那就像,哦。
原木和春天一样,哦,一个喜欢是的,这是个很好的问题,所以他说的是,这不是要花很长时间来计算吗,因为你要移动字符串的所有字符,是的,是的,这是正确的,那倒是真的,实际上,它通常是好的。
因为大多数弦其实没有那么长,所以它最终变成了,你说过,是O的N,我们要小心,对呀,因为n不是某个字符串的字符数,n是我添加到右边集合中的字符串数,所以即使是一段有循环的代码,我们不一定说那是不可能的。
但我明白你的意思,我想你是说O'of N是一条捷径,我必须把这里的每一个东西都循环一遍,我在前言里明白了,没那么糟吧,这些弦大多都很短,计算这段代码不需要那么长时间,另一件事,所以有一些调整。
有些人做一些图书馆,做一个是你可以循环到,就像四号或十号字符,或者你可以在某个时候停下来,然后你就会忽略其余的,如果字符串碰巧有一百万个字母长,你忽略了前十二个什么的,这是件坏事吗,嗯。
这可能意味着一些长串相互碰撞,但有些碰撞是可以的,那很少见,可能是,所以我们对此没意见,我们将使用我们的链表来处理这个问题,水桶什么的,我们没意见,所以一些图书馆这样做,其他图书馆。
他们只要继续计算这个,但是当他们计算哈希码时,他们喜欢保存它,他们记住了,它们将其保存在字符串对象本身的对象中,在某种程度上,所以如果你要为那个字符串再计算一次,我已经拿到了,我不知怎么救了它。
所以你可以做很多小技巧,你说原木,我是说我的例子,如果我只是阻止了一个字符12,我不是木头,我只是不变,以12为常数,所以你可以做很多不同的变化,是啊,是啊,这里有一个快速的例子。
就像你只是散列一个结构,就像一个有x和y的点,这是对象的整个状态,您希望对其进行散列,你基本上就像,把污渍放在一起,把它们乘上一些东西,你知道我的意思,为什么我把y乘以这个,把x乘以那个,我不知道。
我只是挑奇怪的数字,所以会把人数分散得很广,是啊,是啊,我只想让你把那些乘法常数,例如,每次乘以31,那不是意味着整数会,是啊,是啊,这不会像用负片之类的东西包起来吗?会的会的,但我们只是去,好啦。
谁在乎,它会,会有一些int,一切都会好的,是啊,是啊,我同意就像,如果是一根长绳子,你可能想挑一个小一点的哈希什么的,我想这个想法是,它真的在周围优化了,大多数字符串都很短的事实。
如果你把战争与和平的全部内容,这将是一个糟糕的时间,你会溢出一百万倍,所以这是给你的,它主要适用于短弦,不管怎样,我会说,任何东西都可以散列,因为基本类型的数据可以以双倍的形式散列,布尔人,字符串。
一旦你知道怎么做,所有其他数据类型都只是,所以你只要把碎片拼凑起来,把他们所有的小脑浆都拿出来,获取对象状态的所有片段的哈希码,然后用不变的乘数把它们加在一起,这就是你的哈希码,只要你的公式是一致的。
已经够好了,它是不完美的,会有一些碰撞,但这已经足够好了,结构分布得很好,所以我想说的另一件事是,我一直在谈论如何实现哈希集,那么如果您很好地实现了哈希映射呢,差不多是同样的想法。
除了小节点存储了两件事,一种派斯或一个键和一个值,而你正在散列的是关键,所以我的意思是,这个例子假设马蒂的哈希码是五,所以我把这些数据存储在那里,是同样的想法,你只是有一张纸条。
我不知道我有没有这张幻灯片,“井在哪儿呢?我想我没有,但是如果你有一个哈希节点,它只有一个数据和一个,他和A和一个值和一个下一个,而不仅仅是一个数据和下一个,所以它会稍微修改你的算法。
像添加或删除和包含基本上和放置、删除和包含键是一样的,嗯,所以逻辑本质上是一样的,唯一的区别是,如果你把你记住,你可以替换,如果你把马蒂逗号10,然后你说把马蒂逗号二十,你需要用20来代替晒黑。
所以你去寻找旧的名字和价值,你把它擦洗掉,换上新的,所以我的意思是有一点点像地图,你在这里必须做的具体逻辑,但不是很多,所以这就是你如何实现的,事实上,我不认为这在我的幻灯片里。
但如果你去看看我们哈希的源代码,映射和哈希集集合,你会看到这两个东西的这两个实现是如此相似,他们在一起会有点多余,对呀,所以我们做这件事的方式,如果您查看哈希集的源代码,你寻找私处。
您发现哈希集的数据是哈希映射,从您想要的数据类型布尔的真正含义,它在这里,你明白吗,就像哈希集,它只是一个从值到真的哈希映射,所以我们这样做只是为了避免重写相同的代码,是啊,是啊。
所以你能回到哈希图而不是逻辑吗,但你是说这里的幻灯片,是呀,是啊,是啊,为什么像35下一个地方,哎呦,哎呦,哎呦,对呀,小心点就行了,因为你所说的,为什么是三,五到二而不是五,记住我们要散列的是钥匙。
所以有点困惑的是,我的意思是这条街就像一个杂凑物,二的代码或修改为二的代码,所以从这张图上看并不清楚,但我只是编造了这些数据在这些索引中,但它与这里的这些价值观无关,一切都与,是啊,是啊。
所以就像补语是王牌嗬,作为哈希掩码,从钥匙到两把。
两个布尔值,会不会是在浪费空间,是不是有点浪费空间,是啊,是啊,规则没那么大,所以没那么糟,但是我们的图书馆通常是为其他事情而优化的,不是为了最小的内存消耗,其实呢,如果你去看一些语言和库。
他们有专门版本的哈希集,对某些类型更好,为了节省几个字节的内存,或者别的什么,如果您将规则的哈希集,从技术上讲,公牛可以表示为每个一位,而不是像一个输入四个字节,所以与其浪费大量的内存。
如果你碰巧做了一个公牛的哈希集,他们实际上用一个完全不同的实现来交换你,那非常,非常,非常紧凑,他们不会为其他类型的人做的,现在我们不这么做了,我们的图书馆基本上是为了简单易读,相对来说,所以是的。
我们,我们只是选择不优化它,啊,库需要O的log n来读取。
那要看你在找什么,是啊,是啊,关于这个散列还有什么问题吗,所以这是最后一次,我现在想说的是哈希,我觉得真的很酷,对我来说,你可以像这样做任何事情,这很神奇,当我第一次了解到它的时候,我真的不太相信。
我就像,但如果你必须在列表上循环,那不是恒定的,它有一个环,男人和我不得不喜欢,去测试一下,一堆说服自己,背诵随机大小,可以吗,重新散列到随机大小,好吧,只要它比原来的大,那很重要,也有很大的原因。
它必须比一个乘法因子更大,就像如果你的旧数组是一千个,你做一个新的,那是一千零二十并没有多大帮助,它需要像两千或四千,或者是多重因素,原因是如果你,如果你想计算,记住这一点,就像大多数广告一样快。
但偶尔你会有一个非常慢的广告,必须调整大小,所以问题是这是否破坏了增加,答案是否定的,因为你可以把那个昂贵的大O的大小,你可以把它的一小部分,在所有其他广告中,你可以摊销那个昂贵的成本。
但这是唯一可以做的,如果你不需要经常调整大小,所以我的意思是,如果你在这里做一些餐巾数学,你发现如果你,如果按相加而不是按乘法调整大小,广告成本足以搞砸你的大O,但如果你每次乘以2、3、4或其他什么。
这样大O就不会搞砸了。
所以我说我要谈谈遗产,但我说了太多哈希表,所以关于遗产我就不多说了,我告诉你一件事,虽然我喜欢做这些关于继承的恶魔练习,它们被称为多态神秘问题,在你的版面上有一个,讲义,你的部门,领导可能会说。
待会去看看这个,或者他们可能已经检查了一些,和你在一起,我觉得你应该看看这个,所以我做这样的问题,在那里我有这些不同的类相互扩展,他们有不同的方法和类似的东西,看,我有四门课,叫不同的东西什么的。
然后我给你一个问题,我让你看,我给了一个问题,我说嘿,如果我做一个雪变量,雨夹雪物体的来源,我希望这种方法在物体上,它是做什么的,我建议我,我现在只有几分钟的时间来讨论这个问题。
但我建议你看看这些幻灯片,请看你们的讲义来了解这一点,并熟悉这种继承行为,我是说基本上发生的事情是,您可以创建一个类型的变量,该变量指向另一种类型的对象,只要另一种类型是它的子类,允许你这么做。
但是当您调用这些方法时,运行的方法是来自实际对象的方法,不是变量,好啦,所以这是一种简单的思考方式,除非这个方法在这里也找不到,它不会编译,所以这个类型是否有这个告诉你代码是否编译,但是一旦它编译。
这是这种类型的方法版本,所以这就是一个过程,如果我问你这样的问题,你得检查一下,如果它通过查看变量类型来编译,如果它编译,您可以查看右边的对象类型来计算输出,现在还有一个额外的皱纹,有时我也会打字。
所以我声明了一个变量,我存储了一个不同类型的对象,它是一种子类类型,把它转换成其他类型的,叫它,所以现在我真的搞砸了你们的权利,那么你怎么知道它的优点是什么,我就告诉你,这和我一分钟前说的基本相同。
除了铸造效果,它是否会,所以记住我在左边的类型告诉你它是否编译之前说过的话,右边的类型告诉您代码的正确操作,这里也差不多,只是不要看这个类型,看看它是否编译,您正在查看此类型,看看它是否编译。
暂时将此视为,所以这是一个基本的想法,除了还有一个部分,也就是说,如果你不应该把其中一个传递到其中一个,会导致代码崩溃,这种事情的一个例子是,如果我有像雪、雨夹雪和雾这样的课程,如果我把雪变成雾。
但物体实际上是雨夹雪,我把它铸成它本来的样子,你知道我的意思,变量可能不如对象类型强大或不太具体--没关系,当你通过,您通常会从变量类型传递到对象中,它真正的类型,如果你投到比实际情况更低的地方。
它不改变对象,它只是诱使编译器认为它是那种类型的对象,它能做的是,它会导致编译器在实际运行代码时崩溃,一个例子是,如果下面这个类有一个名为method的方法,只有在这里,其他班都没有,有办法的。
我有一个雪变量,指向雨夹雪或雨什么的,如果我把它扔进雾中,然后尝试调用一个方法,它将编译,因为博格有办法,但当我实际运行代码时,物体睡着了,它没有办法,所以说,当编译器尝试执行它时,那里没有任何代码。
代码实际上会崩溃,所以有点奇怪,基本上,当您遇到这些问题时,进行类型转换,您必须查看强制转换类型,以查看代码是否将编译,或者不是绿色的,你得确保方法,当你运行它的时候,您必须从对象类型运行一个。
但你也要确保这个石膏不是非法的,但你不是在投不是这样的东西,如果它不能投进去,你得说这一行代码崩溃了,所以这都是一堆垃圾和胡言乱语,但都是遗产的问题,我建议看一些像这样的练习,就像这些幻灯片上的。
如果它完全无法破译,下周问问题,我们可以一起复习,但从周三开始,这些关于继承的演讲幻灯片都在这里。
这些是11月2号9号的,正如我所说,在你的部分有一堆像这样的例子练习有问题,本周讲义,好啦,这就是继承和哈希,现在是上课的时候了,所以我要让你去有一个很棒的周末,星期一我们会再回来一周。
【编程抽象方法 cs106x 2017】斯坦福—中英字幕 - P24:Lecture 24 - Sorting - 加加zero - BV1By411h75g
现在是第11周或第10周什么的,我不知道我们怎么称呼一周了,但这是讲座的最后一周,你们兴奋吗,你想说什么?你不喜欢我的课,你很期待我下课,听到这个我很难过,你应该发出嘘声和嘶嘶声,人群中应该有哭泣。
来吧,来吧,给我一些爱,嗯不,开玩笑的啦,我是说,我知道我们都很期待寒假,我们快到终点了,从今天起还有一个星期的课,一大早,你要参加我们班的期末考试,今天晚些时候,我要贴一些练习考试和学习材料。
你可以看看,所以看看那些,你会在网站首页看到公告,当这些都起来,嗯,大部分覆盖,专注于我们从期中考试开始研究的材料,呃,是啊,是啊,所以没有真正把注意力集中在考试上,我打算在星期三多谈谈考试的事。
今天少星期五,今天我们要谈谈分类,而今天的内容将是最后一个,我可能会在期末考试中测试你,就像星期三,我将基本上谈谈你会怎么做,如果没有斯坦福图书馆,如果你只需要写真正常规的c+,你将如何生存。
你会怎么做,我还谈到了某种图书馆,特别是您可能感兴趣的智能指针库,不管怎样,在那次演讲之后,如果你要去一家公司工作或实习,你可能知道更多如何做到这一点,因为大多数公司不使用我们的斯坦福图书馆课程。
然后在星期五,那将是我们最后一堂课,我要做一些总结,谈谈我们学到的,给你们一些建议,关于课后你可能想做的事情,我还要谈谈期末考试,一点点,做一点回顾,上面会有什么,复习一些话题,回答一些关于这些的问题。
这就是本周的计划,你们周五有八点的作业要交,所以希望你们正在努力,只是一个小问题,Who’谁已经做完家庭作业了,不是很多,好啦,谁还没开始,我知道有些人就是不抬起头来,他们就像,我不想承认,没关系。
那很酷,你不必还没开始,但你要等到周五,所以留意一下,好啦,好吧,反正,这就是我们目前的情况,今天教大家分类,嗯,你们中有多少人以前学过排序,是啊,是啊,你学过哪些排序算法,博戈排序,气泡排序,哇塞。
好啦,嗯,我要去,我基本上假设你没看过,但我也会试着用一个教它,零六x的方式,所以我会试着过得快一点,但你知道吗,没关系的,如果你以前学过一点排序,希望今天我能告诉你一些你不知道的事情。
即使你以前见过排序。
所以好吧,开始分类,什么是排序,它是当你把事情重新安排到有序的时候,哇塞,嗯,我是说,我想我们有一种秩序的感觉,你会把事情分类,就像,如果你在分类整数,你按数字顺序排序,如果您正在对字符串进行排序。
你按字母顺序排序,或者类似的东西对吧,所以我们有一种感觉,就像数据类型一样,天生就有一个与他们相关的命令,对于某些类型来说,这可能是正确的,比如,也可能是字符串之类的,你可以称之为自然顺序。
虽然我只想说清楚,你可以把事情按不同的顺序排序,就像如果你想按长度排序,所有的短的先,所有的长的后,那还在排序,只是按不同的顺序排序,你知道的,安排权,那也算排序,实际上。
许多排序库或算法将允许您有时指定,比如我怎么分辨哪个在前面,还有哪些,这样你就可以调整它被排序的顺序,但不管怎样,我的意思是,排序经常在像这样的计算机科学入门课上教授,这可能看起来有点奇怪。
因为这是一个已经解决的问题,就像你知道的,排序您通常只是调用一些库函数,它分类,然后你就完蛋了,之后你就不怎么想了,所以它可能看起来有点平淡无奇或者不值得报道,或者类似的东西,但我想你知道的原因之一。
我们想教给你们的是,因为这是一个可以解决的问题,无数种不同的方式,其中很多方法都很聪明,有有趣的想法,有趣的算法概念,它非常适合谈论大o运行时,时空权衡,你可以谈论其他话题,就像并行化。
你可以谈论巨大的规模,谷歌如何对万亿个网页进行排序,或者别的什么,你知道的,就像,你可以通过,排序的类别,所以无论如何,我将介绍几种不同的排序算法,常用的或众所周知的,我们谈论它们,谈论利弊。
所以我个人最喜欢的排序算法叫做bogo排序,听起来应该是假的,就像,这是一个假的排序算法,但这不是假的,这是正确的,完全有效,算法如下,如果列表已排序,你完蛋了,如果没有,洗牌值并重复,所以洗牌吧。
希望你能把它们分门别类,它不是最聪明或最快的排序算法,但它最终还是起作用了,只要你随机,最终找到排序的顺序,会成功的,所以我的意思是,人们把它作为一个非常愚蠢的算法的例子,最终还是会找到正确的答案。
假设我们有一个很好的随机数分布,对呀,需要多长时间,这个算法的平均最大O是什么,我是说你得说最坏的,最坏的情况,它永远找不到对的地方,因为你总是随机选择错误的答案,但让我们假设。
如果你看看算法能做的所有事情的所有空间,有点像,平均案例运行时间是多少,你有像阶乘这样的答案吗,你为什么说我认为这可能是对的,是啊,是啊,是啊,是啊,我是说,把它想象成这里不同顺序的数量。
或者我想我也是从概率的角度来考虑的,就像如果你有,我把它当成一副纸牌,想象你洗牌,你被评为2-3-4-5的几率有多大,你很清楚,这有点像,第一张牌是正确的第一张牌的几率有多大,这副牌有五张两张牌。
所以这是正确的可能性,第一张是五张中的一张,对了,那么下一张牌是正确的第二张牌的几率有多大,你可能会说五十二个中的一个,但前提是你没上过概率课,就像一零零九,你学得很好,又不是五十二个中的一个。
你已经用过了,所以五十一分之一是对的,所以你在倍增,五十人中有一个,两次,五十人中有一个,十有八九,一直到最后一张牌,如果前五张1牌的顺序正确,那么最后一张牌,根据定义,必须是正确的一张。
所以这是一个中的一个,所以是的,这有点像1/52的阶乘,这就是你做对的几率,所以如果这就是你做对的几率,把它翻过来,而且是的,有点像阶乘,是关于你要花多长时间才能找到合适的,粗略地说,这是代码。
我实际上写了这个算法,其实呢,我从伯克利雇了一个分包商来写,它花了他们,你知道四分之三的全职工作,他们给我买了这个,随便吧,你知道的,虽然没有排序洗牌,然后它排序,我只是绕过去看看邻居是否井然有序。
或者对我们来说不是一路,实际上这个算法最难的部分是洗牌部分,就像如果你没有洗牌功能,我们还没有真正谈过这件事,但就像你如何洗牌数组或向量的元素,如果您没有这样做的库函数,你知不知道,别把它们弄乱了。
你没有任何魔法图书馆可以为你做这件事,你有什么想法吗,你想得很好,如果你有某种随机性,我不知道这是不是最好的办法,但一种方法是,在列表中随机选择一个时刻,吹灭它,把它放在一个新的列表中,然后重复。
免费名单上的另一个新的,现在你从n减去5中选择,但是你知道,是啊,是啊,我想基本的想法是喜欢,从列表的原始顺序开始,并对其进行随机操作,要么随机提取元素并将其放入结果中。
或者随机选择成对的元素并交换它们之类的,尽管出于,我没时间陪你,一定要小心,因为如果你做错了一点,你最终会有一个非偶数的概率,如果你做对了,五张两张牌都有五分之一。
两个平等的机会在五个两个位置中的每一个,但如果你做错了你的随机性,你对一端或另一端的可能性衡量得太远了--敬请关注,你会在一个零里学到更多关于这种东西的东西,三一,九门计算机科学理论课程,但不管怎样。
这里有啊,这里有一个,啊,我没有带洗牌密码的幻灯片,我不是什么,反正,我以为我有下一张带洗牌的幻灯片,但基本上很多人做的算法是,它们循环每个索引的列表,他们在它前面选择一个元素,他们交换它们。
你只要照着单子走就行了,然后当你做完,你现在是交换,你的算法很好,就像把东西拉出来一样,只是做一个辅助结构需要更多的记忆,把它建立起来,这东西只是在原地交换人,它做了同样的事情,但这些都是好主意,反正。
那是博戈排序,你想看看博加索特吗?我在班级网页上有一个拉链。
我很确定我这里有bogo排序,是啊,是啊,博戈排序,所以在这里,哦,我想我必须有我该做什么,我没有,所以是的,洗牌算法,从零开始,走到长度,从那里到最后挑一个随机数,如果你选择了不同的索引,那就交换吧。
所以博戈排序,所以我这里有一个主,我的主,你知道,如果你以后想看这个代码,你可以,但基本上我所做的是,我做了不同大小的向量,我用随机选择的数字填充它们,然后我对它们运行一个排序算法,我知道要花多长时间。
所以让我们做博戈排序,我可以调整这里的尺寸限制,所以让我们从两个开始,上升到20乘以2,我们做n加,我看到你举起手来,我等一下再打给你,跑到这里来,我们走,它一直做得很好,直到九点,呃,哦对不起。
你有一个问题,是呀,啊,是啊,是啊,所以有这样的东西,啊,那是某种字符串洗牌代码,是啊,是啊,我做错了事,我想,但不管怎样,这个想法是对的,你有索引i和j,你随便挑一个J,然后摇摆什么的。
我不会让它跑得更远,很奇怪它从这里跳到这里,其中一些只是它的随机性部分,但这是一种可怕的,我是说只需要四秒钟就能把十件事整理好,我弟弟的分类速度比这还快,所以来吧,嗯好吧。
所以我要关闭它,它是阶乘的,我想你是对的平均案件运行时间,这个太傻了,让我们继续前进,让我们继续前进,这里有一个不那么傻的,但还是有点平庸,它被称为选择排序选择排序是你在数组或向量中遍历的地方。
找到向量中最小的元素,你把它移到前面,所以像这样是原始数据,我走了全程,我寻找最小的值,我想这是指数三的负4,所以一旦你找到了,你把它换到前面,现在我要小心,掉期,我不是在说矢量,就像移除和移动。
然后插入移位,换班代价高昂,我们不想转移,所以我们找到了,我们只要把它的值和前面的值交换,好啦,交换而不是移位,所以现在我们做完之后,你可以把它想象成,这一个元素现在是数组的排序子部分,现在我们重复。
我们寻找下一个最小的,我们把它们换成索引一,所以我认为这两个是对的,所以指数12的两个掉期,现在前两个索引是排序的子组件,我们寻找第三小的元素,我们把他们交换到下两个,你只要一直这样做。
直到整件事都解决了,你觉得这是什么代码,基本上你可以用稍微不同的方式来写,但对于每个指数来说,我从I开始,然后走到末尾,在数组的那个区域中寻找最小的值,我们称之为指数最小值,一旦我们找到小敏。
如果一分钟还没有在正确的位置,把它换到正确的位置,这个算法的大O是什么,N的平方,1。你为什么这么说,是啊,是啊,因为它在名单上走了一次,是啊,是啊,我是说这种简单的答案很好,它有两个相互嵌套的循环。
它们都上升到矢量的大小,我是说你的回答稍微好一点,因为只有两圈,并不总是,你们知道你们,我期中考试用这些老掉牙的问题骗了你们,写两个循环并不总是意味着n的平方,但是是的,这个很合适,这个很合适。
看起来很漂亮的n平方,现在给我死,当然,它不会从零到大,从零到大,这个从零开始,但这个就像我加一个一样大小合适,所以内循环小于n的事实,我想我们以前谈过这个,对吧。
如果你有嵌套循环,外循环是n次,内循环是n次,下一次内环是n-1,下一次是n-2,下一次它是n-3或者类似的,最终你会得到一个三角形,我不会画直线,但是您最终得到了一个三角形的运行时。
所以n的平方就是整个矩形,这几乎正好是那个的一半,所以是n的平方除以2,我们知道大o和2的平方仍然是大o和n的平方。
所以这个算法是n的平方,所以是的,这就是选择排序运行所需的时间,很容易理解,虽然是对的,简单算法n平方运行时,所以是的。
我是说,我们可以运行它并测量它,我想在这里而不是博戈排序,啊,我本来应该,我想保存这些,让我们,让我们在这里保存一些运行时,别读那个,这是博戈选择排序,让我们做选择排序,然后我在哪里进行选择排序,好啦。
开始了,哦等等,你知道的,我排序像十个元素,因为我把它校准为bogo排序,所以应该是N次,初始大小应该是,我不知道十个,最后的尺寸应该是十万左右,我不知道是什么,我想让你看到的是。
如果我将数组的大小增加一倍,运行时几乎增加了四倍,对呀,那是因为二的平方等于四,此运行时与输入大小变化的平方成正比,好吧,如果我是说我,但我想我经常看到这种情况,人们去的地方。
Oh n平方表示运行时增加4,就像嗯,那只是因为我把数组大小增加了一倍,如果我把这些尺寸,乘以这里的十倍,然后这里发生了什么,一百倍,对呀,从两万到两千,或者它会上升一百倍,是啊,是啊,所以是两个四。
因为四是二的平方,所以是的,这是一种运行时,我们在这里结束,好吧酷,这就是选择排序运行时,你知道这里的运行时间是可以的,在波戈时代,我们可以整理一万件事,排序有点像什么--九件或十件事,好一点了,好啦。
让我们看另一个排序算法。
那个是n的平方,我相信我自己,嗯,所以插入排序,我想这个是大多数人类使用的,当他们不得不对实物进行分类时,就像我在期中考试后收集测试一样,然后我想按字母顺序排序,我所做的是我从一个开始,然后我拿第二行。
我走得很好,你先去还是后去好的,我现在把你,你们两个现在各就各位,我拿了第三个,我插入你,我基本上抓住每一个测试,我把新的测试放在我的小分类堆里的适当位置,我整理的东西越来越多,直到我抓住所有人。
我在现实生活中就是这么做的,当我整理东西的时候,这就是插入排序,所以它也是一个n平方算法,我给你看一下,我觉得这些算法都更容易理解,图片视图,所以我有个想法,如果速率从这个数据开始,一开始你说,嗯。
让我们把第一个人看作是我排序的圆周率,从本质上来说,你知道他是按大小一的定义排序的,排序正确,所以现在我要做的是,我要去看看第二个人,我只是想知道他去了哪里,关于我整理好的那堆,所以他比我的单元素堆小。
所以我把它们换了,所以现在我的一堆是这样的,这是二号的,现在我要看第三个人,八个,我想把他放在我分类的正确位置,基本上是你交换,掉期,换回来,直到他们在正确的位置,所以15是太大了。
所以八个掉期回到那里,现在我整理好的一堆有那么大,所以现在下一个是,我有一个,我想插入这堆长度,三个,所以我交换,掉期,再把他换到前面去,不是移动,移动,增加,移动,这是交换,掉期,掉期,掉期。
所以每次你看下一个元素,并根据需要向后滑动它们,我在最后一张幻灯片上说,我想最后一张幻灯片说运行时是n的平方,我想谈谈那个,我想试着说服自己那是真的,或者帮助你们相信这是真的。
我还想谈谈不同类型的数据和不同的数据安排,他们会对这里的运行时做什么,所以我们确信它是n的平方,比如这张图片或算法描述给了你本能,它将是n的平方,你觉得怎么样,是啊,是啊,我觉得是的。
它让你想起了一个黄色的三角形,只是看起来像那样,是啊,是啊,是啊,是啊,我想是的,我是说每一个,所以这个东西,这就像垂直n次传球,或者N倍,我将增长我的排序区域,对呀,所以这个轴很明显是n。
真正的问题是水平的,我们做对了多少工作,所以这要看,每一关你要做多少次这样的小交换,什么情况下我必须做大量的掉期,相对于我不必做很多交换,对不起,什么提高你的铜三三小,哦,当然,我是说费率的大小很重要。
但我只是说对于给定大小的数组,数组或值的排列中的哪些值在得到时产生更多的筛选器,如果原始数字是向后顺序或接近它,我将不得不交换很多,把人调回正确的地方,但相比之下,如果它们已经排序或接近它。
没有太多的交换需要发生正确的,因为你可以去把下一个人加入你的分类堆,你说嘿,他已经比我整理过的一堆里的每个人都大了,我什么都不做,我只是把他留在原地,所以实际上,这个算法做的工作少了很多。
如果输入数组已排序,少了多少工作,它实际上做的工作很少,以至于运行时下降到n的o,如果输入已排序,因为基本上在这N个过程中的每一个,你开始一个循环,然后立即停止循环,所以有N次你达到顶峰。
但又放弃循环了。
所以这有点有趣,如果我运行插入排序,让我回到我的顶部,我做插入排序,我管理它,这与选择排序运行的数据类型相同,你可能会说很好,我不记得我们把这和什么比较了,所以让我下降到这里,这些是选择排序的数字。
你看到了吗,对于相同的输入,插入要少一点,现在有点像二点半,我不知道,大概少了百分之几的有趣,它仍然有这样的时间,但几乎是四倍,我总是有学生问我,但它似乎并不总是跳四个,但我觉得你有点想忽略小的。
因为微小的数字会受到微小波动的影响,就像你的电脑在那一毫秒内碰巧检查了你的电子邮件,或者你知道你想要的东西,更大的数字更能说明问题,对,所以真的起来了,这里是喜欢的地方,看看有多近,几乎正好是四倍。
那是个更好的数字,你知道很好很好,那是插入排序快一点,我去看看,我试着回忆,我有办法喂它吗,我有一个填充,随机int向量,我有分类的填充吗,我这样做,好啦,好啦,我是霉菌,我什么都不记得了。
如果我将此更改为填充排序,所以数组之前已经排序了,我甚至在上面运行算法,看看插入排序有多快,是呀,它像成千上万的元素一样在短时间内完成,因为它几乎不需要做任何工作,你也许会说,我能很好地测量运行时吗。
是啊,是啊,当然啦,你当然可以,你可以把N做得更大,你知道你可以让最大n是那么多,我不记得它什么时候用完了内存,但我的意思是,在某一点上,您开始在这里看到可测量的运行时,即使那也不是很多。
如果你想测量更多,有时候,你能做的就是,您可以多次运行算法和时钟,这样也会有所帮助,但我的意思是基本上如果我把输入翻倍,的,运行时,这些小数字很难读懂,但它有点翻倍,基本上是关于,它更像是一个大的。
如果数据排序正确,那很酷,好啦,所以让我把它放回去,让我把它放回去是随机的。
所以无论如何,我觉得那个很有趣,就运行时而言,这是我们迄今为止看到的最好的一个,它还有这两个有趣的属性,你知道这个有趣的属性,输入的顺序对选择有很大的影响,所以我没有对排序的数据运行选择排序。
但这没有多大帮助,因为选择商店仍然为每一个通行证要走和看,一旦它完成寻找,它说是的,我不需要做什么,走啊走啊走啊说,我不需要做什么,不少学生尝试提出优化方案,他们进展顺利,如果我写了选择排序呢。
但首先它会走路,看看整件事是否解决了,如果是的话,它就不会做所有的选择,就像,是的很好,但我的意思是,大多数输入不是完全排序的,就像排序或大部分排序,所以你的小优化对这些都不起作用。
所以这是很难喜欢心理出来,尝试用算法中的一些技巧来击败它,基本上没问题,那就是插入,把我们目前看到的问题分类,是啊,是啊,我们为什么不用像,哦,像跳到正确的地方把它使用二分搜索,是啊,是啊。
那是个好主意,我是说我想你会发现,虽然就像,即使你找到了那个地方,你还得给他腾出地方,所以你得把大家都移过去,这基本上和交换交换是一样的,你知道我的意思,就像你一样,这样您可能可以节省少量的运行时。
但我想你会发现他需要移动的每一个索引,其他人也需要搬家,所以我不认为这会有什么大的不同,但不管怎样,好啦,那是插入排序,现在呢,到目前为止我们看到的所有这些类型,博戈排序以外的,它们是基于交换的。
基于比较的排序,所有这些性质都倾向于有n平方的运行时,所以现在让我们来看看更多聪明的想法,跳出框框,也许我们可以走得更快,我想说的第一个是合并排序,你们中的一些人可能听说过合并排序,或看到合并排序。
之前这是一个相当流行的排序算法来教,尤其是在这样的课堂上,这里的想法是把你的未排序的数据,你知道的,数组将其切成两半,把两半排序,现在把排序好的两半,把它们重新组合在一起,所以好吧,所以说。
这里的主张是,这可能比我们目前看到的其他方法更快,让我试着举例说明,所以有一个,有一个大小为8的数组,你能做的就是把它劈成两半,现在你可以把这一半分类,你怎么开始半场,所以你知道错误的答案是你说好。
我会在每一半上调用选择排序,或者我称之为插入排序,那也没关系,我其实经常得到这个答案,但是,当然,这是一个递归,自我相似的想法,所以哦,我可以把每一半合并排序,当然,只有当我们的算法是正确的。
但你知道如果你假设它会起作用,所以我可以合并排序左边的一半,所以这又意味着把它一分为二,我们可以把这一半合并排序,我们会把它们分成两半,这有点傻,但在某些情况下,比如你得到了一个带有递归的基本情况。
这里的基本情况是什么,如果有一个元素或空,好像没什么可做的,在一个长度内没有什么是不排序的,右一分,好啦,所以这两个家伙是天生的,现在在回忆之后,算法说的是你把分类的谷壳,这已经很平常了。
然后你把它们合并,你怎么把东西合并在一起,嗯,你们两两一组,你看着每个人的前面,你拿一个小一点的,把它们放到这样的结果中,所以你会看着这两个,说18个更小,然后二十二,所以我会把它们按那个顺序放回一起。
所以这就是结果,然后在右边,我会做同样的事情,我把这个分了,我说,哎呦,那些应该这样放,所以现在我想这可能是第一个案例,在那里合并不那么微不足道,所以你合并这些的方法是,你只要看看它们的正面。
你看哪一个小,我要那个,所以如果我喜欢这家伙,我带他去,现在你把十八和十二作比较,你知道我的意思,你两者都在走,你可以从每个起点中选择哪一个较小,所以我拿着这个,然后我要拿着这个,然后我拿着这个。
然后我会拿着这个,所以我最终得到了这个,这边是我的结果,我分裂,我合并在某个时候,我基本上做了我说过要做的事,也就是我一分为二,然后我整理了一半,现在我走过两半,把它们合并在一起,我最终得到了这个。
所以这看起来很可笑很复杂,我想有些人很难想象,为什么这会有效或更好,和选择排序或插入排序,当然是更多的代码,你知道这是典型的谬论,人们有大约大,O就像代码很短,就像选择、排序和插入排序的代码一样。
非常紧凑,但这需要更多的代码,但是会更快对吧,好啦,所以让我们来谈谈,如果你有这两半,你如何将它们合并在一起,就像另一个例子,想象一下,这里有这两半,你需要合并它们,所以事实上你知道它们都是排序的。
一半都排序好了,你可以利用,我想把这八个数字复制到一个结果中,全都在那儿了,所以你所做的就是你我的意思是,你可以把它想象成你在指着,或者在开始时每个数组都有一个索引,你就说哪个小,哦,我喜欢那个。
他比较小,所以我把他放在结果里,然后我移动,我在这里加上它的索引,现在我比较这两个更小的,两个三个,所以我把它们放进去,i加上这个指数,我把这两个比较小,这一个让他们在一个加分,另外,你要明白。
你要这样做,直到你走过这两个,你把它们都用完了吗,现在你得到了一个结果,这要花多长时间,这个结果就像那边的n,这个要多长时间,它需要一个正确的,因为这两个中的每一个,每项费用,你拿一个元素,你做了N个。
所以合并需要N个时间,我需要弄清楚合并的运行时是什么,在算法的每个级别上排序,我拆分并进行排序,然后我合并,所以我想我喜欢这些关于大O的空间想法,因为这是直觉,我想是的,这有点像,这种面积是多少。
你知道嗯,就像合并一样,所以我认为它就像水平的,我有张照片等一下,别看那个,对于算法的每个级别都是这样的,你把你的一分为二,你劈开劈开劈开劈开,然后你把人们重新组合在一起,所以这有点像。
像分裂和合并的水平时间是n个时间,好的我们只需要计算出我们要做多少次,得到这个的垂直分量,然后这些的产物基本上是我们的运行时,这不是一个很好的证明,但这种对它的直觉思考,所以差不多是这个井的N倍。
这个有多高,这东西有多高?是啊,是啊,我想它在滑梯上,对不起,我不该问你是不是在滑梯上,但是,是啊,是啊,因为你除以2,除以二,除以二除以二,你必须将某物除以2的次数,为了得到一个,等于你要乘以的次数。
一个接一个去拿你的东西,这就是以n或2为基数的对数,所以是的,这就像N次登录,所以这变成了n,log,n而不是n的平方,我希望你们现在知道了,n,log,n比n的平方好,我也希望你有直觉,n,log。
n比n的平方好多了,不只是好一点,好多了。
所以我想和你们一起写这个,很快的,我们有时间,所以,嗯,记住合并排序的算法合并排序,算法是将数组一分为二,所以这些部分比这里的其他部分更难,我帮你把第一部分一分为二,有一个很好的方法,int左等于向量。
有一个方法叫做v点子列表,子列表需要一个开始和一个长度,所以从零到什么是第一步,是的,两码以上,对吧,好的,现在我们有了右向量,在右=v的子列表中,剩下的部分是对的所以基本上我们想从v点的大小。
你得通过第二个指标,我忘了我应该换它,所以你不,哦,好吧,嗯,然后像有多少元素在这,我只想说v点大小减去左点大小,你知道我的意思,因为你可能会说2号以上,但它可能是奇怪的尺寸可能是左边或右边多一个。
或者别的什么,所以不管我拿什么,这两半,对呀,好啦,这是第一部分,对半排序,嗯哼,我不知道该怎么做,那很难,合并一半,这也很难,嗯,好啦,我们说这是递归的,我想让你们用这两个部分告诉我。
我做这部分是为了你们,这很棘手,那么我如何对这一半进行排序,我在这里放什么,是呀,很短,合并合并,我还写了Mogo排序合并排序左,这就像一个随机递归,所以我只是随机调用递归函数,哎呦,分形,对,你有吗。
你听说过我最喜欢的愚蠢的排序算法叫做量子排序,这个想法是看看数组是否排序,如果是停止,否则毁灭宇宙,当你做完,唯一存在的宇宙将是数组被排序的宇宙,你完蛋了不是很好吗,我喜欢它,试试看,你去编码。
以后试着编码,嗯所以是的,把一半排序,我想这是对的,那有点,Mumbo,Jumbo依靠我们的代码工作,但我想我们会做对的,所以好吧,然后我们要把它合并,这可能是最难的部分,啊,还有一件事。
这应该是递归的,对呀,所以我们会继续打电话,左边合并排序,右边合并剑,他们必须在某个时候击中一个基本情况,对呀,所以让我们在这里做,我真的没想过,所以这真的更像是,如果我要费心在这里做任何工作。
那我就把这项工作做好,所以如果v点的大小至少是2,我应该做点正确的事,基本情况是明确的,含蓄地做任何正确的事情,所以L空间案例什么都不做,好啦,所以合并一半,这部分写起来有点棘手,但我觉得这有点像。
你知道屏幕上的那张照片我只是有不同的元素,我只是在复制它们,或者我们可以试着模仿这个代码,尽我们所能。
我一个和我两个,你知道我们可以,我们可以做到这一点,所以在i中1等于零而i 2等于零,我们会有一个循环,我们把东西复制回v,从左到右,所以我想我们要做一些循环,我想我们会说int i等于零。
小于v点大小,所以我们要循环v的索引,把东西放进每一个里面,最后我们要说v i=,我们将从左边或右边取元素,所以我想我们需要弄清楚,如果有什么东西,我会从左边取元素,我还要取右边的元素。
所以v i等于左,我一,你明白的,就像有时我会从左边抓住,否则我会在索引处从右边抓起,我两个对,我还没写,我什么都没做,我跳过了最难的部分,但是呃,在这些尸体里我只想做一件事,每一项权利,我还能做什么。
是啊,是啊,是啊,是啊,我也应该增加,如果你是黑客,你可能想这么说,就像我读了那个索引后,然后增加指数,或者在我不能在作业后排队之后,就是这样,管他呢好吧。
我怎么知道我是否应该从左边拿,幻灯片上说选一个小一点的,所以你可能会说为什么马蒂跳过了那部分,好吧好吧,我想我只想说,如果左I一小于右。
我两个如果他们是一样的,这并不重要,所以随便拿一个,但这是正确的答案,但还有更多,我要办个案子,那就不好了,除非我修好它,哦耶,你可能会击中左的末端或右的末端,我可能该吃点。
是啊,是啊,就像如果你,如果你在某个时候经历了这一切,你基本上耗尽了其中一个或另一个,然后就没有剩下了,我一个,没有权利,我两个或一个其他类型的用完了。
你知道我的意思,所以我认为我们应该做的不是去检查他们的价值,除非我们确定两个数组中都有剩余的值,所以我想我想说的是,如果有记得这个,如果是测试,我什么时候该从左边走?所以我应该从左边开始。
属性上没有剩余值或没有剩余值时,左边这个小,你知道我在说什么吗,如果右边没有剩下的值,我怎么检查,如果i 2大于或等于右大小,类似的东西,或者我想我甚至需要在这里多一个测试,就像。
或者我想要的是小于左网点大小之类的,我可能有一个不必要的,如果有这种性质的东西,就像如果我们做得不对,或者左边小一点,我们走左边,好啦,所以我想就这样了,我想就这样了,我们可以在C中运行和测试它。
但一旦我们完成了,所有的V都将更新到新的值,他们应该在这里,大体上,我把它装满了随机数据,然后调用合并排序,为了确保我们没有把代码弄乱,就像我真的检查了,如果它是排序,所以说,如果我们写错了。
密码不会让我们得逞的,因为这将是你可以找到一个突破性的排序算法,这实际上并没有对数据进行排序,所以我想它起作用了,已经完成了,记住如何使用插入排序,对4万个元素进行排序花了40秒。
要对相同数量的数据进行排序,合并排序需要五分之一的时间,所以看起来大O很重要,孩子们,你知道嗯,从n平方到n log n,是一个非常非常大的加速,好吧我想让你明白,所以实际上只是为了真正看到这个运行时。
我想知道在我得到40秒之前我能排序多少元素,那是个有趣的问题,所以让我们把它改成一个更大的数字,让我们试试看,你实际上花了更多的时间来产生随机性,是啊,是啊,其实你看不太清楚。
但就像建立矢量所需的时间一样,把向量中的数字洗牌比它所需的时间长,对向量和滑稽进行排序,我是说这需要一段时间对吧,你可以从这些数字大致推断出,关于我能在40秒内整理多少,但这比选择和插入快得多。
我只想和你一起写,因为我真的想让你看到,我觉得很多人,最初在他们的教育中,他们没有大的本能,O,他们知道这样更快,但我不知道,可能是两次,两次,三次,四次,如你所知,快一点不行,好像快了很多。
它的速度快了几个数量级,它快多了,你只需要这么做,你需要用正确的算法来做到这一点,基本上我想我想我的程序停止了,我连这个都做不到,Z我走得还不够远,所以大约有一千万个元素,在相同的时间内插入排序。
或四万个元素,所以这很酷,我复印一下,我这里有这样的数据,这就是合并,排序酷,所以你知道,合并排序相当不错,实际上如果你去,如果你去下载Java或Python附带的库,或者c+或其他什么。
这些语言附带的实际标准库,他们中的许多人使用合并排序作为他们的排序算法,当您实际对数据进行排序时,另一个排序算法,我的幻灯片里没有,是Python附带的排序算法,我喜欢这个,这叫提姆排序。
那是因为一个叫蒂姆的家伙,我好嫉妒,我就像,那是最聪明的主意,我会喜欢,我来告诉你他做了什么,因为之后我会告诉你我的计划,所以这是蒂姆排序,所以如果你要提姆排序,一种叫做V的向量,大致如下。
如果v点大小小于某个数,就像20个插入排序,这基本上是蒂姆剑是你去谷歌它,呃,可能不是20,我想他们测量了所以这个家伙蒂姆,他做了一堆排序算法的测量,他发现的是合并排序,显然比插入排序快得多,对呀。
但他发现,在某个时候,所有的分裂和合并,拆分和合并确实有成本,所有的递归调用,它确实有一点成本,它真正有高成本的地方就像,如果你有两个元素,你费心把它们分开,然后做一个完整的递归调用。
然后把它们合并起来,只是为了整理两件事,你知道那很傻,为四件事做好八件事也有点傻,有多少事,如果我没有什么,如果我实际上主要是合并排序,但一旦我进入一个相当小的数组,然后我真的在那里做了插入排序。
他发现它更快是因为功能减弱,呼叫头顶和分裂新出现的向量之类的,所以他调整了又调整又测量,他发现有一些价值,我想大约有二四十五十个谷歌,如果你想要蒂姆排序,他发现就像,如果我把这个大小设为常数。
我的快了百分之五,或者快10%,或者类似的东西,这就是Python中的内容,有点不一样,我是说提姆排序,有时间排序的变化,在那里你有更多的选择而不仅仅是两个,你选择的更多变化等等,但这基本上是我的想法。
我就像男人蒂姆,为了钱,那很好,你现在知道了,我好嫉妒,我要发明像马蒂的算法,就像戴克斯特拉的算法,但你一开始就写了你好,在所有的教科书中,这又是马蒂的算法,只要调整一个现有的就出名了,是啊,是啊。
为了这个,就像我们曾经,就像它裂开,就像那样裂开,这就像,少于20的东西就像插入排序一样,呃对不起,我有点过于简单化了,我想我是什么,如果你真的想从字面上理解,呃,它在哪里合并排序,这里比较像。
就像如果左边是二十,做插入,否则做功,所以这部分你还是做这个,所以我会在这里插入,如果不是逻辑,基本上没那么简单,但不管怎样,有点有趣,所以我的意思是这意味着另一个概念,就像有时各种各样的东西都很聪明。
它在某种情况下是有用的,所以合并排序非常好。
合并剑是很多语言使用的,或者它的变体,比如帝汶岛,是许多语言使用的,让我再告诉你一个你没有太多的时间了,但这一个甚至可以比合并排序快一点,这叫做快速排序,因为它很快,我我总是笑。
因为你知道那个叫WH的人,所以他不想称之为四,或者你知道,他们说我们得想出别的办法,我们能不能,我们可以叫它快剑吗那样会更好一点,所以快速排序与合并排序非常相似,在这个意义上,你分而治之。
但它有一个不同的有趣的想法,这个想法是你选择向量的一个元素,我可以谈谈你如何选择哪一个做,你在一秒钟内,你选择其中一个元素,你说这个元素将被称为枢轴元素,好啦,所以现在你要做的是。
您需要使它使您的数组被排列,使得所有小于该枢轴值的值,你看,如果你碰巧选了一个号码,那是四二,你需要排列数组,因此,所有值小于4-2的元素都出现得更早,所有大于4 2的值都在后面。
听起来好像有很多胡言乱语,但如果你这么做,这不会排序数组,因为你知道如果所有小于4 2的元素都在这里,但它们还是乱七八糟的,但我知道他们都不到四二,所有大于42的元素都在这里,但它们都乱七八糟的。
但这并不意味着我被分类了,但如果我继续这样做,如果在少于4 2的区域内,我选择了另一个支点,是二十个,然后我移动了所有不到二十个的人和所有大于二十个的人,在那些小地方,我会继续做这种旋转的事情。
最终你会得到组合数组,如果你再这样,问题真的就像,这是做分类的好方法吗,我告诉你这是因为它是这个算法的实质,但很难有直觉认为这会很好地工作,但让我向你展示一下它是如何工作的。
所以这里有一个随机内容的列表,算法有效,不管你选择什么作为支点,只要你坚持足够长的时间,所以实际上,如果您想编写一个非常简单的快速入门版本,你只要取第一个元素,所以不管他的价值是多少,那是支点。
我们走吧,所以有时候你知道,你可以选择一个糟糕的支点,您希望枢轴大致是数组的中值,你想对分区进行排序,这里一半的人,那里一半的人,如果可以的话,如果你幸运的话,就像这里的数据,什么是一个好的支点,嗯。
我不知道,我真的没有提前看数字,但是,三四十,所以我不知道类似的事情,你想在它的每一边都有一半的元素,所以有一些快速的策略,就像,你如何选择一个真正好的支点,您可以随机选择一个索引,让我倒回去。
其实是这样因为你想把它平分,你想把它均匀地分开,那么,有什么数据或枢轴的例子会非常糟糕呢,如果你总是选择最大或最小的元素,作为支点,这将是非常非常有用的理解,你可能会遇到麻烦,如果你总是抓住。
第一个是支点,因为如果数据被排序或反向排序,这意味着你的支点选择得非常糟糕,所以有些人会随机选择一个索引,其他人所做的是,他们看起来像三个索引,他们选择这三个指数的中值,你所做的事情有不同的策略。
让我试着给你画一个,让我看看,我不是有这张照片吗,在这等着我们走,好啦,所以如果你有一个支点,所以说,让我们假设我的支点是八,对不起,我觉得这张幻灯片有点混乱,但是在这个数组中,也许8是第一个指数。
所以假设我选择八个作为我的支点,你把他们搬到最后,你让他们别挡路,就一会儿,好啦,交换到最后,现在你要做的是,在其余速率的端点启动两个索引,八点零的时候,你带着他们走向对方,这个想法是。
如果你看到左边的东西比我大,那很糟糕,如果你看到右边的东西小于8,那很糟糕,所以如果那个是大的这个是小的,那些不好,所以你把它们换了,然后你继续搬进来,交换交换交换,然后当你做完。
你最终和每个人都在隔板上,所以我试着画一幅画,但基本上你有j和j,你走过去,你看,所以很难想象,所以等等,我选了什么,是我的枢轴六,对不起,对不起,我想我设置错了,我向你道歉,支点是第一个切六。
所以我要做的是,我把他从前面换到后面,所以我要把他挪开,好啦,到这边来,六现在是一对,我开始把我的人从i和j从端点向内走,所以我要找的是,右边六个以上的人是好的,所以我只是从他们身边走过。
但如果我在这里看到一个不到六岁的人,那很糟糕,杰要停在这里停在边上,我在找那些,嗯大于6,所以基本上我的算法停止了,这里是i,那里是j,因为这不合适,这个也出来了,看到了吗,所以我把它们交换了。
然后我就继续前进,如果我继续这样做,我最终在一个不到六个人的人都在左边的州,大于六的人都在右边,你知道的,然后i和j相交的索引是它的中间,然后我把枢轴放回原处,那是我后来放六个回去的地方,所以在这之后。
它没有被正确地排序,但它有点排序,比以前好多了,我的意思是它有点接近排序,所以现在我递归地快速排序这个峰值部分,我很快把绿色部分的荧光笔分类,如果你继续这样,最终数组被排序,很难看到。
尤其是考虑到我的幻灯片很混乱,但是哦,下面是另一个例子,这里是支点65移动65到最后,我走进来,我喜欢这两个家伙,但让我们看看最后交换65,我不喜欢这里的八十一个,因为他太大了,我不喜欢这里的十六岁。
因为它们太小了,所以我把它们交换了,现在我继续搬进来,直到我找到其他我不喜欢的,是哪两个我把它们换了然后走进去,最终我得到了这个,原来如此,好吧好吧,你走过去交换东西,拿着,那需要多长时间,一次。
对的O,你在阵列中行走直到它们相遇,那需要N个,我得做多少次,运行时的高度是多少,如果类似的递归,因为递归调用将在这部分,绿色的部分和这个粉色的部分,所以如果这两部分有一半大,每一个都是合并排序的权利。
我们是一半一半一半,所以这有点逻辑,这是n,这是一种对数,那是唯一正确的,如果这些边大约是,每一项权利,所以如果我选择这些枢轴,嗯,这需要n log n时间,就像合并一样,但问题是。
它实际上比合并好还是坏。
或者它可能看起来和合并排序差不多,我们可以运行它看看,我已经实现了,我已经写好了,您可以稍后查看它的代码,如果你想,如果我运行快速排序,这是我得到的,我想你会看到它更快一点,它实际上要快得多。
在这个数据上大约快两三倍,我在很多其他编程语言和库上看到过,区别不太明显,嗯,关于我们如何实现合并排序,有些事情不是最优的,我们把东西一分为二的部分,矢量和二,然后再把它们合并在一起,从技术上讲。
你实际上不必做一个完整的另一个矢量,对于这部分,你可以把子范围想象成,从概念上对较小的向量进行排序,你知道我的意思,所以就像,您可以使合并排序比我们这样做更有效,无论如何,就差异而言,这有点夸张。
我想说,快速排序的速度通常是合并的1。5倍,剑或更少,通常不那么明显,但你仍然会注意到这里的增长,一些n log n的东西的生长,好像是两倍多一点,每次都是两倍多一点,不是四倍,你明白的,二倍等于n。
二倍加一点等于n,log,n,这基本上就是我们这里的增长,每次都比翻倍多一点,所以这是快速排序,在日志里,略好于合并排序,现在呢,我刚刚告诉过你,这是在我们走之前我要说的最后一句话,我刚刚告诉过你。
很多编程语言使用合并排序或提姆排序,他们为什么不用快速排序,这是因为快速排序相对于合并排序的一个特殊性质称为稳定排序,我就告诉你,这是一个离开的评论嗯,如果你按一件事排序,然后按另一件事排序。
您按主要排序,然后按次要排序,订购,问题是在那之后是,它仍然按照第一件事排序,如果是这样,它是一个稳定的排序,如果没有,它不是合并排序是稳定的,快速排序不是哪个,很多人希望自己的剑能稳定。
这就是为什么快速排序没有那么多的使用,好啦,我没时间了,所有这些算法都在今天讲座的代码中,如果你想看的话,玩得开心作业八,我们星期三的最后一堂课内容见。
是呀。
【编程抽象方法 cs106x 2017】斯坦福—中英字幕 - P25:Lecture 25 - Templates, STL, Smart Pointers - 加加zero - BV1By411h75g
开始了,这是我们今天上的倒数第二堂课,我们星期五上,星期一是期末考试,你现在可能知道了,呃,我很高兴看到你们在这里,我想奖励你来上课,所以我要给你们看一段小狗的视频,是的,是的,因为我爱你们,所以说。
那倒是真的,我应该把视频关掉,不应该,我是的,去他们的,他们没有来,所以说,我们开始上课吧,别告诉他们他们错过了什么,嗯是的,所以我保证我今天也会试着教你一些东西,所以好吧,剩下的演讲时间我要做什么。
下面是我想告诉你们C Plus的一些方面,我们略过了,因为我们用这些斯坦福图书馆,如果你再也不用C++编码了,那你真的不需要这些东西,我今天要告诉你,但是如果你的代码是C++。
在这门课之外或者斯坦福之外,你需要知道如何编写真正的C++,你知道可以说,也许我们应该一直教你真正的C+,但我觉得重点是我们的东西更容易使用,更容易学,如果你犯了错误,比真正的东西更有帮助。
所以这就是为什么我们在这门课中使用它,然后我们想,如果你能一路走到这一步而不辍学和退出,然后你可能会想出如何把这些东西翻译成真实的东西,季度末,这就是我们现在所处的位置。
所以让我们来谈谈吧,在我告诉你之前,我想谈谈一个叫做模板的特性,它与这些东西有关,所以我会到达那里,所以让我们来谈谈模板,这来自书的第十四章,嗯,您可以编写一个模板函数。
模板函数是接受已知类型的参数的函数,所以我的函数没有用int作为参数或字符串,你说我的函数用t表示某种类型的t,我还不知道是什么,所以这个想法是,函数可以自我复制,它可以创建一个自己的版本。
该版本接受一个int,参数,或者一个需要双倍的,或者根据需要取一根绳子,如果你叫它,给它一个双倍,它会制造一个自己的版本,需要一个双倍的,以此类推,我想从一个例子中更容易看出,我给你看下一张幻灯片。
这里有一个叫做max的函数的例子,您给我一个类型为t的值,称为a,类型为t的值,称为b,哪个大一点,如果a小一点,我就把它退了,真b,否则,如果你是一个,所以我认为这个想法是。
您可以通过传递int来调用它,你可以通过传球双打来称之为,您可以通过传递字符串来调用它,你想要的任何类型,它只是复制了这个函数的一个副本,但是它会把t换成int,好像你是那样打出来的。
所以你必须确保的一件事,你想传递的数据类型,它必须支持您在此代码中调用它的任何东西,所以如果我写的小于a小于b,我必须传递一个数据类型,它有一个小于操作,所以如果我在里面通过一个,它不会编译吗?好啦。
或者如果我试图调用函数,就像如果我把那个点说成大写什么的,然后我输入的任何类型都必须有一个两个大写,暗示是没用的,但它可能对弦起作用,你知道类似的事情,这就是模板函数的思想,很多语言都有这样的概念。
那你可以有一个通用的数据类型啊,参数什么的,好啦,您还可以编写使用模板的类,在我们的课堂上,你可能会更多地遇到这种情况,你可以你可以写它类,这是声明类的标准语法,就像H文件之类的,但最重要的是。
你说得好,这不仅仅是一堂课,这是一个类的模板,该类与称为t的数据类型相关,这里的想法是,这是你写作时我们用的,当你有一个向量或哈希图,或者类似的事情,那些是模板类,所以你可以做一个int向量。
字符串的向量,你在这些尖括号中提供t的值,所以如果你说弦的矢量,然后它复制向量代码,其中t被设置为string,这就是矢量的用法,所以这是一个模板类,它的语法有点好笑,你写标题,上面写着模板。
然后在CPP文件中,当您编写所有方法的主体时,你说模板也在那里,这里有一个快速的例子,如果您有一个名为数组到列表的类,或者这就像我在重新实现向量,但写在自己身上,你知道的,但它只适用于它的。
所以你可以添加一个int,你可以把它放入给定的索引中,可以在索引中插入,你可以把这种事情做对,所以它基本上是向量的方法,但它只对它起作用,你说,哦,天哪,我真的希望它对每一种类型的数据都有效。
我们可以把它做成一个模板类,对呀,所以说,当然啦,有些人想做的是,他们说得好,如果它不再是一个收入清单,我把它列成一张清单,或者名单什么的,所以我要搜索并把单词替换为这里的字母t,这让你更接近。
但是有一些词出现了,那是不应该被取代的对吧,喜欢喜欢,哪里有一些应该留在,它不应该变成,再举个例子,大小,是啊,是啊,名单的大小是一英寸,这不是一个T,如果我有一个字符串数组列表。
该列表的大小不是字符串,对呀,所以是的,我应该说,还有什么应该留下来,如果你有不同的答案,能力,哦耶,是呀,下面的一些田地,规模和容量,就是这个尺寸,数组的长度,你有答案吗,是啊,是啊,我做索引,索引。
是啊,是啊,比如当你得到一个索引的值,列表的索引是整数索引,不管索引中的数据是什么都是对的,所以你认为,是啊,是啊,我认为所有索引的出现都应该保持不变,如果你,如果您将此重写为模板类。
它说锻炼就像我们要一起写一样,我不会那么做的,因为我不想那么做,但你知道我们可以我们可以做到,如果我们将最后一段代码更改为模板类,我们就能做这样的事情,列出INS列表,其中之一是基本上是一个向量。
也许现实一点,直接把绳子放进去什么的,因此,练习基本上包括以下内容,就像我们将类声明为模板类一样,然后我们会有选择地用茶代替,在那里做有意义的事情,所以说,添加类型为t的值,你得到一个值。
添加一个一英寸的索引,但是如果它的值是T类型正确的,所以你会穿过这些不同的地方,把茶放进去,酌情,是啊,是啊,所以T是一个占位符,就像你用的那种类型,是啊,是啊,它有时被称为类型参数或类型变量。
就像我认为它只是一个喜欢的替代,如果我写一个现实的字符串,就像这样,从字面上看,遍历这个文件并用字符串替换t,然后它就像承认作为源文件,作为一个程序员,他基本上是这样编译的,你需要负责确保更换发生。
它仍然在这里的一个函数中,我猜函数的类型是T类型,您需要确保所有这些添加实际上是,我是说如果我在这个代码上多花一点时间,我们可以遍历所有这些函数的所有主体,并确保,我拿着这些小T做什么,我想你会发现。
我只是把它们存储在一个数组中,然后返回它们或其他什么,好像这就是我对他们所做的一切,所以我不依赖数据,键入t以获得它支持的许多特定操作,就像我没有试图调用每个T值的方法一样,你知道我的意思,实际上。
这就是为什么它对任何类型的数据都如此有效的原因,因为我几乎什么都不期待,我只需要能够存储和返回这些值,真的,如果你在做一个布景或一张地图,排序成一个顺序,那些模板类试图做小于或大于的事情来计算顺序。
它应该把一切都分类,所以你只能使用那些类,使用具有小于或大于运算符的类型,在他们身上定义有一种方式喜欢,检查要等于什么,有没有像,我可以做喜欢,如果t等于谁这样做,如果t等于做啊,是啊,是啊。
那是个有趣的问题,嗯,C++并没有很好的方法来做到这一点,比如如果你有一个给定的数组列表或向量,或者你能告诉我你喜欢什么类型,什么事?它并不真的支持,有一个特点,如果你想谷歌什么。
这叫做rti运行时类型推断,它试图做到这一点,但效果不是很好,我不推荐更多,现代语言有更好的能力喜欢,自讨苦吃,就像Java有一种问的方式,它在Java中被称为反射,你只要问一个班,你喜欢什么类型。
你喜欢在海滩上散步吗?或者你所知道的,你喜欢什么类型,呵呵,你知道的,你可以用其他语言询问这些信息,但是C++并没有很好的支持,反正,在那里吗,另一个我错过了另一个问题吗,是啊,是啊,那么是什么类型的。
啊,为什么这里写的是类型名,那只是个关键词,我只是说这门课取决于你,提供数据类型的名称,我在这里说,但这基本上是一个变量,我可以让马蒂,然后所有这些无边的,你呀,所有这些茶都是马蒂的,我可以叫它什么。
我见过,最常见的惯例是称之为T,但如果我写得像哈希地图课,这实际上取决于钥匙的类型,逗号值的另一个类型名称,所以它通常被称为类型名,类型名称,五,所以类似的事情,是啊,是啊。
如果你看看斯坦福收藏的源代码,他们不说,他们通常称之为值类型或元素类型,他们用了一个完整的词来形容它,但我个人更喜欢这个小短它只是对我来说,给我的那个简短的大写字母,它说那是一个类型变量。
对我来说就是这样后面还有一只手吗,某处,是啊,是啊,所以当你对类型进行一组比较时,如何指定,啊,如果你像一组或一张地图一样排序,你需要知道顺序,您如何指定如何进行您需要的订购,而不是,是啊,是啊。
所以这节课的作者让别人知道的方式,我需要你的课有一个小于或大于是,你只要用它,然后当他们试图创建您类型的对象时,他们提供的A T没有这些运算符,它就是不会编译,上面写着这条线要求这个操作员,是啊,是啊。
那有点笨重,他们只是不知道,直到他们试图正常编译,您可以在这里对文档的评论中解决这个问题,你就会说嘿,您可以将此用于任何支持此、此和此的泛型类型,有些语言有更多的契约。
在这里你可以说类型名t冒号必须有这个和这个,还有这个或者你可以用,就像这些接口,需要您正在使用的t类型的某些特性的东西类型,但就像Java有Java一样,您可以说type name t扩展了可比的。
现在你只能接受可以比较的类型,你可以做这样的事情,你知道的,但那是,你知道的,他们没有想到这一点,当他们做c+加的时候是1983年,放他们一马,是啊,是啊,反正,这里还有其他问题吗,是啊,是啊,去吧。
还有其他东西可以放在括号里吗?除了时间,类型名称,或者这是唯一的,哦,除了类型,你还能放别的吗,我想你可以说T级,但就像我想他们想让你说类型名,因为这样你就可以提供一个int,这不是一个类,或枚举。
或者其他的事情,我想我不确定C++的语法在这里允许什么,但我知道你可以说上课或打字,但他们告诉你打字更普遍,反正,这是它的基本思想,我不会让你在考试中这么做的,或者做作业什么的,但我有点想填补这个空白。
因为就像你们实现了所有这些不同的集合,您已经了解了二叉树和链表是如何工作的,你可以理解所有这些东西是如何实现的,但是我们总是用int或string来实现它们,这是一种逃避,或者一些简单的类型。
它只适用于一种类型,我想确保你能看到,它实际上没有太多的工作要去从一个只工作在,到真正拥有一个什么都能用的,所以可以说,也许我们应该从那开始,但它只是给代码增加了一层复杂性,所以嗯,好啦,嗯,反正。
下面是一些,你知道的,如果您正在创建T的数组列表,您创建一个新的T数组,你知道代码会有一点变化,但是一旦你习惯了,没那么糟,好啦,所以我要去,那个话题到此结束,但它引导我进入我接下来想说的。
哪个是标准模板库STL,这基本上是一组C++附带的集合,与我们在本课程中使用的斯坦福收藏相反,所以让我们谈谈吧,STL,不要与斯坦福模板库混淆,我们用了很好的缩写,伙计们。
STL是语言附带的一组类和算法,它们很大程度上依赖于我刚刚向你们展示的模板功能,它包含一组集合,他们称之为集装箱,但他们的收藏,这是一回事,它还附带了一套算法,这真的很有趣,我将在几分钟内讨论这个问题。
它还附带了一堆其他的,只是杂七杂八的功能,我马上就给你看,但是它们包含在这个STL中的集合,它有一个一对一的映射到我们在这个类中使用的,所以我想这提出了一个问题,为什么我们要费心重新发明轮子。
重写所有这些东西,我要给你们看一些例子,你可以在讲座结束时决定,不管你是否同意我们的决定,好啦,所以这是一张喜欢的桌子,我们在左边的课上所做的,在真正的语言中,真正的是什么,在右边,所以对于初学者来说。
您可能会注意到,所有类的名称都是小写的,我不知道他们为什么那样做,我想很多东西都是用C++和小写字母命名的,尤其是作为标准库的一部分,like string是小写的s,所以他们有,你知道地图。
他们有一套,它们的向量是小写的v,他们有堆栈和队列,它们的优先级队列带有下划线,他们有哈希图和哈希集,称为无序映射和无序集合,因为它们杂乱无章,因为散列,你知道的,所以你知道。
这些东西大多映射到真正图书馆中的东西,少了几个,就像他们没有字典一样,词汇是一种特殊的结构,只用于某些类型,在某些情况下,所以他们不包括他们没有图的类,我可能在我们讨论图的时候提到过。
很多时候你实际上没有一个图形对象,你只有一张地图,它基本上意味着这是一个邻接列表,什么的,或者你得到一个2D数组,它基本上是一个邻接矩阵,我们说过的内部陈述之一,所以他们没有图库,是啊,是啊。
那是他们内置的一组库,我马上向你展示一下它们是如何使用的,下面是一个具体的例子,实际向量和我们的向量的比较,下面是适当方法的名称,所以你知道,在我们的向量中,有一个大写,B,呃,如果要在末尾添加元素。
你说就在那里推回,我不知道他们为什么叫它推回,但我想这和,就像,推是加弹是除,我们学习堆栈的术语,所以他们决定喜欢,在所有线性集合中使用该术语,我认为这是个糟糕的选择,但不管是什么。
我认为命名委员会应该给这个想法多一点,抵制,清晰是一样的,如果你想从向量中得到元素,你说,获取或使用括号,他们没有得到的方法,但他们有应用程序的方法,基本上就是得到,但是你还是可以用括号。
所以这部分没问题,嗯,其他一些方法有点奇怪,就像插入在适当的地方被调用,比如这是谁的主意,我知道这就像你得谷歌,那个地方,什么,反正就是叫他,你知道,就像方法上的小命名差异,区别不止于此,我有一些星号。
那个,我想马上谈谈其中的一些,但你知道没那么糟,对呀,只是为同样的东西学了一个不同的名字到目前为止还不错,我一会儿要讲的一件事是,嗯,其中一些方法不仅仅是名称不同,他们想要的参数是不同的。
特别是很多方法,我们希望通过索引,想在那个指数上做点什么,比如在给定的索引点插入一些东西,STL而不是要求您传递索引,它要求您传递另一个叫做迭代器的东西,我一会儿就谈这个,下面是一个代码的快速示例。
这是使用斯坦福,我们做对的那个,这是我们的矢量,我们做一个矢量,我们加5寸,我们插入索引零,我们正在进入索引,两个右,那是那是,你知道,第二周我们已经做了,这是真的,好像是这样。
所以当你声明的时候小写v,你注意到图书馆,当包含库,它有括号而不是引号,这意味着系统库,而不是本地图书馆,小写d向量,而不是你怎么说,向后推,这还不错,这很奇怪,在向量的开头插入四二,对呀。
我以前在这里说的是零,在这里插入索引,我说在开头插入,然后如果我想删除索引2中的元素,我说一开始就删除元素,加二开始,只是一个返回零的方法,就像这里是怎么回事,否,它是,我会说的,但这有点奇怪,对吧。
我们会习惯的,但这有点奇怪,这是地图,我会回来的,一分钟后开始工作,但这里有一张地图,这是我们的斯坦福地图,对呀,我们已经学过的那个,你画一张地图,你在里面放了些东西,您可以在文件上循环并将内容添加到。
你知道的,一张地图,你可以问地图是否包含一些非常标准的东西,这是真正的地图,所以你包括,你知道,系统标头,你用小写声明,然后这边也是一样的,输入数据没问题,这样很好,去把东西拿出来,但看看这个。
就像问你看不见的东西,侧面太低了,但要问在地图上是否发现了什么,没有包含键方法,有一个很好的方法,但它不返回布尔值,如果你想找到它,它不在地图的尽头,然后它就在那里,就像。
这就是你问某物是否被包含的方式,所以这很奇怪,所以,我的意思是,它就像它的大部分罚款,但后来发生了一些奇怪的事情,这有点像所有STL的工作方式,基本上你看到它的最初几次,我要谈谈这个开始。
最后的东西在一秒钟内,所以开始和结束是所谓迭代器的例子,迭代器是在集合中存储位置的对象,我的想法是,你知道你可能会在元素中循环并打印所有的元素,或者检查他们,或者修改它们,或者你可以通过做一个。
在向量或其他东西的索引上循环,但有些集合没有索引,那么我喜欢如何在集合上循环,有些语言或库有这个概念,称为迭代器,你说给我一个迭代器,它是一个小物体,帮助你走过收藏,看看所有的元素,你可以说嘿,迭代器。
给我一个集合中的元素,然后移动到下一个元素,然后再给我一个,它可以处理类似的事情,我如何在这个集合中走动,看看所有的元素并把它们给你,这就是迭代器的作用,在向量的情况下,迭代器很容易理解。
它只是一个小对象,排序你是什么索引,如果你说给我下一个元素,它会抓住它然后还给你,如果你说进入下一个元素,它的指数会是正的,所以这很容易理解,但可能很难理解你为什么想要,因为你可以自己做。
你不需要一个物体来帮助你做到这一点,我想也许一个更好的例子是像一套什么的,秩序混乱,我也不太清楚,它没有索引,所以如果我想把元素弄出来,不知何故,它有办法四处走动,让他们,所以我只说给我一个元素。
它会从,如果我说去下一个,它会走到房子里,然而,它需要这样做,它会走到集合中的下一个元素,所以再一次,对象,帮助您遍历集合的元素,所以STL大量使用这些东西作为其设计的一部分。
所以如果你想循环一个向量的元素,如果需要,您可以使用从零到大小的索引,但是你也可以说给我一个迭代器,等于向量循环的开始,直到i到达向量的结束,和一个加号加号,这个迭代器。
Plus Plus是在迭代器类中重载的运算符,将其移动到向量的下一个元素,所以你基本上可以写一个遍历向量的,把所有的元素都打印出来,我认为用矢量看起来是一件愚蠢的事情,因为你刚才说做一个for循环。
从int,i,0到大小,那是更聪明的办法,对我来说更有意义,但这个确切的循环将适用于STL中的任何类型的集合,只不过你会把它从b变成一个集合或一张地图,不管你明白什么,所以一个从开始到结束的模式。
图书馆里的每个藏书都知道怎么做,使用迭代器,好啦,所以实际上每当你为每个循环做一个,暗地里编译器真正在做的是,它在做一个迭代器,然后查看每个元素,这就是当你为每个循环做这件事时真正发生的事情。
所以关于迭代器的这些东西是使用stl的核心,你不能就这样不用它,因为很多不同的方法,所以我们不喜欢那样,你们必须在第一周或第二周处理这个问题,所以这就是我们想要回避的原因之一,你知道这是个奇怪的概念。
你可以掌握诀窍,但需要一分钟才能弄清楚,所以这就是我们避开STL的原因之一,在我们的课程问题中,是啊,是啊,斯坦福图书馆也,所以实际上我们的图书馆,我们的载体,我们的布景,我们的地图。
我们所有的集合类都有这些迭代器,如果你叫点开始,它给你一个迭代器,如果你叫点尾,它在集合的末尾为您提供了一个迭代器,但我们不强迫你方法都在那里,不需要使用它们,所以基本上就像你说的。
就像你不必知道他们是否在那里,所以我的意思是我们有点希望STL有同样的设计,但他们不在后面,是啊,是啊,那么指数如何更好,它基本上就像一个基于数字的迭代器,对呀,是啊,是啊,是啊,是啊,这怎么比索引好。
这不是,我承认这样也好不到哪里去,如果i等于零循环更容易理解,这样更有道理,你不需要这个,我给你看的原因,这个例子是,如果你用一组s代替向量v,你可以有完全相同的循环,但你可以说嗨点和s点结束。
完全相同的代码会在布景中遍历,所以说,迭代器是与所有元素交互的统一方式,按收藏顺序,不管里面是什么藏品,不管是数组还是链表,哈希表或二叉树,迭代器会遍历它,并给你元素,所以你可以看着他们。
所以它应该是一个统一的界面,您可以使用它与每个集合的元素交互,在循环中或在序列中,所以创建者或者你有主索引,罚款,他们本可以,是啊,是啊,但使用这个的原因是,因为这个迭代器对象可以在他体内存储状态。
所以如果他在某个二叉树里面,他可能需要在不同的节点上行走,所以他可能需要喜欢,记住他在哪个节点什么的,如果它只是一个int,我不能喜欢,将该信息存储在int中,你知道我的意思。
所以这个对象可能只是存储它,他可能只是一个包裹,让一些人记住他在哪里,但他可能储存了无连接的石头,二叉树注释,绘制他在周围行走的顶点图,他喜欢帮忙记录他需要记录的东西,遍历完全广义的数据结构,是啊。
是啊,是啊,是啊,和喜欢,我会说喜欢,我已经承认了,这个向量上的循环在一分钟内有点傻,我来告诉你这些小家伙在哪里可以为你做一些强大的事情,我想现在我只是想解释它们是什么,我认为动力仍然有点缺乏。
因为你就像,你为什么不用它呢?我给了我几张幻灯片我想我可以让它更有动力,是啊,是啊,事实上,只要你能,您可以访问,就像,对着中间的藏品说,你不应该去那里,如果你能进入,哦耶,这是否破坏了类似的封装。
我可以走到队伍中间吗,是啊,是啊,所以你可以做的一件事是,您可以使迭代器不受支持,如果您不想让用户访问这些,就像在堆栈上,我只想让他们摸上面的元素,不是其余的,所以也许我不会在堆栈上提供迭代器。
那将是我可以做出的设计选择,或者我会说是的,如果我真的提供了,你不应该那样用它跳到队列中间,或者堆栈的中间和变化,那里有什么,你知道的是的,你必须,您必须决定您希望允许用户做什么。
基本上我不喜欢他们的图书馆,如果图书馆在那里,你想写代码来做到这一点,它会让你这么做的,我是说有些图书馆设计师想阻止你做一些,他们中的一些人想让你决定,但你得负责任,你知道权力越大责任越大,对呀。
差不多吧,蜘蛛侠系列,嗯,我再给你看一点,你能用这些东西做什么,因为我想现在就像这样,就像一个垃圾循环,这有什么意义,我再给它一点动力,所以在这里,让我在这里等着,有一个标题叫做算法,如果包含算法。
你突然得到了所有这些坏函数,你可以调用,其中一些相当简单,就像,啊,你知道的,排序还是洗牌还是好的,不管怎样,这里有一大堆很酷的东西,你可以把这些叫做,这些只是存在的全局函数,现在你可以打电话给他们了。
你可以给他们任何收藏,它会对收藏品造成这样的影响,它会整理藏品,它会洗牌收藏,它会搜索收藏,它会逆转收藏,不管这些不同的东西,其中一些不是微不足道的,但就像你知道的,计算给定元素的所有出现次数。
数数所有发生的事情,如果下面的谓词为真,你知道的,已排序的集合是什么,这些都是您可能认为是集合类中的方法的操作,就像嘿,矢量点,整理一下自己什么的,但他们所做的却是,他们把它们写成一种全局函数。
并且将集合作为参数传递,这意味着任何集合都可以通过,即使你写了一个合集,它将与这些图书馆一起工作,这些方法的一个有趣之处在于,这些函数是不传递向量或哈希映射,您传递一个迭代器,如果你给它一个迭代器。
它将遍历集合的元素,然后做函数承诺做的任何事情,所以这真的很酷,因为如果您编写自己的集合,其中包含迭代器,您可以在集合上调用这些方法,也是,因此,我们的斯坦福收藏采用了这些方法。
下面是调用这些方法的几个快速示例,如果要对向量排序,你不是说B类吧,你说从向量的开始到结束排序,所以你所做的是,你真的像指针一样传球,基本上是指向开始和指向结束的指针,你说的一切都在这个范围内。
我想把它分类,它会的,但你可以对任何其他类型的收藏做同样的事情,它也会解决这个问题,你也可以做一些很奇怪的事情,就像我想对这个向量的后半部分排序,你可以说排序开始加大小超过两个逗号结束。
它将对矢量的一半进行排序,但剩下的就不用管了,真的很酷,不是吗,您只能像向量的范围一样排序,它就会那样,它之所以有效,是因为您可以在迭代器上做加号,在这么多的因素下前进,嗯。
如果你想知道剧组里有多少马蒂家的人,您说它使用集合的开始迭代器和结束迭代器,它需要你想要搜索的元素,这是你的马蒂号码,其实呢,我认为marty的复数是marty,但不管怎样,你找到了你收藏的所有标记。
嗯,你想知道向量中最大的元素,好啦,给你,最大元素,你想,你知道的,从V1复制五个元素,从v1开始到v2,好啦,复制开始加五,你知道它有所有这些真的真的很酷,这些算法的强大使用,事实上。
每年都有这些国际编程比赛,你知道他们在小团队中给学生这些棘手的算法问题,他们必须以最快的速度输入解决方案,尽可能多地解决问题,你们中的一些人以前可能参加过一些编码比赛。
很多时候他们让你从几种不同的语言中挑选,你想不想,Java,你想不想,C加什么加什么,大多数赢得这些东西的团队都用C++代码,不是因为C++是一种好语言,但是因为它有这个,这些都是如此强大的东西。
就像很多常见的问题都可以通过,只是从这个库中抛出一堆函数,然后它就起作用了,所以这是非常非常,STL非常强大,一旦你知道如何使用它,但有一个问题是这样的开始和结束,迭代器的东西到处都是。
所以你只需要喜欢,早点说,也许比我们想要的更早,那很不幸,如果我回去一秒钟,嗯,迭代器的语法是它们的行为有点像指针,它们不是指针,但是如果您想访问迭代器当前所在的元素,您必须写star加上迭代器的名称。
如果你还记得,那是跟踪指针星的操作员,p是指针p指向的值,这使用了重载版本的运算符来表示,去找迭代器指向的元素,所以为了做迭代器,你得理解指针,或者至少是指针附带的运算符,又是这样。
就像如果我们要用这个收藏库,在本课程中,我们不得不谈论星星和与号,再加上好处,减号在指针上,在第二周做一些类似的事情,所以我只是,你知道的,这也是我们不去图书馆的原因之一,在我们班,是啊,是啊。
你想出的这个范例,就像,和大范围算法,有点依赖于,劳动领域的抽象概念,这种范式应用于不同的,我们能用这个做什么,对此非常具体,写一般函数的想法,在任何课程上都有效,是啊,是啊。
它在不同的语言中以不同的方式应用,嗯取决于什么,你知道,它是一种语言,Java一开始并没有这个概念,所以如果你想有一个排序函数,您要么在数组is class中放置一个排序方法。
以及链表类中的排序方法和该类中的排序方法,你知道你必须这么做,或者您必须使用静态方法编写一个类,你知道你必须有一个接口或者一个叫做Collection的超级类,然后所有的收藏都扩展了。
或者你知道你必须这样做,你必须用某种基于继承的诡计来修复它,所以我的意思是,在Java中,你不能总是这样做,还有其他一些语言,比如Ruby语言有一个叫做Mix Ins的概念,有点像多重继承。
你可以说我想要这个功能和这个功能,还有这个和这个我想让你把它们都放在我的班上,现在你把一切都混合在我身上,所以如果你的红宝石混合在,你可以说我想被分类,所以我要把排序混合放在我的课上。
现在我可以做到这一点,我可以给自己打电话,所以不同的语言以不同的方式做到这一点,但我想每一种语言都想要这样的东西,就像我有很多不同的容器、收藏或对象,我希望能够有,他们都支持这个操作。
这在他们之间是相似的,所以他们怎么做取决于语言,是啊嗯,谁听到了我们自己的收藏,很可能给了她一个,如何给自己的集合迭代器,您必须编写一个支持某些操作的小类,像一些运营商,就像一颗星星和一个加号。
我想如果你想谷歌一下,我认为这是最好的学习方法,您必须编写一个支持一些操作的小类,通常在集合类中实现它,就像如果你有一个矢量点h,您正在编写自己的向量类,你会做一个小迭代器,嵌套在向量内部的类。
这样它就可以查看矢量的所有数据,在迭代器类中实现某些特定的操作,然后你必须写向量的方法,称为开始和结束,返回指向数据开始和结束的迭代器,分别,所以如果你好奇,你可以看看一些斯坦福收藏的来源。
因为它们内部有迭代器类,有时候读起来有点难,但我觉得这会让你有一点想法,还有很多教程,比如如何编写C++迭代器类,如果你想谷歌一下,它会显示,所以这是一个一般的想法,虽然,是啊,是啊。
我的幻灯片少了很多,哦为什么是正加,我是说这是一件很微妙的事情,如果你真的发帖,在增加到新值之前,它必须返回旧值,所以从技术上来说,它必须复制迭代器来做到这一点,所以它浪费了少量的内存。
所以如果你做了加号,它立即递增它,而不返回旧值,这只是一个小小的优化,反正,是啊,是啊,还有其他问题吗?是啊,是啊,如果你的排序器不是有序的,像你这样的人,尝试在哈希集上调用sort。
没有排序数据类型的,它不会编译,因为在排序的实现中,它试图说小于和大于,然后你的收藏对象会有一个,所以里面的东西顺序不对,啊,原来如此,我明白了这样元素就可以排序了,但在收藏中。
试图对它们进行分类是没有任何意义的,是啊,是啊,这是个好问题,我其实我不记得它是做什么的,嗯,我很确定它不喜欢打破哈希集,但我不记得了,我认为您可以在迭代器中提供一些特性。
你可以说我想允许这样或那样的操作,而不是那些其他人,我不得不承认,我没有我没有那样做,所以说,我不记得它是做什么的,但我知道它不喜欢打破你的哈希集,你知道我不知道,我想那很好,我应该我应该去看看后讲座。
嗯好吧,反正,那是STL,我想这就是我想说的,所以这是一个很酷的图书馆,它相当强大,就像语言附带的标准,那我们为什么不用它呢,我的意思是我说像,您必须尽早了解指针和指针语法,如果您使用这些迭代器,呃。
一些方法和算法涉及指针,包括指向函数的指针,我们还没讨论过,那令人困惑,还有一件事我没给你看,这是STL的一个缺点,它现在没有非常友好的错误消息,我敢肯定,几乎所有你们去尝试写一些代码。
使用哈希图或向量,你搞砸了,你出界了什么的,你得到了这个非常好的堆栈,跟踪误差超出范围,这里的行号你可以去看看并把它修好,STL在这方面并没有真正帮助你,如果你在向量上出界,它只是超出了记忆的界限。
从那里抓取数据并给你,所以你的程序会继续运行,你会有垃圾数据,你不会知道为什么,所以,STL中的向量和其他类不是为学习者设计的,对于一个学生来说,所以这些是我们不使用它们的一些原因,还有一些课程不见了。
我们想要提供的东西之类的,所以我不知道,我的意思是,我个人,如果你想听我的意见,我可能会选择真正的,如果由我决定,即使这并不理想,只是我们会一起忍受,我们会想出办法的,你知道的。
但这不是我们课程的创作者做出的选择,哦好吧,如果你想改变它,你得重写所有的讲义,所以我对那样做不感兴趣,所以如果你想了解更多关于图书馆的信息,有一些资源你可以,大家可以看一下。
我想你能做到的最简单最快的方法,如果你喜欢,我很想说,我知道真正的,C加加,我想让雇主知道,我真的知道c++fine,好啦,试着用STL重写几道家庭作业题,就像家庭作业二,家庭作业里有很多收藏品要看。
如果您可以使用STL使其工作,不是我们的收藏,也没那么糟,你也许能弄明白,嗯还有,如果你真的想学很多关于真正的C+,我们有,当然啦,我们下个季度报,叫做CS,零六升。
它基本上只是一些真正的C++中的实验室和项目,在那里你只是练习用真正的库做题,如果你想更深入地了解实际的语言,那是一门课,你可以考虑报名参加,所以去看看探索课程,零六升。
我会在广场论坛上发布一则关于零六升的公告,如果你有兴趣,所以这就是,我还想告诉你一件事,这会让你发疯的,我给你看了那只小狗,我把小狗放回屏幕上,如果有必要,但是嗯,让我给你看看让你有点不高兴的特征。
我想这叫做智能指针,就像短版本一样,所有的狗屎都是新的和删除的,并说,就像你真的不用做那些事一样,你在生我的气吗,一切都是谎言,你的一生都是谎言,我很抱歉我现在必须告诉你,就这样,事实上。
我有点喜欢告诉你,但我有点夸张了,让我更详细地解释一下,所以好吧,什么是智能指针,嗯,它基本上是一个释放内存的指针,当你用完后,因为你知道我们在C++中有手动内存管理,当你说新,你得说删除对,那很棘手。
我希望你们现在已经看到,要做到这一点是很难的,你可以有一个指针,指向垃圾,您可以有一个空指针,你可以有记忆,你忘了释放,所以你有内存泄漏,您可能会意外地释放同一内存两次,所以你有崩溃或内存损坏。
这些都是很难解决的概念,你可能会想得很好,我只是在学习它会好起来的,随着年龄的增长,什么是我的懈怠,对不起,别给我发短信了,萨拉,来吧,来吧,所以你可能会认为,嗯,我只是在学习。
如果我在编码方面做得更好,我会想出办法的,但没有,随着年龄的增长,这实际上变得越来越难,因为你正在编写这些非常大的程序和数百万行代码,很难把所有的记忆,刚刚好,所以这不会变得更容易,越来越难了。
所以好吧,所以人们所做的是,他们想出了这个主意,称为智能指针,智能指针是一个小容器,您可以将指针放入其中,指针指向堆上的某个对象,智能指针指向热源上的东西,但是智能指针本身存储在堆栈上。
智能指针有析构函数,所以当它到达范围的尽头时,就像它的功能一样,它,释放它所持有的指针,所以它为您管理指针的生命周期,当你不再需要的时候帮你冷冻,这个概念最初并不是语言的一部分,然后发生的事情是。
一些聪明人想出了图书馆来实现这个概念,他们认为这是一个非常聪明的想法,他们在2011年把它添加到语言中,最初有一个非常好的库,叫做Boost,可以帮助您做到这一点,但现在你不再需要助推器了,好啦。
所以现在内置到语言中,有一个头,您可以包括调用的内存,我有一些早晨我希望我能做到这一点,为什么又是那个好听的名字,包括内存,哦耶,完成了,好啦,有四种类型的东西,我主要想说的是,这个叫做唯一指针。
但还有一些其他的,所以我们想讨论的概念是,你可以申报这些集装箱的家伙,他们可以拥有一个指针,他们能应付的,他们会帮你处理的,他们会给你免费的,当它这样做,关于谁拥有指针的想法,谁的工作是解放它。
这就是我们要担心的事情,好啦,所以有一个叫做唯一指针的类,您可以制作唯一的指针,然后你提供一个模板,说明什么类型的东西,它会指向,所以它将指向一个int星或一个列表节点星,你会在这里写上你的列表节点。
然后给唯一的指针变量起一个名字,然后在圆括号中写出它应该指向的值,所以您可能会看到一个新的迭代器或一个新的列表节点,或者类似的东西,好啦,所以你基本上说嘿,唯一指针,你要管理我现在分配的内存。
一旦你创造了那个东西,你可以用它,就好像它是它拿着的东西一样,所以你可以把这个叫做p,你可以参考P,就像提到这个东西,因为p就像一个很薄的包装纸,但是当唯一指针到达关闭的花括号时,它会释放这个东西。
所以让我给你看看,我觉得这样更容易理解,举一个例子,这里有一个普通的指针,这不是特殊的智能指针,这是一个愚蠢的指针,你有一个功能食物,这就像我只是需要某种类型的指针,所以我做了一些链接列表,虽然如此。
名单没有,我列了一张新的清单,你们不要记得这些东西,我可以设置数据,接下来不管怎么样,我有一个指针,记住内存,就像堆栈是一个指针一样,p实际的小指针本身,但它指出的是这个被加热的物体。
我们对这些东西记得很清楚,当然稍后,如果我用它,如果i,如果我说p等于一个新的列表,我在堆中做另一个节点,我忘了以前那个,我失去了重点,所以我实际上在这里有内存泄漏来理解,因为没人再指着他了。
但现在他指着另一个人,这样我就可以设置一些新的数据,最终当它到达另一个函数时,我应该释放这两个节点,对呀,每次你说新,那是一个稍后必须删除的对象,没有人这样做,哎呀,我有两个列表注释泄露了,好啦。
那么智能指针是什么样子的呢,看起来更像这样,创建指向以下列表的唯一指针,我叫它P,你不说P吗,它就像一个构造函数,你传递这个东西,并指向,所以p将管理一个新的列表节点,但是你看,真的很酷,我可以使用p。
就像我使用列表节点指针本身一样,这不是很奇怪吗,你觉得我怎么能做到,它怎么会有这样神奇的语法,我根本不用改变语法,运算符重载唯一指针类型,如果你在上面用箭头,它编写了一个运算符箭头重载。
基本上返回底层指针,当您使用该运算符时,所以你可以用这个唯一的指针,就像它是列表节点指针一样,所以我可以设置下一个数据集做任何事情,我想以后再做,如果我决定,你知道的,我真的不想指着这张纸条。
我想指出一个不同的音符,你可以说嘿皮特重置你自己,用另一个新音符,释放原始节点,但现在存储第二个不同的值,所以现在我没有内存泄漏,现在我用另一个值,然后当我到达函数的底部时。
记住记忆是如何工作的这个函数,它的内存在堆栈右边,这个唯一的指针p在堆栈上,这是一个局部变量,它指向一个列表节点,那是在堆上,但是当这个唯一的指针击中,关闭卷曲制动器,它扔掉了唯一的点。
唯一指针类具有析构函数,析构函数被调用,当我踩刹车的时候,析构函数所做的是免费的,所以记忆会被释放,当你到达函数的末尾,很酷吧,就像我不用,再次删除,你疯了吗,我让你处理了这么多废话,你不需要。
我是说在某些情况下你不需要,我是说我想让你们受苦,我是说我就是喜欢那样,我只是很享受,但是学习如何管理记忆对你也有好处,但很好的是,这可以避免有时不得不这样做,是啊,是啊,如果你想说,是啊,是啊。
我有一张幻灯片和几张幻灯片,我将讨论返回和参数,因为我认为这是很重要的用例,如果我想做一个指向某物的指针,然后把它转出来呢,它会调用析构函数并摧毁它吗,我想回去,简短的回答是,一定有办法的。
我马上就教你怎么做,是的在这一点上有什么不同,是啊,是啊,比如为什么我不说列表节点p而没有指针,不同的是,如果您只是在堆栈上做一个列表注释,节点本身,节点的寿命将无法超过此函数,但这件事是可能的。
我马上给你看,也喜欢,在堆栈上拥有内存和在堆上拥有内存是有区别的,它们有不同的大小和可以存储的不同范围的内存,所以是的,我觉得这些问题,所以也许让我给你看更多,我觉得这样更合理,所以其他几个方法。
很快就好,如果你做了一个指向某物的指针,您可以要求它真正指出的原始指针,你可以说get,这样你就可以说出真正的重点,如果你真的想要真正的指针,你可以得到它,或者你可以去释放,它给出了原始指针。
但是唯一的指针,让我们去停止拥有他,所以我保证我不会再放走他了,所以如果你想突破唯一指针,你可以可能,我还没有给出一个用例来说明为什么要这样做,但不管怎样,所以还有更多的方法。
那么让我们来谈谈参数和返回,关于你们的问题,如果尝试将唯一指针作为参数传递,它真的不起作用,但你在这里做一个,你试着通过它,这不管用,因为它会试着复制然后删除副本,然后它不希望通过参数传递来释放节点。
你明白吗,这样做不太好,因为唯一指针类中的构造函数析构函数,所以不管怎样,不能将一个唯一指针分配给另一个,因为这意味着他们都试图拥有同一个列表节点,然后当他们都掉出范围时,它会加倍释放它。
所以它不会那样做,它不让你这么做,就像我说的,这不会编译,有一些方法可以绕过它,比如,如果你想通过这个考试,你能做什么,但它不让你这样做,有什么想法吗,你可以把它释放出来,把生的东西传递出去。
那就很好了,有没有办法,也许我可以把它留在独特的指针地想法中,您可以传递指向该点的指针,啊,那是恶魔,我喜欢它,呃,不如写个推荐信,可以传递对唯一指针的引用,但你可以这么做,嗯所以,但你能做的。
你不能把它作为参数传递,但你可以退货,哦等等,呃好吧,所以有几种方法可以做到这一点,你可以说移动,把所有权转移给了他,他的所有权概念,是啊,是啊,我放手,他可以拥有它,所以你可以转给他,但他会释放它。
当他做完,您还可以返回唯一指针,这就是在你的函数中,你可能会做一个,然后你把它还回去,你问这个问题,就像,这难道不意味着,就像它击中卷曲,它会释放它,但是C++有这个想法,叫一招,语义复制什么的。
如果它看到你回到即将死去的东西,您将把它存储在相同类型的对象中,它就像把它移过来,它不会破坏它,这在一定程度上是一种优化,但它在一定程度上使这一切奏效,所以我想要一个帮助函数,生成一个链表并返回。
我能做到,也不会,它不会破坏,所以无论如何,我想我没时间了,所以我得停在这里,但这很酷,我是说它避免了很多我们必须处理内存管理的地方,所以我向你道歉,我让你受尽折磨,但是当你真正写软件的时候。
您经常希望使用这样的库来避免内存问题,并不能避免所有的记忆问题,但这很有帮助我们需要所有的帮助,我们会没事的,嗯,今天就到这里,我们星期五要上课,我要总结一下,帮你一些学习技巧,在网站上的最后查看。
如果你想看一些练习,考试问题,祝你学习和家庭作业顺利。
星期五见。