目录
一、前言
排序,是数据处理过程中经常使用的一种重要操作。
排序:是把一个 无序的 数据序列 按照某个关键字进行 有序排列的过程。
最常见的排序分类:
本篇文章 注重的是 概念理解;如果有需要代码实现,可以去看 博客园博主 一像素 的作品,下面给出链接。
二、交换类排序(!!!重点!!!)
交换类排序有分为:
- 冒泡排序
- 快速排序 (面试官 最喜欢问的一种 排序方法)
2.1、冒泡排序(Bubble Sort)
冒泡排序:是一种简单的交换类排序。
原理:
- -比较相邻的元素。如果第一个比第二个大,就交换他们两个。(升序,降序反之)
- - 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后 的元素应该会是最大的数。
- - 针对所有的元素重复以上的步骤,除了最后一个。
- - 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
口诀:
升序排列: N个数字来排队 两两相比小靠前, 外层 循环length-1 内层循环length-i-1
降序排序: N个数字来排队 两两相比大靠前, 外层 循环length-1 内层循环length-i-1
代码实现(java):
package com.kaikeba.demo1; public class test { public static void main(String[] args) { int[] nums = {1,3,9,5,6,7,15,4,8}; int temp; // 首先进行 冒泡排序 for (int i=0; i<nums.length-1; i++) { //第一层循环 for (int j = 0; j < nums.length - i - 1; j++) { //第二层循环 if (nums[j] > nums[j + 1]) { temp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = temp; } } for (int k=0; k< nums.length;k++){ //打印每一次 第二层循环 结束后,nums数组 System.out.print(nums[k]+"\t"); } System.out.println(""); } } }
2.2、快速排序(Quick Sort)
快速排序算法,是由图灵奖获得者 Tony Hoare 于1962年设计出来的。
是同量数级中最快的内部排序方法。
是冒泡排序的升级算法
原理:
- 从序列中,任选一个元素(通常选取第一个元素)作为支点,其余元素逐一与之比较;
- 比该元素小的,则交换到该元素前面; 比该元素大的,则交换到该元素后面;
- 在进行一轮循环之后,支点前面的元素(称序列1),都是比ta小的;支点后面的元素称序列2),都是比ta大的。 但是 两个序列1、2,各自之间还是无序的。
- 然后,对两个序列,重新执行上述操
动图不能理解该算法,可以看下面举的例子。
原排列 :{37,19,90,64,13,49,20,40}
第一躺排序结果: {20 19 13} 37 {64 49 90 40}
第二躺排序结果: {13 19} 20 {37} {40 49} 64 {90}
第三趟排序结果: 13 {19} 20 37 40 {49} 64 90
最终 : 13 19 20 37 40 49 64 90
代码实现(java)
代码这块,博主后面,会自己编写,继续更新........
三、插入类排序
插入类排序分为:
- 直接插入排序
- 希尔排序
3.1、直接插入排序
直接插入排序,是最简单的排序方法之一。
原理:
- 将待排序的数列,分为无序部分 && 有序部分。开始时,第一个元素为有序区,其余元素则为无序区。
- 之后,将无序区 的第一个元素,按序插入有序区。
- 重复上述操作,直到无序区中全部元素插入有序区。
动图不能理解该算法,可以看下面这个例子:
" [ ] " 表示有序区 ; 高亮元素表示无序区第一个元素
每一次 都将无序区的 第一个元素,插入有序区中,并按序排好
待排序序列: 20 6 15 7 3 6
开始排序前: [ 20 ] 6 15 7 3 6
第一次排序: [ 6 20 ] 15 7 3 6
第二次排序: [ 6 15 20 ] 7 3 6
第三次排序: [ 6 7 15 20 ] 3 6
第四次排序: [ 3 6 7 15 20 ] 6
第五次排序: [ 3 6 6 7 15 20 ]
3.2 、希尔排序
希尔排序:
由D.L.Shell 在1959年提出得名,又称 “ 缩小增量排序算法 ”。
希尔排序对 直接插入排序进行了改进。
原理:
- 增量序列:t1,t2,…,tk,其中tk=1
- 根据给定的增量序列,依次按增量值分成若干小组,然后这小组进行直接插入排序。进行下一次按增量值排序。
- 经过上述几次分组排序后,整个序列就 “基本有序”了,此时增量值为1,也就是进行一次直接插入排序。
动图不能理解该算法,可以看下面这个例子:
增量序列 [ 5,3,1], 初始序列: 47 55 10 80 15 5 30 70 47 40
相同颜色,表示根据增量值分组,分到同一组。 ! 即同颜色的 为一组 !
第一个增量值:5
序号: 0 1 2 3 4 5 6 7 8 9 按增量值分组: 47 55 10 80 15 5 30 70 47 40 同组的进行
直接插入排序
的结果
5 30 10 47 15 47 55 70 80 40 第二个增量值:3
序号: 0 1 2 3 4 5 6 7 8 9 按增量值分组: 5 30 10 47 15 47 55 70 80 40 同组的进行
直接插入排序
的结果
5 15 10 40 30 47 47 70 80 55 第三个增量值:1
序号: 0 1 2 3 4 5 6 7 8 9 按增量值分组: 5 15 10 40 30 47 47 70 80 55 同组的进行
直接插入排序
的结果
5 10 15 30 40 47 47 55 70 80
四、选择类排序
选择类排序分为:
- 简单选择排序
- 堆排序
4.1 简单选择排序
简单选择排序,又称直接选择排序;是一种简单直观的排序方法。
原理:
- 从待排序 序列中,选取最小的元素,与序列第一个元素交换。
- 然后,再选取除上述元素外的 最小元素,与序列第二个元素交换。
- 依次进行,直到排序完成。
动图不能理解该算法,可以看下面这个例子:
- 待排序 序列: 23 90 9 25 16
- 红色元素 表示:当前序列最小元素,
- 绿色表示,已排好序 的元素
- 每次操作:红色元素与 “交换位置” 的元素交换
序号: 0 1 2 3 4 初始序列: 23 90 9 25 16 选取最小值
和 交换位置
交换
位置
min
序号: 0 1 2 3 4 第一次交换结果: 9 90 23 25 16 选取最小值
和 交换位置
交换
位置
min
序号: 0 1 2 3 4 第二次交换结果: 9 16 23 25 90 选取最小值
和 交换位置
min
交换
位置
序号: 0 1 2 3 4 第三次交换结果: 9 16 23 25 90 选取最小值
和 交换位置
min
交换
位置
序号: 0 1 2 3 4 第四次交换结果: 9 16 23 25 90
4.2、堆排序
堆排序:由Floyd与Williams,于1964年共同提出的 对 简单选择排序进行改进 的一种算法。
原理:
- 将待排序的的序列,构建成一个大顶堆,最大元素则为 堆顶的根节点。
- 将根节点元素 与 末尾元素 交换。
- 然后剩下元素,再构建一个新的大顶堆。
- 然后重复上述操作。
难题:
- 如何构建初始堆?
- 输出堆顶元素后,如何构建新的大顶堆?
- 先将待排序 序列,依序按照完全二叉树,构建好一个完全二叉树,为后面建成大顶堆做准备。
- 大顶堆构建:因为只有一个结点的树必是堆,而在完全二叉树中,所有大于(n/2)的结点,都是叶子,就都是堆。建堆时,是从(n/2)结点为跟的子树开始 构建出该节点的大顶堆。(从n/2开始往前 筛选)
例子:
待排序序列: 36 24 48 12 65 25 43 59 76 34 (共10个元素,即n=10)
- 完全二叉树构建如下图所示:
- 然 后开始 构建大顶堆,从(n/2)开始,也就是第五个元素 “65”开始 构建大顶堆。
!!!!! 如上图所述,初始堆构建完成!!!!
下一步,堆顶元素与末尾元素 交换,并把交换后的 末尾元素(即原本的堆顶元素,也就是序列的最大值)拿出去。
在上一步,输出最大元素后,可以看到现在 根节点是 34,我们下一步则开始调整二叉树,使其又变成 大顶堆。
其实,到这一步了,还是比较简单的,仔细看一下上面的二叉树,不难发现,现在就只有根节点,不满足 大顶堆的条件。
所以,只要把 34 与 65 调换,调换之后,根节点65就满足了 大顶堆条件。但34的子树,又不满足了。
因此又要继续调换,把 59 与 34 调换。虽然步骤多了点,但其实还是很简单的,小伙伴们仔细看,就行。
如上图为调整后的 ,一个新的 大顶堆,一样的操作,根节点与末尾结点交换,并输出根节点65,为原序列第二大元素。
后续,就依次重复操作,不断调整 大顶堆,直至输出所有元素!!!
五、归并排序
归并:在数据结构中的定义是 将两个或两个以上的 有序表 组合成一个新的 有序表。
归并排序:是建立在归并操作上的一种有效的排序算法。
归并排序分类:
- 二路归并排序
- 多路归并排序
本篇文章,就介绍 二路归并排序:
原理:
- 将待排序序列的每一个元素,看作一个有序的 序列。
- 将序列两两合并成一个 有序的 序列;若总共有奇数个序列,则最后那个序列,保持 不变,等前面的序列 两两合并之后,一起进入下一步操作。
- 两两合并之后,会得到新的 有序序列,这些新的序列,再一次两两合并。
- 重复上述操作,直至只剩下一个序列
例子:
待排序 序列 : 23 52 67 6 18 10 【】:表示一个有序的 序列
相同颜色 :表示 待会 两两合并
开始时 : 【23】 【52】 【67】 【6】 【18】 【10】
相邻的两两合并: 【23 52】 【6 67】 【10 18】
相邻的两两合并: 【6 23 52 67】 【10 18】
最终合并: 【6 10 18 23 52 67】
六、基数排序
基数排序:是一种典型的分配类排序方法。
主要是对有多个关键字的元素进行排序的。
例如,可以把整数的 个位、十位、百位作为关键字,对元素进行排序。
例子: 369 367 167 239 237 138 230 139
第一步,获取个位 的取值范围: 0 7 8 9,
然后按照 序列的顺序 ,依次分配到 下面中去:
0 :230
7 :367 167 237
8 :138
9 :369 239 139
所以第一次 排序结果为: 230 367 167 237 138 369 239 139
第二步 ,获取 十位的取值范围: 3 6
3 : 230 237 138 239 139
6 : 367 167 369
所以第二次 排序结果为: 230 237 138 239 139 367 167 369
第三步,获取 百位的取值范围:
1: 138 139 167
2: 230 237 239
3: 367 369
所以第二次 排序结果为: 138 139 167 230 237 239 367 369
好了,本篇文章,博主就介绍这么多,一共8种排序方法,大家重点掌握好冒泡排序和快速排序。如果文章有误或者不足之处,欢迎指正奥,博主会虚心听取的。最后制作不易,希望小伙伴们可以多点赞、多评论,关注一下博主哟!