十大排序傻傻分不清?一文带你了解!(有源码有例子)

本文详细介绍了十大排序算法,包括冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序和基数排序,分析了它们的工作原理、优缺点及适用场景。排序算法的选择应根据数据规模、是否需要稳定性以及效率需求等因素来决定。
摘要由CSDN通过智能技术生成

以下是常见的十大排序算法:

冒泡排序(Bubble Sort):重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来,直到没有交换的元素剩下。

选择排序(Selection Sort):首先在未排序的数列中找到最小元素,然后将其存放到排序序列的起始位置,接着再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。重复此操作,直到所有元素均排序完毕。

插入排序(Insertion Sort):将待排序的数组分成已排序和未排序两个部分,取未排序部分的第一个元素插入到已排序的合适位置,重复这个过程直到未排序部分为空。

希尔排序(Shell Sort):将待排序的数组按照一定的增量进行分组,对每组数据进行插入排序,随着增量逐渐减少,每组包含的元素越来越多,当增量减至1时,整个序列被分成一组,完成排序。

归并排序(Merge Sort):将数组递归地分成两半,然后对两半分别排序,最后将排好序的两半合并成一个有序的数组。

快速排序(Quick Sort):选择一个枢轴元素,将数组分成两部分,一部分比枢轴元素小,一部分比枢轴元素大,然后分别对两部分递归地进行快速排序。

堆排序(Heap Sort):将待排序的数组构建成一个最大堆或最小堆,然后依次取出堆顶元素并删除,最终得到有序数组。

计数排序(Counting Sort):对于输入的n个元素,确定其中最大的元素k,然后开辟一个长度为k+1的计数数组,对于每个元素,统计小于它的元素个数,最终得到有序序列。

桶排序(Bucket Sort):将元素划分到一定数量的桶中,对于每个桶中的元素进行排序,最后依次将每个桶中的元素输出。

基数排序(Radix Sort):根据元素的位数,将元素分别放入对应的桶中,然后依次输出桶中的元素,最终得到有序序列。

咳咳,可能有的童鞋又要说了,笙囧你不讲武德,又甩出来一堆概念,看的我头都大了,别急嘛,下面笙囧一个个细细的讲

冒泡排序是一种简单直观的排序算法,它的思路是不断地比较相邻的两个元素,如果它们的顺序不符合要求就互相交换位置,一直重复这个过程,直到没有相邻的元素需要交换为止。

可以想象一下,冒泡排序的过程就像是把一堆水泡冒出来一样,每次比较的两个元素就像两个相邻的水泡,它们之间的大小关系就像是水泡内部的气体压力大小一样。如果气体压力小的水泡在气体压力大的水泡前面,那么就要把它们交换位置,使得气体压力大的水泡能够“冒”到前面去。

例如,我们要对以下一组数据进行冒泡排序:[5, 2, 8, 4, 7]

首先,我们比较相邻的两个元素,如果前面的元素比后面的元素大,则交换它们的位置。第一次比较完毕后,最大的元素7已经“冒”到了数组的最后面。

比较前后元素的过程如下:

5 2 8 4 7 --> 2 5 8 4 7

2 5 8 4 7 --> 2 5 4 8 7

2 5 4 8 7 --> 2 5 4 7 8

第一次冒泡完成后,得到的数组为:[2, 5, 4, 7, 8]

接下来,我们继续比较相邻的两个元素,不断重复这个过程,直到整个数组都有序为止。在第二次冒泡中,我们可以发现4比7小,所以它们要交换位置,得到的数组为:[2, 5, 4, 7, 8]

比较前后元素的过程如下:

2 5 4 7 8 --> 2 4 5 7 8

第二次冒泡完成后,得到的数组为:[2, 4, 5, 7, 8]

在第三次冒泡中,我们可以发现2比4小,所以它们要交换位置,得到的数组为:[2, 4, 5, 7, 8]

比较前后元素的过程如下:

2 4 5 7 8 --> 2 4 5 7 8

第三次冒泡完成后,得到的数组为:[2, 4, 5, 7, 8]

由于在第三次冒泡排序中没有需要交换位置的相邻元素了,所以整个数组已经有序了。因此,最终得到的排序结果为:[2, 4, 5, 7, 8]。

总的来说,冒泡排序算法的核心思想是不断比较相邻的两个元素,通过交换它们的位置,让较大的元素向数组的末尾“冒泡”。这个过程就像是水泡在水面上冒泡一样,非常形象生动,易于理解。

然而,需要注意的是,冒泡排序的时间复杂度为O(n^2),在处理大规模的数据时,效率比较低下,不适合处理大规模数据的排序问题。

选择排序也是一种简单直观的排序算法,其基本思路是找到未排序区间中的最小元素,将其放在已排序区间的末尾,然后不断重复这个过程,直到整个数组都有序。

可以将选择排序的过程想象成为选择一副扑克牌,每次从牌堆中找到最小的牌放到手中已排好序的牌的末尾,直到牌堆中没有牌为止。

例如,我们要对以下一组数据进行选择排序:[5, 2, 8, 4, 7]

首先,在整个数组中找到最小的元素2,将其与第一个元素5交换位置,得到以下结果:[2, 5, 8, 4, 7]。

然后,在剩余的未排序区间[5, 8, 4, 7]中找到最小的元素4,将其与第二个元素5交换位置,得到以下结果:[2, 4, 8, 5, 7]。

接着,再在剩余的未排序区间[8, 5, 7]中找到最小的元素5,将其与第三个元素8交换位置,得到以下结果:[2, 4, 5, 8, 7]。

然后,在剩余的未排序区间[8, 7]中找到最小的元素7,将其与第四个元素8交换位置,得到以下结果:[2, 4, 5, 7, 8]。

最后,因为整个数组已经有序,选择排序结束。

总的来说,选择排序算法的核心思想是找到未排序区间中的最小元素,将其放在已排序区间的末尾,不断重复这个过程,直到整个数组都有序。选择排序虽然比冒泡排序的效率要高一些,但时间复杂度仍为O(n^2),也不适合处理大规模数据的排序问题。

插入排序也是一种简单直观的排序算法,其基本思路是将未排序区间中的元素逐一插入到已排序区间中的合适位置,最终得到一个有序的数组。

可以将插入排序的过程想象成为整理扑克牌,每次将一张新牌插入到已经排好序的牌中的合适位置,直到所有牌都排好序为止。

例如,我们要对以下一组数据进行插入排序:[5, 2, 8, 4, 7]

首先,将第一个元素5看作已排序区间,将剩余的未排序区间[2, 8, 4, 7]中的第一个元素2插入到已排序区间中的合适位置,得到以下结果:[2, 5, 8, 4, 7]。

然后,将前两个元素[2, 5]看作已排序区间,将未排序区间[8, 4, 7]中的第一个元素8插入到已排序区间中的合适位置,得到以下结果:[2, 5, 8, 4, 7]。

接着,将前三个元素[2, 5, 8]看作已排序区间,将未排序区间[4, 7]中的第一个元素4插入到已排序区间中的合适位置,得到以下结果:[2, 4, 5, 8, 7]。

然后,将前四个元素[2, 4, 5, 8]看作已排序区间,将未排序区间中的最后一个元素7插入到已排序区间中的合适位置,得到以下结果:[2, 4, 5, 7, 8]。

最后,因为整个数组已经有序,插入排序结束。

总的来说,插入排序算法的核心思想是将未排序区间中的元素逐一插入到已排序区间中的合适位置,最终得到一个有序的数组。虽然插入排序的效率比冒泡排序和选择排序要高一些,但时间复杂度仍为O(n^2),也不适合处理大规模数据的排序问题。

希尔排序是一种改进的插入排序算法,也称为“缩小增量排序”(Shell Sort),是对插入排序的一种优化。

希尔排序的基本思想是将整个序列分割成若干个子序列,对每个子序列进行插入排序,随着增量的减少,每个子序列的元素越来越多,当增量减至1时,整个序列恰被分成一个子序列,此时整个序列已经基本有序,最后对整个序列进行一次插入排序即可。

可以将希尔排序的过程想象成为先从较大间隔(增量)开始排序,一次缩小增量直至1,最后用普通的插入排序完成排序。例如,我们要对以下一组数据进行希尔排序:[8, 3, 5, 1, 4, 2, 7, 6]。

首先,设定增量为4,将数据分成4个子序列,分别对4个子序列进行插入排序,得到以下结果:[4, 2, 5, 1, 6, 3, 7, 8]。

然后,将增量减半,得到增量为2,将数据分成2个子序列,分别对2个子序列进行插入排序,得到以下结果:[1, 2, 3, 4, 6, 5, 7, 8]。

最后,将增量减半,得到增量为1,此时整个序列已经基本有序,对整个序列进行一次插入排序,得到最终结果:[1, 2, 3, 4, 5, 6, 7, 8]。

总的来说,希尔排序的优点在于它的效率比插入排序高很多,因为插入排序的效率受到插入位置的影响,而希尔排序的增量序列可以有很多种选择,不同的增量序列会影响算法的效率。希尔排序的时间复杂度最坏为O(n^2),最好为O(nlogn),平均为O(n^1.3)。

归并排序是一种经典的排序算法,它利用分治的思想将一个序列分成若干个子序列,对每个子序列进行排序,然后再将排序好的子序列合并成一个有序的序列,最终得到排序后的结果。

例如,我们要对以下一组数据进行归并排序:[38, 27, 43, 3, 9, 82, 10]。

首先,将整个序列分成两个子序列,分别为[38, 27, 43, 3]和[9, 82, 10],然后继续将两个子序列分别分成两个更小的子序列,得到四个子序列:[38, 27],[43, 3],[9, 82],[10]。

接下来,对每个子序列进行排序。首先对[38, 27]进行排序,得到[27, 38];对[43, 3]进行排序,得到[3, 43];对[9, 82]进行排序,得到[9, 82];对[10]进行排序,得到[10]。

接着,将排好序的子序列合并起来。首先将[27, 38]和[3, 43]合并成一个有序序列[3, 27, 38, 43];再将[9, 82]和[10]合并成一个有序序列[9, 10, 82]。

最后,将合并好的两个有序序列[3, 27, 38, 43]和[9, 10, 82]合并成一个完整的有序序列[3, 9, 10, 27, 38, 43, 82],排序完成。

总的来说,归并排序的优点在于它稳定且时间复杂度稳定,不会受到数据的影响。归并排序的时间复杂度是O(nlogn),其中n为数据的规模,这个时间复杂度比冒泡、插入、选择的O(n^2)要快很多,但是归并排序的空间复杂度比较大,需要额外的存储空间来合并两个子序列。

快速排序是一种基于分治思想的排序算法。它选取一个元素作为“基准”,通过比较大小将数据分成两个部分,一部分大于基准,一部分小于基准,然后对这两部分分别递归地进行快速排序,最终将整个序列排序完成。

例如,我们要对以下一组数据进行快速排序:[8, 3, 5, 1, 9, 2, 7, 4]。

首先,选择一个元素作为基准,一般选择第一个元素8作为基准。接下来,从序列的右端开始往左找到第一个比基准小的元素2,然后将2放到序列的左端。接着,从序列的左端开始往右找到第一个比基准大的元素3,然后将3放到序列的右端。

继续循环这个过程,直到左右两个指针相遇。此时,将基准元素放到这个位置,即8放到序列中间的位置。这时,序列被分成了左右两部分,左边部分的元素都小于基准元素,右边部分的元素都大于基准元素。

接下来,对左右两部分分别进行快速排序。对于左边部分[3, 5, 1, 2, 4],选择第一个元素3作为基准,将序列分成[2, 1],[3],[5, 4]三个部分,然后递归地对左右两部分进行排序。最终得到[1, 2, 3, 4, 5]。

对于右边部分[9, 7],选择第一个元素9作为基准,将序列分成[7],[9]两个部分,然后递归地对左右两部分进行排序。最终得到[7, 9]。

最终将左右两部分合并起来,得到[1, 2, 3, 4, 5, 7, 9],排序完成。

总的来说,快速排序的优点在于它效率比较高,是一种较为常用的排序算法。快速排序的时间复杂度是O(nlogn),其中n为数据的规模,空间复杂度也比较小,只需要常数级别的额外存储空间。但是,快速排序的缺点在于对于不同的数据集合可能会导致快排的时间复杂度退化成O(n^2),因此需要在实际应用中加以优化。

堆排序是一种基于堆数据结构的排序算法。堆是一种完全二叉树,分为大根堆和小根堆两种,大根堆的每个节点的值都大于等于其子节点的值,小根堆的每个节点的值都小于等于其子节点的值。堆排序利用堆的性质,将待排序序列构造成一个大根堆或小根堆,然后每次将堆顶元素与最后一个元素交换,再将前n-1个元素重新构造堆,重复这个过程直到排序完成。

例如,我们要对以下一组数据进行堆排序:[8, 3, 5, 1, 9, 2, 7, 4]。

首先,将这些数据构建成一个大根堆。具体的构建方法是,从最后一个非叶子节点开始,依次将其和它的子节点进行比较,如果子节点的值比父节点大,则将它们交换。例如,在这个例子中,节点7和4交换,节点5和2交换,节点3和1交换,构成的大根堆为[9, 8, 7, 4, 3, 2, 5, 1]。

接下来,将堆顶元素9与最后一个元素4交换,得到[4, 8, 7, 1, 3, 2, 5, 9]。这时,只有前7个元素是未排序的,因此需要重新构建堆。再次构建大根堆后得到[8, 4, 7, 1, 3, 2, 5],然后将堆顶元素8与最后一个元素5交换,得到[5, 4, 7, 1, 3, 2, 8],继续重建大根堆得到[7, 4, 8, 1, 3, 2],再将堆顶元素7与最后一个元素2交换,得到[2, 4, 8, 1, 3, 7],继续重建大根堆得到[8, 4, 7, 1, 3],然后将堆顶元素8与最后一个元素3交换,得到[3, 4, 7, 1, 8],继续重建大根堆得到[7, 4, 8, 1],最后将堆顶元素7与最后一个元素1交换,得到[1, 4, 8, 7],排序完成。

总的来说,堆排序的时间复杂度为O(nlogn),其中n为数据的规模,空间复杂度为O(1),是一种比较高效的排序算法。但是,堆排序的缺点在于它不是稳定的

桶排序也是一种非比较排序算法,它的基本思想是将待排序序列中的元素分到不同的桶中,每个桶再分别进行排序,最后将所有桶中的元素按顺序合并起来得到一个有序序列。

具体来说,桶排序的过程如下:

首先确定桶的个数,桶的个数应该根据待排序序列的范围和大小来确定,一般情况下,桶的个数可以取待排序序列的元素个数。

将待排序序列中的元素放到对应的桶中。具体做法是将待排序序列中的每个元素映射到桶中,例如,对于一个范围为[0, 9]的元素,可以将它们放到大小为10的桶中,桶的编号从0到9。

对每个非空的桶进行排序,可以采用任何一种排序算法,例如插入排序、快速排序等。

将所有桶中的元素按顺序合并起来,得到一个有序序列。

例如,我们要对以下一组数据进行桶排序:[5, 3, 2, 8, 6, 4, 9, 1, 0, 7]。

首先,我们确定桶的个数为10,将待排序序列中的元素放到对应的桶中,例如,元素5放到编号为5的桶中,元素3放到编号为3的桶中,以此类推。得到的桶为:

0: [0]

1: [1]

2: [2]

3: [3]

4: [4]

5: [5]

6: [6]

7: [7]

8: [8]

9: [9]

然后,对每个非空的桶进行排序,可以采用任何一种排序算法,例如插入排序、快速排序等。在这个例子中,我们采用插入排序进行排序,得到的桶为:

0: [0]

1: [1]

2: [2]

3: [3, 4, 5]

4: []

5: [6]

6: []

7: [7]

8: [8]

9: [9]

最后,将所有桶中的元素按顺序合并起来,得到一个有序序列为[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。

总的来说,桶排序的时间复杂度为O(n+k),其中n为数据的规模,k为桶的个数,空间复杂度为O(n+k),是一种比较高效的排序算法。但是,桶排序也有它的缺点,当待排序序列中的元素分布不均匀时,会导致某些桶中的元素过多,需要的空间也会随之变大。

基数排序也是一种非比较排序算法,它的基本思想是通过多次比较元素的每一位数字来对待排序序列进行排序。

具体来说,基数排序的过程如下:

首先确定排序的位数,以位数为基础进行排序。例如,如果待排序序列中的元素都是非负整数,可以按照个位、十位、百位等依次进行排序。

将待排序序列中的元素按照排序位上的数字分到不同的桶中,桶的个数根据排序位上数字的取值范围确定。

对每个桶中的元素进行排序,可以采用任何一种排序算法,例如插入排序、快速排序等。

将所有桶中的元素按照顺序合并起来,得到一个有序序列。

如果排序位数还没有达到指定的位数,则返回第2步,否则结束排序。

例如,我们要对以下一组数据进行基数排序:[53, 3, 542, 748, 14, 214, 154, 63, 616]。

首先,我们确定排序的位数为3,依次按照个位、十位、百位进行排序。首先按照个位排序,将待排序序列中的元素分到不同的桶中,得到的桶为:

0: []

1: [541]

2: [52, 62]

3: [53, 3]

4: [14]

5: [215, 155, 65]

6: [616]

7: [748]

8: []

9: []

然后,对每个桶中的元素进行排序,可以采用任何一种排序算法,例如插入排序、快速排序等。在这个例子中,我们采用插入排序进行排序,得到的桶为:

0: []

1: [541]

2: [52, 62]

3: [3, 53]

4: [14]

5: [155, 215, 65]

6: [616]

7: [748]

8: []

9: []

接下来,按照十位进行排序,将待排序序列中的元素分到不同的桶中,得到的桶为:

0: []

1: [3, 14]

2: []

3: [155]

4: []

5: [52, 53, 542]

6: [616]

7: [748]

8: []

9: [215, 65]

然后,对每个桶中的元素进行排序,得到的桶为:

0: []

1: [3, 14]

2: []

3: [155]

4: []

5: [52, 53]

6: [616]

7: [748]

8: []

9: [65, 215, 542]

接下来,按照百位进行排序,将待排序序列中的元素分到不同的桶中,得到的桶为:

0: [3, 14, 52, 53, 65]

1: []

2: []

3: [542]

4: []

5: []

6: [616]

7: [748]

8: []

9: [155, 215]

然后,对每个桶中的元素进行排序,得到的桶为:

0: [3, 14, 52, 53, 65]

1: []

2: []

3: [542]

4: []

5: []

6: [616]

7: [748]

8: []

9: [155, 215]

最后,将所有桶中的元素按照顺序合并起来,得到一个有序序列:[3, 14, 52, 53, 65, 155, 215, 542, 616, 748]。

基数排序的时间复杂度取决于排序的位数和每次排序所用的排序算法,一般情况下可以达到O(d(n+r))的时间复杂度,其中d为位数,n为待排序元素个数,r为基数。但是基数排序的空间复杂度比较高,需要额外的空间来存储每个桶。

哈哈哈哈,大功告成,累坏笙囧了,读者姥爷们一定会双击屏幕的对吧

另外,10种分类方式一听就好难记住,笙囧按照相似度,将这10种排序算法分为以下几类:

1.比较排序:冒泡排序、选择排序、插入排序、希尔排序、归并排序和快速排序。这些算法都是基于比较的排序算法,通过比较元素的大小来确定它们在排序结果中的位置。

2.非比较排序:计数排序、桶排序和基数排序。这些算法不需要进行元素之间的比较,它们利用元素的一些特性,如出现次数、数值范围或位数等来实现排序。

3.基于选择的排序:选择排序、堆排序。这两个算法都是通过选择元素来排序的,选择排序是从待排序序列中选择最小的元素,而堆排序是利用堆这种数据结构来选择元素。

4.基于插入的排序:插入排序、希尔排序。这两个算法都是通过插入元素来排序的,插入排序是将待排序序列分为已排序区和未排序区,每次从未排序区选取一个元素插入到已排序区中,而希尔排序是通过先进行一定间隔的插入排序来将序列变得部分有序,然后再进行插入排序。

需要注意的是,这些分类并不是完全独立的,有些算法可能属于多个分类。例如,快速排序既属于比较排序,也属于基于选择的排序。

好了,离开手机,你的脑袋瓜子里有没有充满了知识,对于十大排序算法有了一定的概念,好,回味一下,再来看看他们的应用场景

这10种排序算法各有特点,适用于不同的场景

冒泡排序:由于冒泡排序的时间复杂度较高,因此它在实际应用中并不常见。但是,它的原理简单易懂,可以作为初学者学习排序算法的入门。

选择排序:选择排序在实现上比较简单,对于小规模的数据集来说,它的效率还是比较高的。但是,它的时间复杂度为O(n^2),因此在大规模数据集上应用时,效率会很低。

插入排序:插入排序适用于对少量元素进行排序的情况。它对于部分有序的数据集效率很高,而对于完全无序的数据集效率较低。

希尔排序:希尔排序在大规模数据集上的效率相对较高,但是它的实现比较复杂,不如插入排序和选择排序容易理解。

归并排序:归并排序的时间复杂度为O(nlogn),因此它在大规模数据集上应用时效率比较高。它是一种稳定排序算法,适用于各种数据类型的排序。

快速排序:快速排序的时间复杂度为O(nlogn),在大规模数据集上应用时效率比较高。但是,它是一种不稳定的排序算法,对于部分有序的数据集效率较低。

堆排序:堆排序适用于大规模数据集的排序。它的时间复杂度为O(nlogn),它可以有效地处理大规模数据集。

计数排序:计数排序适用于元素取值范围较小的数据集,它的时间复杂度为O(n+k),其中k为元素取值范围。

桶排序:桶排序适用于元素分布较为均匀的数据集,它的时间复杂度为O(n+k),其中k为桶的个数。

基数排序:基数排序适用于数字类型的数据集。它的时间复杂度为O(d(n+k)),其中d为数字的位数,k为每一位数字的取值范围。它通常用于处理大规模数字类型数据的排序。

有的题目可能会问,在保证稳定性的情况下,选择什么算法,

按照排序算法的稳定性,可以将10种排序算法分成两类:

稳定排序算法:在排序过程中,如果两个元素的值相等,那么它们在原序列中的相对位置在排序后仍然保持不变。稳定排序算法包括归并排序、插入排序、冒泡排序、基数排序、计数排序等。

不稳定排序算法:在排序过程中,如果两个元素的值相等,那么它们在原序列中的相对位置在排序后可能会发生变化。不稳定排序算法包括快速排序、选择排序、堆排序、桶排序等。

在实际应用中,如果需要保持排序前的元素顺序,那么就需要选择稳定排序算法。例如,在对一个学生成绩表进行排序时,如果两个学生的成绩相同,那么就需要保持他们在表格中的顺序不变,这时就需要使用稳定排序算法。而如果只是简单地需要对元素进行排序,那么可以选择不稳定排序算法来提高排序效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笙囧同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值