排序算法在一些算法 思想中会经常使用到下面就对一些常用的排序算法做一个记录,常见的排序算法可以分为:
比较类排序:通过比较来决定元素的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
非比较类排序:不通过比较来确定元素的次序,可以突破基于比较的时间下界,时间是线性的。因此也叫线性时间非比较排序
比较信息等可以参考下图,图片来自牛客网:
稳定:排序结果不受元素之间的相对位置限制,既a在b前面,且a=b,排序后a任然在b前面。
时间复杂度O() 即从序列的初始状态到经过排序算法的变换移位等操作变到最终排序好的结果状态的过程所花费的时间度量。
空间复杂度O() 就是从序列的初始状态经过排序移位变换的过程一直到最终的状态所花费的空间开销。
冒泡排序算法是把较小的元素往前调或者把较大的元素往后调。这种方法主要是通过对相邻两个元素进行大小的比较,根据比较结果和算法规则对该二元素的位置进行交换,这样逐个依次进行比较和交换,就能达到排序目的。
冒泡排序的基本思想是,
public static int[] BubbleSort(int[] array) {
if(array.length<=1) return array;
for(int i = 0;i<=array.length-1;i++) {
//method1
for(int j=i;jarray[j]) {
array = swap(array,i,i+1);
}
}
//method2
for(int j = 0;jarray[j+1]) swap(array,j,j+1);
}
return array;
}
private static int[] swap(int[] arr ,int a,int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
return arr;
}
JavaScript实现
function bubbleSort(arr){
let len = arr.length;
for(let i = 0;i
经过两次比较,是稳定的排序算法 因此平均、最坏时间复杂度均为O(n^2),最好时间复杂度O(n), 空间复杂度O(1)
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最坏) | 空间复杂度 | 稳定性 |
冒泡 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 |
选择排序算法的基本思路是首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。
使用这种排序时,要注意其中一个不同于冒泡法的细节。
举例说明:序列58539.我们知道第一遍选择第1个元素“5”会和元素“3”交换,那么原序列中的两个相同元素“5”之间的前后相对顺序就发生了改变。因此,我们说选择排序不是稳定的排序算法,它在计算过程中会破坏稳定性。
public static int[] selectionSort(int[] arr) {
int len = arr.length;
int minPoint,temp;
for(int i = 0;i
JavaScript实现
function selectionSort(arr){
let len = arr.length;
if(len<=1) return arr;
let minPoint;
for(let i=0;i
选择排序的结果不稳定,任何情况下时间复杂度永远是O(n^2),所以数量较小时速度处理较快,但是空间复杂度较小
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最坏) | 空间复杂度 | 稳定性 |
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
不稳定可以在排序数组中添加两个相同的数字,出现以下结果
插入排序算法是基于某序列已经有序排列的情况下,通过一次插入一个元素的方式按照原有排序方式增加元素。
这种比较是从该有序序列的最末端开始执行,
我们认为插入排序也是一种稳定的排序方法。插入排序分直接插入排序、折半插入排序和希尔排序3类
//method1
private static int[] DirectInsertSort(int[] array) {
if(array.length<=1) return array;
for(int i=0;i0&&temp
JavaScript实现
//插人排序
//基本思想:在序号i之前的元素(0到i-1)已经排好序,
//本趟需要找到i对应的元素x (此时即arr[i]) 的正确位置k,
//在寻找位置k的过程中与序号i-1到0的元素依次进行比较。
//如果x小于比较元素,则比较元素向后移动一位;否则,结束移位,
//将x插入当前位置k
function insertSort(arr){
let len = arr.length;
if(arr.length<=0) return ;
for(let i = 1;i=0;j--){
if(arr[j]>temp){
//插入元素小于比较元素 比较元素则向后移动一位
arr[j+1]=arr[j];
}else{
//否则结束移位
break;
}
}
arr[j+1]=temp;
}
return arr;
}
console.log(insertSort([7,3,4,5,10,7,8,2,9,]))
插入排序采用in-palce排序(可以理解为不需要辅助数组,原地排序)
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最坏) | 空间复杂度 | 稳定性 |
插入排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 |
在要排序的一组数中,根据某一增量分为若干子序列,并对子序列分别进行插入排序。
然后逐渐将增量减小,并重复上述过程。直至增量为1,此时数据序列基本有序,最后进行插入排序。
将待排序的序列分割成若干个子序列分别进行直接插入排序
public int[] shellSort(int[] arr){
int len = arr.length;
int step ;
for(step = len/2;step>0;step/=2){ //基数为2的希尔排序
for(int i =step;istep-1&&temp0){
//先根据增量排序
for(int i = 0;istep-1&&temp<=str[j-step]) {
str[j]=str[j-step]; //temp小于 前面位数上的值 做交换
j-=step; //步长之间比较
}
str[j] = temp;
//交换大小2
// while(j>step-1&&temp
JavaScript实现
//希尔排序
function shellSort(arr){
let d = arr.length
while(true){
d = Math.floor(d/2)
for(let x = 0;x=0&&arr[j]>temp;j=j-d){
arr[j+d] = arr[j];
}
arr[j+d] = temp;
}
}
if(d==1){
break;
}
}
return arr
}
console.log(shellSort([7, 3, 4, 5, 10, 7, 8, 2]))
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最坏) | 空间复杂度 | 稳定性 |
希尔排序 | O(n^1.3) | O(n^2) | O(n) | O(1) | 不稳定 |
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。
首先考虑下如何将2个有序数列合并。这个非常简单,只要从比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。
/**
* 归并排序
*
* @param array
* @return
*/
public static int[] MergeSort(int[] array) {
if (array.length < 2) return array;
int mid = array.length / 2;
int[] left = Arrays.copyOfRange(array, 0, mid);
int[] right = Arrays.copyOfRange(array, mid, array.length);
return merge(MergeSort(left), MergeSort(right));
}
/**
* 归并排序——将两段有序数组结合成一个有序数组
*
* @param left
* @param right
* @return
*/
public static int[] merge(int[] left, int[] right) {
int[] result = new int[left.length + right.length];
int i = 0,j = 0,k = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
result[k++] = left[i++];
} else {
result[k++] = right[j++];
}
}
while (i < left.length) {
result[k++] = left[i++];
}
while (j < right.length) {
result[k++] = right[j++];
}
return result;
}
JavaScript实现
function merge(left,right){
let result = []
while(left.length>0&&right.length>0){
if(left[0]
归并排序的形式就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的可以得出它在任何情况下时间复杂度均是O(nlogn)。
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最坏) | 空间复杂度 | 稳定性 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
--------2019.8.20 未完待续
参考链接
1、排序算法-百度百科 https://baike.baidu.com/item/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/5399605?fr=aladdin
2、十大经典排序算法(动图演示)
3、菜鸟教程排序算法
4、一文搞定十大排序算法