什么是排序
排序是按照某种顺序排列元素的一种算法。
为什么需要排序
排序是计算机科学中的重要算法,排序有时可以显著降低问题的复杂度,可以使用排序作为减少查找复杂度的一种技术。
排序的分类
排序算法通常基于以下参数分类。
- 比较的次数
- 交换的次数
- 内存使用
- 递归
- 稳定性
- 适应性
内部排序:在排序时仅使用主存储器的排序算法称为内部排序。
外部排序:在排序时需要使用磁带或磁盘等外部存储器的排序算法属于外部排序算法。
排序算法
插入排序
基本思想:每次从输入数据中移除一个元素并将其插入已排序序列的正确位置,直至所有输入元素都插入有序序列中。插入有序序列时,使用未排序元素i与已排序序列j=i-1进行比较,如果i<j,则j=j+1依次向后移动一位,继续比较,如果小于,将已排序序列继续后移,否则则将i插入到已排序序列。如果i>j,将i直接插入已排序序列。注意,第一个元素默认为已排序序列。
算法实现:
private static void insertSort(int[] arr){
for(int i = 1; i < arr.length ; i++){
int j=i-1;
int x=arr[i];
//比较的时候不比较最前
while(j >= 0 && x < arr[j]){ //使用短路与做临界判断
arr[j+1]=arr[j];
j--;
}
arr[j+1]=x;
}
}
算法复杂度: O(n*n)
冒泡排序
基本思想:迭代的对输入序列中的第一个元素到最后一个元素进行两两比较,当需要时交换两个元素位置。最小的元素被交换到数组前部分,形成已排序序列,外层变量i表示未排序的开头元素,从数组开头想末位移动,内层变量j用于对未排序序列中的相邻两元素进行两两比较,从数组末尾N-1开始,减少到i+1结束。
算法实现:
public static void bubbleSort(int[] a){
int n=a.length;
for(int i=0;i<=n-1;i++){
for(int j=n-1;j>i;j--){
if(a[j]<a[j-1]){
int x=a[j];
a[j]=a[j-1];
a[j-1]=x;
}
}
}
}
算法复杂度:O(n*n), 稳定排序
选择排序
基本思想:将待排序序列分为已排序序列和未排序序列,寻找未排序序列中的最小元素,将其插入到已排序序列的下一位,形成已排序序列。未排序序列中寻找最小值,未排序序列的第一位元素看做最小值,分别与后面的元素比较,如果还有最小值,则从使用新的最小值继续与后面的元素进行比较,找到最小值后将其放到已排序序列的后一位,形成排序序列。
算法实现:
private static void selectSort(int[] a){
int n=a.length;
for(int i=0;i<n-1;i++){
int min= i;
for(int j=i+1;j<n;j++){
if (a[j] < a[min]) // 找出未排序序列中的最小值
{
min = j;
}
}
if (min != i)
{
Swap(a, min, i); // 放到已排序序列的末尾,该操作很有可能把稳定性打乱,所以选择排序是不稳定的排序算法
}
}
}
private static void Swap(int[] a, int i, int j)
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
算法复杂度:O(n*n), 不稳定排序
希尔排序
基本思想:比较和交换数组中每个距离为h的元素,如果h=1,则其和插入排序一样。
算法实现:
归并排序
基本思想:归并排序将输入序列分成两部分并递归处理每一部分。当子问题解决后,算法又将子问题的解合并。
堆排序
基本思想:堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
快速排序
基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
树排序
基本思想:使用给定数组元素创建一个二叉搜索树,中序遍历给定的二叉搜索树并生成有序数组。
线性排序算法
计数排序
基本思想:对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数(此处并非比较各元素的大小,而是通过对元素值的计数和计数值的累加来确定)。一旦有了这个信息,就可以将x直接存放到最终的输出序列的正确位置上。
桶排序
基本思想:将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。
基数排序
基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
拓扑排序
基本思想:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。