茹庄网yqp9算法(英语:algorithm),在数学(算学)和电脑科学之中,指一个被定义好的、计算机可施行其指示的有限步骤或次序,常用于计算、数据处理(英语:Data processing)和自动推理。算法是有效方法(英语:Effective method),包含一系列定义清晰的指令,并可于有限的时间及空间内清楚的表述出来。算法中的指令描述的是一个计算,它执行(英语:Execution (computing))时从一个初始状态和初始输入(可能为空)开始,经过一系列有限而清晰定义的状态最终产生输出并停止于一个终态。一个状态到另一个状态的转移不一定是确定的。包括随机化算法在内的一些算法,都包含了一些随机输入。早在尝试解决希尔伯特提出的判定问题时,算法的不完整概念已经初步定型;在其后的正式化阶段中人们尝试去定义“有效可计算性(英语:Effective calculability)”或者“有效方法(英语:Effective method) ”。这些尝试包括库尔特·哥德尔、雅克·埃尔布朗和斯蒂芬·科尔·克莱尼分别于1930年、1934年和1935年提出的递归函数,阿隆佐·邱奇于1936年提出的λ演算,1936年埃米尔·莱昂·珀斯特(英语:Emil Leon Post)的Formulation 1和艾伦·图灵1937年提出的图灵机。即使在当下,依然常有符合直觉的想法难以定义为形式化算法的情况。
我不明白为什么人们在这个问题上胡说八道。是的,数组比链表更普遍。没有问题; 差远了。问题不是“数组是否用于排除其他一切,包括链接的树结构和图形结构”,而是:“数组是否比链表更普遍”。当我们说数组时,它还必须包括向量之类的东西,因为向量是一个数组,只是可以调整大小。如果它被实现为一个数组,那么它就是一个数组。例如,字符串在所有主流语言中都被实现为数组(Haskell 除外,它是“证明规则的例外”。)。链表只是一个列表,但是有链接。它不是树,也不是图。它是一个连续值的列表——这正是数组的本质,除了:链表不是随机访问的(数组是)。链表是指针丰富的,因此缓存不友好(数组不是)。在这里,我将借用Project Valhalla中的一段话这解释了我所说的富含指针的意思:在 20 世纪 90 年代初期设计 Java 虚拟机时,内存获取的成本在数量级上与加法等计算操作相当。借助当今 CPU 的多级内存缓存和指令级并行性,一次缓存未命中可能会花费多达 1000 个算术问题槽——相对成本大幅增加。因此,JVM 青睐的指针丰富的布局涉及小数据岛之间的许多间接,不再是当今硬件的理想匹配。我们的目标是通过为 Java 开发人员提供更简单的平面(高速缓存高效)和密集(内存高效)数据布局而不影响抽象或类型安全性的途径,使数据布局更适合当今硬件的性能模型。“小数据岛之间存在许多间接关系。” 这准确地描述了一个链表。“平而密”恰恰描述了一个数组。链表是 SO 1987。
冒泡排序和数组排序有什么区别?为什么我们需要使用冒泡排序而不是数组排序?冒泡排序的优点和缺点是什么?
据我所知,冒泡排序仅用于教授将事物排序的想法。它的工作原理很容易理解——交换成对的东西。它通常不是最好的使用方式。与以往一样,这取决于您希望数据以何种顺序进入。在专业上,我们倾向于在很多时候对“别人的问题”进行分类。我们将其推送到数据库引擎或库调用中。许多设计不需要对数据进行排序,它只是对其作出反应,因此不存在排序。
因为它遵循 C 和其他语言设置的先例,其中数组索引是从数组开始的内存偏移量。假设您在地址 A 处有一个长整型数组(4 个字节)。元素的地址是起始地址加上元素大小乘以索引。所以在我们的示例中,元素 0 位于 A + (4*0)。元素 1 在 A + (4*1) 处。元素 2 在 A + (4*2) 处。等等。像这样的简单指针数学运算非常快,因此通过索引访问数组几乎没有开销。
你会怎么做呢?选择一个小数组,5x5 足够大,然后想办法用手算出来。你会跟踪什么?你怎么知道要打印哪个数字?有很多编程问题很简单(或者很难,这取决于您的观点)。简单地手写一个例子是解决它们的第一步。事实上,如果我面试的是实习生,而他在实习前只上过一门编程课程,我会给出一个难度级别的问题。而且,如果他们在尝试写出任何代码之前手写了一个例子,我可能会考虑雇用他们,即使他们没有得到一个工作程序。这将表明他们知道如何解决此类问题。大多数编程中大约 90% 只是知道如何从逻辑上解决问题,例如,制作示例并手动制定解决方案,并以可以将您的手动操作转化为代码的方式进行。我雇用过的最好的实习生会处理正则表达式问题。很多人不能正确地编写正则表达式,但她会采取一些我们想要优化的案例,并开始在白板上绘制一个代表问题案例的示例表达式。当她完成时,我们确切地知道我们想要实现什么。大多数时候,我们甚至还知道极端情况和棘手的部分。
…这很复杂。你的编程教授会告诉你,是的,这正是发生的事情。每次迭代后都会调用析构函数,因此您的循环会为对象分配和释放内存,对吗?简单吧?好的,事情就是这样。编译器真的非常非常擅长优化。整个博士 这些论文来自编译器优化。根据您使用的编译器、您设置的标志以及它的优化程度,您可能会惊讶地查看目标代码并发现,不,实际上,编译器已经发现您在做什么并且实际上并没有删除循环中每次旅行时来自内存的向量。您不能总是依赖编译器目标代码完全按照您的想法行事。我的意思是,该死,你可能会编写尾递归只是为了让编译器对你不屑一顾,并将你的递归展开到一个循环中。编译器通常比开发人员更聪明。
它们不是同一件事,但在某些情况下可能会作为同一件事实现。数组基本上是代表多个元素的连续内存块。通常这些元素会被认为是相同的类型,但严格来说它们是相同的size ,不一定是相同的类型。列表是一个更抽象的概念,它并不规定它必须在连续的内存中,或者元素的大小或类型相同,但通常它们是。以 Java ArrayList 为例。这是一个用数组实现的列表。“数组”是关于如何存储多个元素的更严格的概念。“列表”更多的是列表的概念,对于如何存储元素没有真正严格的想法。
为什么插入数组的开头需要 O(n)?计算机不能使用数组首地址之前的地址吗?
这 ( )在数组前面插入的成本基于一组假设。该数组在内存中具有固定的大小和位置。该数组连续存储在内存中。数组的最低有效索引对应于该连续内存范围的最低地址。在位置 N 处向数组中插入一个元素会将位置 N 及之后的元素向上移动,并丢弃索引最高的元素。如果你放宽或修改这些假设,你可以有 ( 1 )在两端插入,同时仍保持 ( 1 )随机访问。有关实际示例,请参阅 C++ 。std::deque,现在,std::deque放宽所有这些限制。特别是,放宽 #2 会在每次查找时增加一个固定的惩罚。如果你想连续保存数据以便更快地查找,你可以设想制作一种std::vector在两端保留备用存储的变体。那将提供摊销 ( 1 )在前面和后面插入,并减少其开销 ( 1 )索引。所以,这一切都取决于你的假设。
|