一、排序
- 目的:快速查找
- 衡量排序算法的优劣:
- 时间复杂度:分析关键字的比较次数和记录的移动次数
- 空间复杂度:分析排序算法中需要多少辅助内存
- 稳定性:如果两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种算法是稳定的
二、分类:内部排序 & 外部排序
- 内部排序:整个排序过程不需要借助与外部存储器(如磁盘等),所有排序操作都在内存中 完成
- 外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中 完成,必须借助于外部存储器。最常见的是多路归并排序。可以认为外部排序是 由多次内部排序组成
三、十大内部排序算法
- 选择排序 —— 直接选择排序、堆排序
- 交换排序 —— 冒泡排序、快速排序
- 插入排序 —— 直接插入排序、折半插入排序、Shell排序
- 归并排序 —— 桶式排序、基数排序
算法的5大特征
输入(Input) | 有0个或多个输入数据,这些输入必须有清楚的描述和定义 |
输出(Output) | 至少有1个或多个输出结果,不可以没有输出结果 |
有穷性(有限性,Finiteness) | 算法在有限的步骤之后会自动结束而不会无限循环,并且每一个步骤可以在可接受的时间内完成 |
确定性(明确性,Definiteness) | 算法的每一步都有确定的含义,不会出现二义性 |
可行性(有效性,Effectiveness) | 算法的每一步都是清除且可行的,能让用户用纸笔计算而求出答案 |
(一)冒泡排序
1.基本思想:通过对待排序序列从前向后,依次比较相邻元素的排序码,若发现逆序则交换,使排 序码较大的元素逐渐从前部移向后部
因为在排序过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个标志swap判断元素是否进行过交换。从而减少不必要的比较
2.结束条件:在任何一趟进行过程中,未出现交换
例如:将序列45,46,95,2,58,56,49,23,12,10用冒泡排序方式进行排序
public class BubbleSortTest { public static void main(String[] args) { int[] arr = new int[] {45,46,95,2,58,56,49,23,12,10}; for(int i = 0;i<arr.length-1;i++) {//比较的轮数 for(int j = 0;j<arr.length-1-i;j++) { /*j<arr.length-1-i * 推导过程: * 当 i=0,进行第一轮排序,共10个元素,所以共需交换9次(10-1-0) * 当 i=1,进行第二轮排序,共9个元素 ,所以共需交换8次(10-1-1) * 当 i=2,进行第三轮排序,共8个元素 ,所以共需交换7次(10-1-2) * ....... */ if(arr[j] > arr[j+1]) { int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } for(int i = 0;i<arr.length;i++) { System.out.print(arr[i]+"\t"); } } }
(二)快速排序
快速排序通常明显比同为O(nlogn)的其他算法快,因此常被采用,而且快排采取了分治法的思想,所以在很多面试笔试中能经常看到快排的影子。
快速排序(Quick Sort)由图灵奖获得者Tony Hoare发明,被列为20世纪十大算法之一,是迄今为止所有内排序算法中速度最快的一种。冒泡排序的升级版,交换排序的一种。快速排序的时间复杂度为O(nlog(n));
四、数组中涉及的常见算法:排序算法性能对比
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
插入排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
希尔排序 | O(n^(1.3)) | O(n²) | O(n) | O(1) | 不稳定 |
选择排序 | O(nlog2(n)) | O(n²) | O(n²) | O(1) | 不稳定 |
堆排序 | O(nlog2(n)) | O(nlog2(n)) | O(nlog2(n)) | O(1) | 不稳定 |
冒泡排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
快速排序 | O(nlog2(n)) | O(n²) | O(nlog2(n)) | O(nlog2(n)) | 不稳定 |
归并排序 | O(nlog2(n)) | O(nlog2(n)) | O(nlog2(n)) | O(n) | 稳定 |
计数排序 | O(n+k) | O(n+k) | O(n+k) | O(n+k) | 稳定 |
桶排序 | O(n+k) | O(n²) | O(n) | O(n+k) | 稳定 |
基数排序 | O(n*k) | O(n*k) | O(n*k) | O(n+k) | 稳定 |
(一) 各种内部排序方法性能比较
1.从平均时间而言:快速排序最佳。但在最坏情况下时间性能不如堆排序和归并排序
2.从算法简单性看:由于直接选择排序、直接插入排序和冒泡排序的算法比较简单,将其认为是简单算法。对于Shell排序、堆排序、快速排序和归并排序算法,其算法比较复杂,认为是复杂排序
3.从待排序的记录数n的大小看:n较小时,宜采用简单排序;而n较大时采用改进排序
(二)排序算法的选择
1.当n较小(如n<=50),可采用直接插入或直接选择排序
2.若文件初始状态基本有序(指正序),则应选用直接插入、冒泡或随机的快速排序为宜
3.若n较大,则应采用时间复杂度为O(nlogn)的排序方法:快速排序、堆排序或归并排序