前言:
作为一个毕业季的狗子,在已经到来的秋招面前可谓是瑟瑟发抖。在海投简历的过程中,一次又一次的笔试,一次又一次的凉凉早就见怪不怪了。但是排序算法出现的频率真的比较大,所有现在做一个学习及总结,应对接下来的笔试和面试(^ v ^)
首先来一个总的介绍,基本排序算法到底有哪些,不说了,直接上图:
图片来自 https://www.cnblogs.com/onepixel/articles/7674659.html
总结一下:
平均复杂度来分:
快排,堆排,归并是最好的为o(nlog2n),
其次是插入,选择,冒泡较差o(n^2)
计数排序和桶排序一样为o(n+k)
其中快排的最好复杂度为o(nlog2n),最坏为o(n^2),
按稳定性分:
插入,冒泡,归并,计数排序,桶排序,基数排序是稳定的,
选择,快排,堆排,希尔排序不是稳定的
那么如何区分稳定与不稳定?
稳定:如果a=b,排序前顺序为a b, 排序后仍然为 a b
不稳定:如果a=b,排序前顺序为a b,排序后变成 b a
下面将手撕这几个算法,嘿嘿嘿^ v ^
-
冒泡排序
//定义数组 r int[] arr = {5,4,1,3,8,5}; //冒泡排序 for (int i=0;i<arr.length;i++){ for (int k=i;k<arr.length;k++){ int temp; if(arr[i]>arr[k]){ temp = arr[i]; arr[i]=arr[k]; arr[k]=temp; } } }
-
选择排序
int[] arr1 = {5,4,1,3,8,5}; //选择排序 int temp,minindex=0; for (int i=0;i<arr1.length-1;i++){ minindex=i; for(int j=i+1;j<arr1.length;j++){ if(arr1[minindex]>arr1[j]){ minindex = j; } } temp = arr1[minindex]; arr1[minindex] = arr1[i]; arr1[i] = temp; }
-
插入排序
//插入排序 int[] arr2 = {5,4,1,3,8,5}; int current,preindex; for (int i =1;i<arr2.length;i++){ preindex = i-1; current=arr2[i]; while(preindex>=0&¤t<arr2[preindex]){ arr2[preindex+1]=arr2[preindex]; preindex--; } arr2[preindex+1] = current; }
-
希尔排序
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:
选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
按增量序列个数k,对序列进行k 趟排序;
每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
function shellSort(arr) {
var len = arr.length;
for (var gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
for (var i = gap; i < len; i++) {
var j = i;
var current = arr[i];
while (j - gap >= 0 && current < arr[j - gap]) {
arr[j] = arr[j - gap];
j = j - gap;
}
arr[j] = current;
}
}
return arr;
}
-
归并排序:
把一个长度为n的子序列分为长度为n/2的两个子序列
然后对两个子序列进行归并排序
最后对得到的子序列合并成一个序列
列如对2,1,4,6进行归并排序
第一趟:2,1 排列1,2
第二趟:4,6 排列4,6
第三趟: 1 2 4 6排列 1 2 4 6 -
快速排序
例如有如下8 10 6 1 3 4 15 的整数序列,利用快排进行排序,假设以第一个数8为基准,head,end分别指向第二个和最后一个数字的下标
第一次排序:从后往前数,end–,4<8,故4与8交换位置,数列为4 10 6 1 3 8 15,再从前往后数head++ 10>8,
10与8交换位置,变为4 8 6 1 3 10 15,再次从后往前数,3<8,交换4 3 6 1 8 10 15
然后再从前往后数,发现6,1都小于8,最后end==head结束第一次排序,结果为4 3 6 1 8 10 15
8左边的数小于8,8右边的数大于8,最后对两边再进行快排。
public class Main {
public static void main(String[] args) throws InterruptedException{
int[] arr = {2,1,4,0,5,6,3,8};
int low = 0;
int high = arr.length-1;
System.out.println("快排算法");
System.out.println("排序之前");
for (int i:arr){
System.out.print(i+"\t");
}
quikSort(arr,low,high);
System.out.println("排序之后");
for (int i:arr){
System.out.print(i+"\t");
}
}
public static void quikSort(int[] arr,int low,int high){
//递归出口
if(low>high){
return;
}
//标记
int i = low;
int j = high;
int key = arr[low];
while(i<j){
//从后往前
while (i<j&&arr[j]>=key){
j--;
}
while (i<j&&arr[i]<=key){
i++;
}
int temp = arr[i];
arr[i] = arr[j];
arr[j]=temp;
}
int temp = arr[i];
arr[i]=arr[low];
arr[low]=temp;
quikSort(arr,low,i-1);
quikSort(arr,i+1,high);
}
}