排序算法
基本概念:
时间复杂度:对数据操作次数的数量级
空间复杂度:算法所需额外空间的数量级
稳定性:将数据进行排序之后,相同数据的相对位置不发生改变
分类:比较类排序和非比较类排序
比较类算法:通过元素间的两两比较进行排序的算法
-
冒泡排序:
最简单的排序算法,进行n轮重复遍历,每一轮进行n次比较选出元素的一个最大/最小值,将剩下元素继续排序,直到剩下一个元素。时间复杂度最差情况:O(n2) 最好情况:O(n)
空间复杂度:O(1),算法稳定性:稳定
代码:
public static void bubble(int[] arr){
int l = arr.length;
for(int i = 0 ; i < l - 1 ; i++){
for(int j = 0 ; j < l - 1 ; j++;){
if(a[j] > a[j] + 1){
//相邻元素当顺序发生错误时,互换
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
-
选择排序
在未排序的元素中选出最小/最大的元素,放在以排序序列的起始/末尾,循环操作直至所有元素已排序时间复杂度最差情况:O(n2) 最好情况:O(n2)
空间复杂度:O(1),算法稳定性:不稳定
代码:
public static void selectSort(int[] arr) {
int l = arr.length;
int min;
for(int i = 0 ; i < l - 1 ; i++) {
min = i;
for(int j = i + 1 ; j < l ; j++) {
if(arr[j] < arr[min]) {
min = j;
}
}
int temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
}
-
插入排序
在未排序的数组里依次选择一个元素,从后往前,找到已排序数组的对应位置并插入时间复杂度最差情况:O(n2) 最好情况:O(n)
空间复杂度:O(1) 算法稳定性:稳定
代码:
public static void insertSort(int[] arr) {
int l = arr.length;
for(int i = 1 ; i < l ; i++) {
int j = i - 1 ;
int p = a[i];
while(j >= 0 && arr[j] > p) {
arr[j + 1] = arr[j];
j--;
}
a[j + 1] = p;
}
}
-
希尔排序
是插入排序的改进版,先定义一个增量,再按照增量划分子序列,对每一个子序列分别进行插入排序,排完序后再缩小增量值,划分子序列进行重复操作,直至增量为1 ,此时,数组基本有序,然后进行最后一次排序得到有序序列,也叫减小增量排序时间复杂度最差情况:O(n2) 最好情况:O(n)
空间复杂度:O(1) 算法稳定性:不稳定
代码
public static void shell(int[] arr) {
int l = arr.length;
for(int i = l / 2 ; i > 0 ;i = i / 2) {
for(int j = i ; j < l ; j++) {
int k = j;
int p = arr[j];
while(k - i >= 0 && p < arr[k - i]) {
arr[k] = arr[k - i];
k = k - i;
}
arr[k] = p;
}
}
}
- 快排
快速排序,顾名思义,就是非常快的排序,也就是时间复杂度会很低,主要思想就是递归,先找到一个基准,将比基准小的都放在基准左边,大的放在右边,再对两边分别进行排序,循环下去,便可达到快速排序的效果
时间复杂度最差情况:O(n2) 最好情况:O(nlog2n)
空间复杂度:O(nlog2n) 算法稳定性:不稳定
代码:
public static void quick(int[] arr , int l , int r) {
int i = l;
int j = r;
int p = arr[i];
if(l >= r) {
return;
}
while(i < j) {
while(j > i && arr[j] >= p) {
j--;
}
while(j > i && arr[i] <= p) {
i++;
}
if(i < j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
arr[l] = arr[i];
arr[i] = p;
quick(arr , l , i - 1);
quick(arr , i + 1 , r);
}
- 归并排序
该排序采用分治的思想,设计的一种排序算法,基本步骤是将子序列排序,然后合并使总的成为一个有序序列
时间复杂度:最好最差都是:O(nlog2n)
空间复杂度:O(n) 用ArrayList做辅助空间
算法稳定性:稳定
代码
public static int[] sort(int[] arr) {
int len = arr.length;
if(len < 2) {
return arr;
}
int mid = len / 2;
int[] l = Arrays.copyOfRange(arr, 0, mid);
int[] r = Arrays.copyOfRange(arr, mid, len);
return merge(sort(l) , sort(r));
}
public static int[] merge(int[] l , int[] r) {
int llen = l.length;
int rlen = r.length;
int lnum = 0 ;
int rnum = 0 ;
List<Integer> list = new ArrayList<Integer>();
while(lnum < llen && rnum < rlen) {
if(l[lnum] < r[rnum]) {
list.add(l[lnum]);
lnum++;
}else {
list.add(r[rnum]);
rnum++;
}
}
if(lnum >= llen) {
for(int i = rnum ; i < rlen ; i++) {
list.add(r[i]);
}
}
if(rnum >= rlen) {
for(int i = lnum ; i < llen ; i++) {
list.add(l[i]);
}
}
int[] result = new int[llen + rlen];
for(int i = 0 ; i < list.size() ; i++) {
result[i] = list.get(i);
}
return result;
}
==说明一下:我们经常会用到Arrays.sort方法,该方法在jdk1.7之前底层使用的就是归并算法,而在jdk1.7之后用的是timsort算法,是一种结合了快排,归并和插入的算法==
非比较类算法:不用通过比较进行排序的算法。
- 基数排序
该算法是根据数组元素的各位上的值进行排序的一种算法,需要先取得最大数的位数作为最大位数,然后从每个数字取出最低位,次低位直至最高位,最后对每一位上的数字进行排序
时间复杂度:最差最好都是O(n * k)
空间复杂度:O(n + k) 算法稳定性:稳定
代码:
public static int max(int[] arr) {
int max = arr[0];
for(int i : arr) {
if(max < i) {
max = i;
}
}
return max;
}
public static void radix(int[] arr) {
int max = max(arr);
int maxDigit = 0;
do {
maxDigit++;
max /= 10;
}while(max > 0);
int n = 1;
int[][] temp = new int[10][arr.length];
int[] count = new int[10];
for(int i = 0 ; i < maxDigit ; i++) {
for(int j = 0 ; j < arr.length ; j++) {
int mod = arr[j] / n % 10;
temp[mod][count[mod]] = arr[j];
count[mod]++;
}
int index = 0;
for(int k = 0 ; k < 10 ; k++) {
if(count[k] != 0) {
for(int l = 0 ; l < count[k] ; l++) {
arr[index] = temp[k][l];
index++;
}
count[k] = 0;
}
}
n *= 10;
}
}
- 桶排序
桶排序是在了解所有元素的一个范围之后,准备和对应数量的桶,使元素在桶中的分布尽量均匀,再将元素按顺序输出,是一种典型的空间换时间方法
时间复杂度:最差为O(n2),最好是O(n)
空间复杂度为O(n+k) 算法稳定性:稳定
代码:
public static int max(int[] arr) {
int max = arr[0];
for(int i : arr) {
if(max < i) {
max = i;
}
}
return max;
}
public static int min(int[] arr) {
int min = arr[0];
for(int i : arr) {
if(min > i) {
min = i;
}
}
return min;
}
public static void bucket(int[] arr) {
int max = max(arr);
int min = min(arr);
int[] buck = new int[max - min + 1];
for(int i = 0 ; i < arr.length ; i++) {
buck[arr[i] - min]++;
}
int index = 0;
for(int i = 0 ; i < max - min + 1 ; i++) {
if(buck[i] != 0) {
for(int j = 0 ; j < buck[i] ; j++) {
arr[index] = i + min;
index++;
}
}
}
}