面试官:写一个冒泡排序和快速排序吧
Posted 爬虫工程师之家
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试官:写一个冒泡排序和快速排序吧相关的知识,希望对你有一定的参考价值。
排序算法是面试必考题,本文聊一聊通过交换顺序从而得到有序数列的冒泡排序和快速排序。
首先来看冒泡排序
冒泡排序是一种简单的排序算法,我们最终要一个由小到大或由大到小的排序数列,每次比较两个相邻的元素,如果他们的顺序错误就把他们交换过来,算法名称的由来也是因为越小或越大的元素会经由交换,慢慢的浮到数列的顶端。
算法描述:
1、比较相邻的元素,如果第一个比第二个大(或者第一个比第二个小),就交换他们两个;
2、对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大或最小的数;
3、重复以上步骤,直到排序完成。
执行一次的过程可以用动图展示出来:
该图片选自《算法从入门到“放弃”(6)- 冒泡排序》https://zhuanlan.zhihu.com/p/40859355
代码实现:
def bubbling_sort(alist):
'''
冒泡排序
:param alist: 无序数列
:return: 有序数列
'''
n = len(alist)
# 共执行循环
for i in range(0,n):
# 执行一次循环
for j in range(0,n-1-i):
#判断当前值和下一个值的大小
if alist[j] > alist[j+1]:
#如果当前值大于下一个值,则交换
alist[j],alist[j+1] = alist[j+1],alist[j]
if __name__ == '__main__':
alist = [66,1,3,-9,20,7,100,0]
bubbling_sort(alist)
print("最终结果为:",alist)
#[-9, 0, 1, 3, 7, 20, 66, 100]
接下来,我们来看快速排序
快速排序使用分拆排序方法,将一组数列分为两个子数列。
1、从数列中挑出一个元素,称为"基准",一般我们取数列中索引为0的数值
2、对数列进行拆分和排序,比基准元素小的元素放在基准元素的左侧,比基准元素大的元素放在基准元素的右侧。经过排序后,该基准就找到了自己应该在的位置,此时最原始的数列被分为两个子数列;
假设我们现在对“6 1 2 7 9 3 4 5 10 8”这个 10 个数进行排序。首先在这个序列中随便找一个数作为基准数(不要被这个名词吓到了,就是一个用来参照的数,待会你就知道它用来做啥的了)。为了方便,就让第一个数 6 作为基准数吧。接下来,需要将这个序列中所有比基准数大的数放在 6 的右边,比基准数小的数放在 6 的左边,类似下面这种排列。
3 1 2 5 4 6 9 7 10 8
该段选自《算法 3:最常用的排序——快速排序》http://wiki.jikexueyuan.com/project/easy-learn-algorithm/fast-sort.html
此时生成两个子数列,分别为3 1 2 5 4和9 7 10 8
3、通过递归,把子数列按照相同的方法进行拆分和排序。
实现方法:
要实现快速排序,就是要找到无序数列中每个元素应该放置的位置。
以下段落该段选自《算法 3:最常用的排序——快速排序》http://wiki.jikexueyuan.com/project/easy-learn-algorithm/fast-sort.html
方法其实很简单:分别从初始序列“6 1 2 7 9 3 4 5 10 8”两端开始“探测”。先从右往左找一个小于 6 的数,再从左往右找一个大于 6 的数,然后交换他们。这里可以用两个变量 i 和 j,分别指向序列最左边和最右边。我们为这两个变量起个好听的名字“哨兵 i”和“哨兵 j”。刚开始的时候让哨兵 i 指向序列的最左边(即 i=1),指向数字 6。让哨兵 j 指向序列的最右边(即 j=10),指向数字 8。
首先哨兵 j 开始出动。因为此处设置的基准数是最左边的数,所以需要让哨兵 j 先出动,这一点非常重要(请自己想一想为什么)。哨兵 j 一步一步地向左挪动(即 j--),直到找到一个小于 6 的数停下来。接下来哨兵 i 再一步一步向右挪动(即 i++),直到找到一个数大于 6 的数停下来。最后哨兵 j 停在了数字 5 面前,哨兵 i 停在了数字 7 面前。
现在交换哨兵 i 和哨兵 j 所指向的元素的值。交换之后的序列如下。
6 1 2 5 9 3 4 7 10 8
到此,第一次交换结束。接下来开始哨兵 j 继续向左挪动(再友情提醒,每次必须是哨兵 j 先出发)。他发现了 4(比基准数 6 要小,满足要求)之后停了下来。哨兵 i 也继续向右挪动的,他发现了 9(比基准数 6 要大,满足要求)之后停了下来。此时再次进行交换,交换之后的序列如下。
6 1 2 5 4 3 9 7 10 8
第二次交换结束,“探测”继续。哨兵 j 继续向左挪动,他发现了 3(比基准数 6 要小,满足要求)之后又停了下来。哨兵 i 继续向右移动,糟啦!此时哨兵 i 和哨兵 j 相遇了,哨兵 i 和哨兵 j 都走到 3 面前。说明此时“探测”结束。我们将基准数 6 和 3 进行交换。交换之后的序列如下。
3 1 2 5 4 6 9 7 10 8
到此第一轮“探测”真正结束。此时以基准数 6 为分界点,6 左边的数都小于等于 6,6 右边的数都大于等于 6。回顾一下刚才的过程,其实哨兵 j 的使命就是要找小于基准数的数,而哨兵 i 的使命就是要找大于基准数的数,直到 i 和 j 碰头为止。
OK,解释完毕。现在基准数 6 已经归位,它正好处在序列的第 6 位。此时我们已经将原来的序列,以 6 为分界点拆分成了两个序列,左边的序列是“3 1 2 5 4”,右边的序列是“ 9 7 10 8 ”。
如上过程,我们可以通过代码来实现它
def quick_sort(alist,first,last):
'''
快速排序
:param alist: 无序序列
:param first: 游标起始位置
:param last: 游标终止位置
:return: 有序序列
'''
# 当游标重合即只有一个元素时为有序状态
if first >= last:
return
# 选取一个基准值
mid_value = alist[first]
# 游标起始位置
low = first
# 游标终止位置
high = last
while low < high:
# 当游标终止位置值大于基准值并且两个游标没有相遇时
while low < high and alist[high] >= mid_value:
high = high - 1
# 否则退出循环进行值交换
alist[low] = alist[high]
# 当游标起始位置值小于基准值并且两个游标没有相遇时
while low < high and alist[low] < mid_value:
low = low + 1
# 否则退出循环进行值交换
alist[high] = alist[low]
# 找到基准值位置
alist[low] = mid_value
print(alist)
# 对分割的两个部分进行递归操作
quick_sort(alist,first,low-1)
quick_sort(alist,low+1,last)
if __name__ == '__main__':
alist = [66,1,3,-9,20,7,100]
n = len(alist)
quick_sort(alist,0,n-1)
print("最终结果为:",alist)
#[-9, 1, 3, 7, 20, 66, 100]
以上即为冒泡排序和快速排序的粗浅解释及看法,欢迎大家一起交流。
以上是关于面试官:写一个冒泡排序和快速排序吧的主要内容,如果未能解决你的问题,请参考以下文章