大家好,关于深入解析:二分查找与快速排序算法原理与应用很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!
二分查找的基本思想:每次将要查找的序列切成两半,这样最多需要次才能切完整个序列。我们说算法的复杂度是。
注:的复杂度指的是。
注意:二分查找仅在列表是有序列表时才有效。
二分查找算法的代码表示:
def binary_search(nums, 目标):
lo, hi=0, len(nums)-1
而lo=hi:
mid=(lo + hi) //2 # 必须四舍五入,否则数组的索引会错误
如果nums[mid]==target:
中途返回
if nums[mid] target:
# 这里加1,后面减1是为了防止lo和hi卡在某些数字上(比如lo=5,hi=6)
低=中+1
否则:
高=中-1
return None 算法时间复杂度中的“线性时间”意思是:算法的运行时间与序列的长度相同。顺序越长,运行时间就会越长。其时间复杂度表示为。
二分查找的运行时间是对数时间(时间)。其时间复杂度表示为。
计算算法时间复杂度的目的是为了知道算法的运行时间增加多快,即当序列长度增加时算法的运行时间增加多快。例如,当序列长度从较小的值变为较大的值时,线性时间复杂度的额外运行时间增加非常多,而对数时间复杂度的额外增加很小(几乎不受序列长度的影响) ),序列长度越长,差异越大。因此,时间复杂度对于解决实际问题起着非常重要的作用。
大的表示法指出了算法需要执行的操作数(可以理解为“操作”)。它指出算法运行时间的增加。它实际上计算的是操作次数。 (算法的速度不是指时间,而是指操作数增加的速率。当谈论算法的速度时,我们谈论的是随着输入的增加,其运行时间增加的速度。)
大的表示法实际上是指向最坏情况的运行时间,它指定了算法运行时间的上限(例如假设一个算法的运行时间为,此时我们说该算法的运行时间不可能超过)。
五种常见的时间复杂度:
时间复杂度运行时间示例快速二分查找快速简单查找慢速快速排序慢速选择排序非常慢旅行商问题常见大O 运行时间图如图所示。 1 显示:
图1:常见的Big O 运行时间
排序算法的重要性(或者说我们为什么要学习排序?为什么有这么多排序算法?):因为很多算法只有在数据已经排序之后才起作用(比如二分查找)。
计算机内存是如何工作的:(计算机就像是许多抽屉的集合,每个抽屉都有一个地址。)当我们需要将数据存储到内存中时,我们要求计算机提供存储空间,然后计算机给我们一个地址。当需要存储多项数据时,有两种基本方式:数组和链表。
数组中的元素在内存中相连。数组的这个特性是导致数组在添加新元素时处理速度慢的根本原因:如果数组原地址对应的内存后面没有多余的内存可供添加新元素,那么计算机就会为数组分配一个新元素。地址以保证所有元素在内存中能够紧密相连。这时,数组中原来的所有元素都会被移动到这个新地址。同理,如果向数组中添加新元素,如果原来的内存不够,就会分配新的地址,并将原来的所有元素移动……因此,当动态添加新元素时数组,内存将会丢失。造成严重影响速度。解决这个问题的一种方法是提前为数组分配足够的内存。但这种方法有一个缺点:它不知道要提前分配多少内存。如果分配太多,就会导致内存浪费。如果分配太少,则必须重新分配地址。
彻底解决这个问题的一种方法是链表。链表中的元素可以存储在内存中的任何位置:链表的每个元素存储下一个元素的地址,从而使一系列随机内存地址串在一起。向链表添加新元素很容易:只需将其放入内存并修改其前面的元素指向的地址即可。
数组和链表的优点是互补的:链表的优点在于插入元素(插入新元素的时候非常方便),但是在链表中查找就很不方便(当我们要在链表中查找元素时,我们如果无法直接找到元素的位置,只能从链表的头节点开始,依次访问下一个节点,直到找到要找的元素,所以链表中的查找就会是相当耗时);相反,数组的优点是查找元素(可以快速找到数组的任意元素),但缺点是插入元素速度较慢。
当需要在中间插入元素时,链表是更好的选择。当你需要删除元素时,链表也是一个更好的选择,因为你只需要修改前一个元素指向的地址。使用数组时,删除一个元素后,所有后续元素都必须向前移动。
链表只支持顺序访问(即从第一个元素开始逐个读取元素),而数组同时支持顺序访问和随机访问,因此可以更快地读取数组。实际情况大多需要随机访问,因此大量使用数组。
数组和链表操作的运行时间如下:
操作数组链表插入读取删除选择排序算法:
算法名称选择排序算法目的排序算法描述首先遍历列表,找到元素的最大值,然后将其添加到新列表中;然后再次遍历剩余的链表,找到该元素的第二大值,按排序顺序添加到新链表中;直到所有元素都排列成新的序列。每次遍历的时间复杂度为:、、…、,总共需要遍历次,所以总体时间复杂度为:使用的优点递归的好处是它可以让程序更容易理解;使用循环的好处是程序的性能可能会更高。
每个递归函数都有两部分:递归基和递归条件。递归基数是指函数不再调用自身的时间,递归条件是指函数何时调用自身的时间。每个递归函数都必须有递归基,否则会形成无限循环。
堆栈弹出引用删除并读取。
栈的基本操作:入栈(向栈顶添加新元素)和出栈(删除并读取栈顶元素)。
每当程序调用函数时,计算机都会为该函数调用分配一块内存,该函数调用涉及到的所有变量的键和值也会存储在该内存中;如果这个函数中有新的函数被调用,那么之前的函数就会成为栈底,然后新的函数就会被压入栈顶,并且涉及到的变量的键和值新函数将被保存在栈顶;如果调用了另一个嵌套函数,则重复此过程;当栈顶的函数执行完毕后,计算机会将其从栈顶弹出(读和删除)(每次返回相当于一次弹出操作),然后之前的函数就变成了新的函数。执行完后会从栈顶弹出栈顶;直到堆栈出空,所有函数都会被执行,程序将返回最终结果。
堆栈的缺点:存储详细信息会占用大量内存。每个函数调用都会占用一定的内存。如果堆栈很高,则意味着计算机存储了大量的函数调用信息。此时,可以考虑用循环代替递归,或者使用尾递归(但并不是所有语言都支持尾递归)。
分而治之是一种通用的问题解决方法,属于递归式问题解决方法的一部分。当遇到问题不知所措时,可以考虑分而治之。
使用分治法解决问题的过程包括两个步骤:
(1)求递归基,递归基必须尽可能简单;
(2)继续分解(或缩小)问题,直到满足递归基的要求。
分治策略的关键是如何缩小问题的规模。
分而治之实际上并不是一种解决问题的算法,而是一种解决问题的思路。
快速排序使用分而治之的策略。
将列表A 添加到空列表仍会生成列表A:
[1, 2, 3] + [ ]=[1, 2, 3] 快速排序的代码如下:
def 快速排序(nums):
iflen(数字) 2:
return nums # 这是递归基数:空数组或单元素数组是有序的
否则:
ivot=nums[0] # 从nums中取出一个元素作为比较的基础
# 接下来,将原数组分成两部分,一部分比pivot小,另一部分比pivot大。
# 更小和更大至少是空列表
较小=[i 代表nums[1:] 中的i,如果i=枢轴]
更大=[i for i in nums[1:] if i hub]
return fastsort(smaller) + [pivot] + fastsort(bigger) 快速排序是最快的排序算法之一,平均时间复杂度为,但在最坏情况下,其时间复杂度与选择排序相同,均为。
快速排序的性能在很大程度上取决于每个选择的主值。最好的情况下,快速排序的时间复杂度是。当每个选定的参考值都可以将剩余数组分成两等份时,就会发生这种情况,这样只需要次即可划分整个数组。完全的;而每次排序操作需要,所以此时的时间复杂度为;而在最坏的情况下,快速排序的时间复杂度会达到,这种情况每次选择的基值都是剩余数组的最小值或最大值,这样每次只能减少数组的一个元素时间。这样一来,需要n次才能将整个数组的长度减为0,非常耗时,而且每次排序的时间复杂度为,所以本例的总体时间复杂度为010- 69536。图2-1 和图2-2 给出了该解释的两个非常形象的说明。
图2-1:最坏情况时间复杂度:
图2-2:最佳情况时间复杂度:
词典创建、添加和阅读:
#创建字典(以下两种方法是等价的)
书=字典()
书={}
#添加键值对
书["牛奶"]=1.49
书["香蕉"]=2.37
# 在字典中查找内容
# 字典搜索时间为O(1)时间
打印(书["香蕉"])
# 使用get方法获取字典内容
re=book.get("milk") # get中传入的是key,是一个字符串类型值字典。一种应用案例是缓存。缓存是一种常见的加速方法,所有大型网站都使用缓存,缓存的数据存储在哈希表中。当需要从缓存中提取内容时,需要将页面的URL 映射到页面数据。服务器缓存的代码示例如下所示:
缓存={}
def get_page(url):
if cache.get(url): # 我们这里使用get而不是直接使用cache[url],因为我们不确定缓存中是否有url。
return cache[url] # 返回缓存数据
否则:
data=get_data_from_server(url) # 如果缓存中没有该url,则让服务器生成该url对应的页面。
cache[url]=data # 将服务器生成的内容保存到缓存中,以便后续不需要重复搜索。
返回数据字典的内部工作机制:
哈希函数负责将不同key对应的值映射到不同的位置。但是,如果不同key对应的值映射到同一个位置,就会发生冲突。
解决冲突的一种方法是在冲突位置存储链表。但这里的问题是:这些存储的链表不能太长,否则字典的速度会急剧下降。因此,这对哈希函数提出了很高的要求:哈希函数必须尽可能地将键均匀地映射到字典中的不同位置,即尽量避免冲突。
平均而言,字典执行各种操作需要秒。被称为恒定时间,但恒定时间并不意味着立即,而是意味着无论哈希表有多大,所需的时间都是相同的。
好了,关于深入解析:二分查找与快速排序算法原理与应用和的问题到这里结束啦,希望可以解决您的问题哈!
【深入解析:二分查找与快速排序算法原理与应用】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
想学算法?这篇文章挺不错的,听说二分查找和快速排序都是基础的
有8位网友表示赞同!
我对快速排序不太了解,这个系列的文章能详细介绍吗?
有9位网友表示赞同!
每次看到 "图解" 就感觉学习起来会更轻松!
有19位网友表示赞同!
我大学的时候学的算法课,现在想温习一下,这篇文章正好合适
有9位网友表示赞同!
二分查找好像在面试也经常考吧?这篇文章应该能复习复习
有14位网友表示赞同!
希望文章能解释清楚这两个算法的复杂度分析,这个很重要啊!
有13位网友表示赞同!
我之前试过快速排序,感觉效率挺高的,就来看看作者是怎么解释它的
有20位网友表示赞同!
现在做软件开发,需要了解一些算法知识,这篇文章正好可以学习一下
有11位网友表示赞同!
图解真的比纯文字的讲解更容易理解
有18位网友表示赞同!
算法一直都是我比较感兴趣的话题,会好好看看这部“算法图解”
有10位网友表示赞同!
二分查找好常见啊,各种面试题都可能会用到
有6位网友表示赞同!
学习时间学个算法图解,看看能不能提升一下我的编程能力
有6位网友表示赞同!
不知道快速排序在实际项目中使用场景有多广泛?
有11位网友表示赞同!
这两天正好想复习一下数据结构和算法,这篇文章太合适了!
有5位网友表示赞同!
学习编程感觉算法是必不可少的知识点
有12位网友表示赞同!
希望文章能给我一些关于如何应用二分查找和快速排序的实例,这样更直观
有16位网友表示赞同!
图解真的可以让我更快理解和记忆这些复杂的算法逻辑
有19位网友表示赞同!
算法学习需要循序渐进,从基础开始学感觉比いきなり看复杂的部分要好
有9位网友表示赞同!