四种排序算法
今天复习了插入,选择,冒泡,快速四种排序算法
首先列出各种算法的复杂度
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
插入排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
选择排序 | O(n²) | O(n²) | O(n²) | O(1) | 不稳定 |
冒泡排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
快速排序 | O(nlog₂n) | O(n²) | O(nlog₂n) | O(nlog₂n) | 不稳定 |
稳定性:如果原本a在b前面而a=b排序后a是否仍在b前面
java的代码实现
1.插入排序
1.1基本思想
- 以第一个元素为基准默认第一个数字已经有序
- 取下一个元素,并且记录
- 从取到的元素位置向前找直到找到元素应该存在的位置
- 通过前移或者后移将该位置空出
- 将取出的元素存放的适合的位置
1.2代码实现
public static void sort(int arr[]){
int i,j;
//以第一个元素为基准默认第一个数字已经有序
for ( i = 1; i < arr.length; i++) {
//取下一个元素,并且记录
int temp = arr[i];
//从第i个位置开始向前找直到找到该元素应该存在的位置
//该位置根据从小到大或者从大到小的不同判定也不同
//在这里是从小到大
for ( j = i; j > 0&& temp<arr[j-1]; j--) {
//如果temp小于j-1个元素则将元素后移
//j的位置就是temp应该在的位置依次向前找
arr[j] = arr[j-1];
}
//将temp插入到正确的位置
arr[j] = temp;
}
for (int k = 0; k < arr.length; k++) {
System.out.println(arr[k]);
}
}
2.选择排序
2.1基本思想
- 默认当前数是最小数记录下标
- 从当前数字开始向后找直到找到最小数的下标
- 若最小数位置不对则交换
- 该算法默认前面的数字总是有序
2.2代码实现
public static void sort(int arr[]){
int temp=0;
//一共比较n次
for (int i = 0; i < arr.length; i++) {
//认为目前的数就是最小的,记录最小数的下标
int minIndex=i;
//从i+1开始比较到最后一共
for(int j=i+1;j<arr.length;j++){
//比较大小总是记录最小数值的大小
if(arr[minIndex]>arr[j]){
minIndex = j;
}
}
//最小数位置不对则交换前i个数字总是有序
if (i != minIndex) {
temp = arr[i];
arr[i]=arr[minIndex];
arr[minIndex] = temp;
}
}
}
3.冒泡排序
3.1基本思想
该算法要两两相邻比较将最小或者最大数逐渐前移或者后移形成有序序列
3.2代码实现
public static void sort(int[] a){
int temp=0;
//一共要排序n-1次
for (int i = 0; i < a.length-1; ++i) {
//每次要比较n-i-1次
for (int j = 0; j < a.length-i-1; ++j) {
//从小到大排序
// if(a[j]>a[j+1]){
//从大到小排序
if(a[j]<a[j+1]){
temp = a[j];
a[j]=a[j+1];
a[j+1] = temp;
}
}
}
4.快速排序
4.1基本思想
1.找出枢纽
2.分割成两部分
3.递归分别排左边和右边
- 挑选基准值:从数列中挑出一个元素,称为“基准”(pivot),
- 分割:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。在这个分割结束之后,对基准值的排序就已经完成,
- 递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。
将数组分为两部分寻找枢纽
递归排序左数组和右数组
默认将最左边作为枢纽记录
交换比枢纽小的到枢纽左边
比枢纽大的到枢纽右边
全部扫描完成后更改枢纽位置
4.2代码实现
public static void quickSort(int[] arr){
qsort(arr,0,arr.length-1);
}
private static void qsort(int[] arr,int low,int high){
if(low<high){
int pivot = partition(arr,low,high);//将数组分为两部分
qsort(arr,low,pivot-1);//递归排序左数组
qsort(arr,pivot+1,high);//递归排序右数组
}
for (int k = 0; k < arr.length; k++) {
System.out.println(arr[k]);
}
}
private static int partition(int[] arr,int low,int high){
int pivot = arr[low];//把最左边作为枢轴记录
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;
//返回枢轴位置
return low;
}
更详细的注释版本:
package priv.wzb.sort.quicksort;
import priv.wzb.sort.Util;
/**
* @author Satsuki
* @time 2019/9/14 15:50
* @description:
* 1.找出枢纽
* 2.分割成两部分
* 3.递归分别排左边和右边
*/
public class QuickSort03 {
public static void sort(int[] arr){
qsort(arr,0,arr.length-1);
}
//递归排序
public static void qsort(int[] arr,int low,int high){
if (low<high){
//找枢纽的位置
int pivot = partition(arr,low,high);
//递归排序左侧数组
qsort(arr,low,pivot-1);
//递归排序右侧数组
qsort(arr,pivot+1,high);
}
Util.printf(arr);
}
//找出枢纽
//分割数组
public static int partition(int[] arr,int low,int high){
//假设枢纽为数组开头第一个数字
int pivot = arr[low];
//循环条件当左边下标小于右边下标时循环分割数组
//当条件不满足就是左边下标等于右边下标
//也就是找到了pivot枢纽应该存放的位置
//将枢纽归位即可
while (low < high){
//从最右边开始找
//如果右侧数值大于pivot枢纽的数值则继续向前找即可
while (low < high && arr[high]>=pivot){
high--;
}
//当从右边开始找找到了一个小于枢纽并且存在于枢纽右边的数字时
//将该数值扔到枢纽左边
arr[low] = arr[high];
//从右边找完就应该从左边再开始找
//如果左边数值小于pivot则继续向后找
while (low<high && arr[low]<pivot){
low++;
}
//找到一个数值大于枢纽并且在枢纽左边
//扔到枢纽右边
arr[high] = arr[low];
}
//全部循环玩一遍之后当low=high时
//就找到了枢纽应该存在的位置
//就是给枢纽排序了
//枢纽存在位置左边的数字永远小于枢纽
//pivot存在位置右边的数字永远大于pivot
//枢纽归位
//此时的low==high
arr[low] = pivot;
//返回枢纽位置
return low;
}
public static void main(String[] args) {
int[] a = {0,10,9,2,4,6,4,3,1};
sort(a);
}
}
```**加粗样式**