排序算法
Java提供了7中常见的排序方法:冒泡、插入、选择、快速、希尔、归并和堆
衡量一些算法的相关属性:时间复杂度、空间复杂度、稳定性
冒泡排序
基本思路: 从第一个元素开始比较相邻的两个元素,如果第一个比第一个大或小,就互换它们的位置,这样先比较完一次,然后抛弃最大或最小的继续比较,直到排序完成。
具体实现:
{4,2,3,5,7,6,8,1,9}
i = 0 k = 1 (定义两个变量代表数组下标)
自然排序(从小到大)
最简单的方法就是嵌套循环(for循环) 利用这个想法 大致描述一下排序过程
外层循环由 i 控制(i代表数组下标)从1开始 i < arr.length
外层循环控制的其实就是内层比较的次数 跟排序本身没有任何关系
里层循环 k 从0开始遍历 k < arr.length-i 如果arr[k] > arr[k+1]
那么两个元素互换 然后执行k++ 继续比较arr[k]和arr[k+1]
如果arr[k] <= arr[k+1] 不互换元素 直接进行k++ 操作
这样循环比较 直到内层第一次循环比较结束
第一次循环结束后就可以找出数组中最大的元素 那么下次比较的时候就可以跳过这个最大的元素
所以内层控制的范围应该是k < arr.length - i
第一次循环结束后 外层循环 i++ 内层循环继续比较
这样一直执行上述循环操作 直到外层循环结束 输出结果就是最后排好序的数组
实现
public static void main(String[] args){
int[] arr = generArray(10);
bubblSort(arr);
showArray(arr);
}
//冒泡排序
public static void bubblSort(int[] arr) {
for (int i = 1; i < arr.length; i++) { //外层循环
for (int k = 0; k < arr.length - i; k++) { //内存循环
if (arr[k] > arr[k + 1]) { //满足条件则互换两个元素的值
int temp = arr[k + 1];
arr[k + 1] = arr[k];
arr[k] = temp;
}
}
}
}
//定义随机数组
public static int[] generArray(int len) {
int[] res = new int[len];
for (int i = 0; i < res.length; i++) {
res[i] = (int) (Math.random() * 100);
}
return res;
}
//定义方法 显示输出数组
public static void showArray(int[] arr) {
System.out.println(Arrays.toString(arr));
}
稳定性
在冒泡排序中,遇到相等的值,是不进行交换的,只有遇到不相等的值才进行交换,所以是稳定的
排序方式。
时间复杂度
冒泡排序最好的时间复杂度为O(n)。
适用场景
冒泡排序适用于数据量很小的排序场景,因为冒泡的实现方式较为简单。
快速排序
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)
本质上看,快速排序应该算是在冒泡排序基础上的递归分治法
基本操作步骤:
-
从数组中挑出一个元素,称为基准(pivot)
-
重新排序数组,所有元素比基准小的放在基准前面,所有元素比基准值大的摆在基准的后边 相同的数可以到任一边。在这个分区退出后,该基准就处于数组的中间位置。这个称为分区(patition)操作
-
递归(recursive)把小于基准元素的子数列和大于基准元素的子数列排序
具体实现
[4,7,1,8,10,6,5,3,7,9]
pivot = 4 start = 0 end = 9
low = 0 high = 9 pivot = 4 = arr[low]
首先从高端部分开始比较,保证高端部分比pivot大。如果值比4大,则high--
high = 7 此时high指针执行的值比pivot小, arr[low] = arr[high]
[3,7,1,8,10,6,5,3,7,9] low = 0 high = 7 pivot = 4
开始低端比较,从low执行的数据开始进行比较,直到有数据比pivot大为止
如果low指向的数据比pivot小,则low++
low = 1时对应的数据为7,比pivot大,则 arr[high] = arr[low]
[3,7,1,8,10,6,5,7,7,9] low = 1 high = 7 pivot = 4
一轮比对完成的结束条件应该是low >= high,当前low = 1 < high = 7
继续高端比较,比较方式同第一次高端比较
high-- 具体值为2,arr[high] < pivot,所有需要赋值
[3,1,1,8,10,6,5,7,7,9] low = 1 high = 2 pivot = 4
继续低端比较low low++
此时low = high,本次循环结束,回存基准值
[3,1,4,8,10,6,5,7,7,9] 可以发现在4左端的所有数据都比4小,而4右端的数据都比4大
---
将原始数组分为2部分继续排序
arr 0----2
arr 3----9
以左端为例[3,1,4]
low = 0 high = 2 pivot = 3 = arr[low]
4 > 3 所以high-- low = 0 high = 1
arr[high] < pivot 所以进行修改操作arr[low] = arr[high],所以[1,1,4] low = 0 high = 1
pivot = 3
比较低端,如果值小则low++ low = 1 high = 1 pivot = 3
此时low和high重合,则进行结束循环并赋值[1,3,4]
---
重复上述操作
具体编码实现
public class Test1 {
public static void main(String[] args) {
int[] arr=new int[] {3,7,1,8,10,6,5,3,7,9};
quickSort(arr, 0, arr.length-1);
for(int tmp:arr) {
System.out.print(tmp+"\t");
}
}
public static void quickSort(int[] arr,int start,int end) {
if(start<end) {
int pivot=arr[start];
int low=start;
int high=end;
while(low<high) {
while(low<high && arr[high]>=pivot) {
high--;
}
arr[low]=arr[high];
while(low<high && arr[low]<=pivot) {
low++;
}
arr[high]=arr[low];
}
arr[low]=pivot;
quickSort(arr, start, low-1);
quickSort(arr, low+1, end); //递归调用自身进行下一次排序
}
}
}