几种经常使用的排序算法

什么是算法

我想不少程序员恐怕误解了「算法」的意义,一想到算法就是动态规划,机器学习之类的高大名词。算法其实就是数学中的「解题过程」,解题过程要求精确,考虑各类状况,须要人看得懂。算法不须要你在键盘上选择什么编程语言实现,只须要在本子上详细的写出每个步骤就能够了。程序员

算法真的很重要吗?

我常常在社区里看到有人说初级开发不须要懂算法,这是很是真切的,不少的业务构建都是很常规的套路,查个数据库返回,没有太多复杂的计算,哪须要什么解题过程。面试

可是我想遇到稍微复杂一点的业务,或者想要系统运行得更流畅、更有性能的时候,咱们就会构思采起什么样的方法能让系统跑得更快、更稳定,因而有了「分布式算法」等架构方面的算法。有时候咱们发现某个响应很慢,可能就是某个算法的执行效率过慢,只是咱们不知道这也能称为算法?最多见的恐怕是多层遍历,很容易致使效率很低的问题。因此在编程的时候要养成思考算法复杂度的习惯。算法

算法对于提升代码的执行效率,对问题的抽象有很是大的帮助。算法学好了,在遇到同一类问题的时候不再用挤破脑壳来想了,可以更加容易的联想到相关的算法解决问题。程序员要想编程更容易,不怕各类场景没遇到过,学好算法是颇有必要的。数据库

排序算法的运用很是普遍。各类语言都有本身内置的排序函数,在面试过程当中也常常会有排序算法的考题。总结几种排序算法的实现。编程

这个问题的显示表示是:请详细描述如何将一组数字按从小到大的顺序排列。数组

我首先想到的是:bash

  1. 找出数组中最小的一个;
  2. 把这个数放到另外一数组的最后面;
  3. 把这个数从原来的数组中剔除;
  4. 重复

重复的过程一般涉及到遍历和递归,上面这个解法叫「选择排序」,用 Python 实现以下:架构

def select_sort(arr):
    new_arr = []
     # 重复
    for i in range(len(arr)):
        small_index = find_smallest(arr)
         # 把这个数从原来的数组中剔除;
        smallest = arr.pop(small_index)
         # 把这个数放到另外一数组的最后面;
        new_arr.append(smallest)
    return new_arr
       
def find_smallest(arr):
     """找出数组中最小的一个;"""
    smallest = arr[0]
    index = 0
    for e in range(1,len(arr)):
        if arr[e] < smallest:
            smallest = arr[e]
            index = e
    return index
复制代码

能够看出来,代码实现基本上就是用编程语言写出解题思路。因此不少编程进阶书都提到一个解决问题的办法就是离开键盘,去上个厕所,在纸上画一画。只要是解题思路很详细,基本上是能够用来当伪代码使用的,能够所有放入代码的注释当中。app

冒泡排序(Bubble Sort)

  1. 比较前一个数和后一个数,若是前比后大,对换他们的位置;
  2. 循环执行
def bubble_sort(arr):
    for i in range(len(arr) - 1):
        for j in range(len(arr) - i - 1):
            if arr[j] > arr[j + 1]:
                tmp = arr[j + 1]
                arr[j + 1] = arr[j]
                arr[j] = tmp
    return arr
复制代码

快速排序

上面两种算法要操做的步骤不少,当数组太多时就会形成性能太低,咱们能够想办法减小要操做的步骤,从而下降算法的复杂度,提升执行效率。减小步骤的不少算法都是将数据分红几部分来处理,也就是一般说的「分治」,从而不断减小没部分须要处理的步骤,选择排序就是这样一种算法: 1.选出第一个元素 2.遍历每一个元素,也就是从第二个开始拿,若是比第一个元素小,放到一个新数组里;若是比它大,放到另外一个数组; 3.对两个新数组执行一样的操做; 那何时不须要执行这样的操做了呢?当数组的元素个数小于2的时候,不须要比较了,分治策略就结束。less

「分治」是一种很是常见的解题思路。由于它能不断的将问题变成更简单的问题,最后变成一个显而易见的事。也就是说它有两个条件:

  • 基准条件。也就是没有办法再分了,足够简单了。
  • 分治条件或者叫递归条件。可以进一步缩小须要解决的问题的规模。

分治法在算法中很是广泛,不是由于他能下降算法的复杂度,而是他能一步步将复杂的问题变得愈来愈简单,规模愈来愈小,最后变成一个超级简单的问题,若是能进一步抽象这种过程,就能考执行一样的抽象步骤解出来来。分治法常常和递归用在一块儿,这就衍生了一种变成方式——函数式编程,若是能多接触一些递归的案例,对于函数式变成和抽象是很是有帮助的。软件设计就是讲一个很是复杂的问题抽象的过程,因此掌握函数式编程和递归概念对于抽象能力和软件设计应该是颇有帮助的。

下面实现快速排序:

def quick(arr):
    if len(arr) < 2:
        return arr
    else:
        base = arr[0]
        less = [i for i in arr[1:] if i < base]
        greater = [i for i in arr[1:] if i >= base]
        return quick(less) + [base] + quick(greater)
复制代码

归并排序

归并排序和选择排序同样是一种分治递归策略:

  1. 从中间分红两组
  2. 将两个已经排序好的列表进行合并,合并成的列表就是排序好的 那怎么对上述两个列表排序呢?对两个列表再执行分组策略 何时不能继续了呢?当元素个数小于 2 的时候

具体实现:

def merge_sort(arr):
    # divide to two
    if len(arr) < 2:
        return arr
    mid = int(len(arr)/2)
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    return merge(left, right)

def merge(left, right):
    result = []
    j = 0
    i = 0
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    # add the larger part both left and right
    result += left[i:]
    result += right[j:]
    return result
复制代码

总结

这篇文章总结了 4 个经常使用的排序算法的实现,这几个算法常常在面试中能够用到,须要紧紧掌握。掌握基础算法能让程序员知道一些经常使用的设计套路,在真遇到这些算法的应用场景的那一天,不至于挠头不知所措。经常使用的算法的复杂度能让咱们把握程序设计的性能,在软件出现性能瓶颈的时候能经过改善软件的算法来优化。在文章中,我还说明了递归和函数式编程的重要性,软件设计是一个抽象的过程,面向流程的编程很难让人养成抽象性思惟,而函数式编程每每经过递归能将具体的问题进一步抽象,有助于培养咱们的软件设计能力,这恐怕是之前的大牛和黑客都特别崇尚 Lisp 的缘由。

相关文章
相关标签/搜索