几种常用的排序算法

什么是算法

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

算法真的很重要吗?

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

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

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

排序算法的运用非常广泛。各种语言都有自己内置的排序函数,在面试过程中也经常会有排序算法的考题。总结几种排序算法的实现。

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

我首先想到的是:

  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

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

冒泡排序(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的时候,不需要比较了,分治策略就结束。

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

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

分治法在算法中非常普遍,不是因为他能降低算法的复杂度,而是他能一步步将复杂的问题变得越来越简单,规模越来越小,最后变成一个超级简单的问题,如果能进一步抽象这种过程,就能考执行同样的抽象步骤解出来来。分治法经常和递归用在一起,这就衍生了一种变成方式——函数式编程,如果能多接触一些递归的案例,对于函数式变成和抽象是非常有帮助的。软件设计就是讲一个非常复杂的问题抽象的过程,所以掌握函数式编程和递归概念对于抽象能力和软件设计应该是很有帮助的。

下面实现快速排序:

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 的原因。

?

原文地址:https://www.cnblogs.com/heniu/p/9922039.html

时间: 2024-07-31 14:34:47

几种常用的排序算法的相关文章

7 种常用的排序算法-视觉直观感受

7 种常用的排序算法-可视化 1. 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性. 步骤: 从数列中挑出一个元素,称为 “基准”(pivot),

几种常用的排序算法总结

主要针对于插入排序,交换(冒泡和快速),选择,堆排序,归并这几种排序的基本原理和时间复杂度,及空间复杂度的一个总结. 一.插入排序 基本执行过程:3  5  2  7  9  8 1.从小到大:从第二个数开始,每次比较都与前边的几个数进行比较 但是从大到小,要先与前边排好序的几个数中的最大的开始进行比较即倒序比较,依次往前推. 如:5 先与3进行比较,比3大,所以直接排在3的后边为:3 5: 2要先与5进行比较,比5小,再与3比较,比3小,所以排序后为 2 3 5: 7要先与5比,比5大,所以直

视觉直观感受 7 种常用的排序算法

1. 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性. 步骤: 从数列中挑出一个元素,称为 "基准"(pivot), 重新排序数列,所有元

7 种常用的排序算法直观感受

1. 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性. 步骤: 从数列中挑出一个元素,称为 "基准"(pivot), 重新排序数列,所有元

八种常用的排序算法(转)

下面要讲到的8种排序都属于内部排序,既在内存中完成,主要从理论原理方面来分析的.    插入排序 ①直接插入排序 例:六个数12 15 9 20  6 31 24 用直接插入排序,如下图: 思路: 第一步:从给出的六个数中,随便拿出一个数,比如12,形成一个有序的数据序列(一个数当然是有序的数据序列了,不看12之外的数,就当其他的数不存在): 第二步:从剩下的五个数中挑出一个数来,比如15,和刚才的12作比较,12<15,因此,放在12后面,形成数据序列12 15: 第三步:从剩下的四个数中挑出

C语言几种常用的排序算法

/* ============================================================================= 相关知识介绍(所有定义只为帮助读者理解相关概念,并非严格定义): 1.稳定排序和非稳定排序    简单地说就是所有相等的数经过某种排序方法后,仍能保持它们在排序之前的相对次序,我们就 说这种排序方法是稳定的.反之,就是非稳定的.  比如:一组数排序前是a1,a2,a3,a4,a5,其中a2=a4,经过某种排序后为a1,a2,a4,a3,

浅析常用的排序算法

排序分内排序和外排序.内排序:指在排序期间数据对象全部存放在内存的排序.外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内.外存之间移动的排序.内排序的方法有许多种,按所用策略不同,可归纳为五类:插入排序.选择排序.交换排序.归并排序.分配排序和计数排序.插入排序主要包括直接插入排序,折半插入排序和希尔排序两种;选择排序主要包括直接选择排序和堆排序;交换排序主要包括冒泡排序和快速排序;归并排序主要包括二路归并(常用的归并排序)和自然归并.分配排序主要包括箱

JavaScript实现常用的排序算法

▓▓▓▓▓▓ 大致介绍 由于最近要考试复习,所以学习js的时间少了 -_-||,考试完还会继续的努力学习,这次用原生的JavaScript实现以前学习的常用的排序算法,有冒泡排序.快速排序.直接插入排序.希尔排序.直接选择排序 ▓▓▓▓▓▓ 交换排序 交换排序是一类在排序过程中借助于交换操作来完成排序的方法,基本思想是两两比较排序记录的关键字,如果发现两个关键字逆序,则将两个记录位置互换,重复此过程,直到该排序列中所有关键字都有序为止,接下来介绍交换排序中常见的冒泡排序和快速排序 ▓▓▓▓▓▓

java SE 常用的排序算法

java程序员会用到的经典排序算法实现 常用的排序算法(以下代码包含的)有以下五类: A.插入排序(直接插入排序.希尔排序) B.交换排序(冒泡排序.快速排序) C.选择排序(直接选择排序.堆排序) D.归并排序 E.分配排序(基数排序) 以下算法都是可以实现的,但是什么情况使用什么算法都是根据实际情况选用的. 如果有用的话就顶起吧,谢谢. import java.util.ArrayList; import java.util.List; public class Sort { // test