基础算法-排序(选择&冒泡&快排)
基本概念
选择排序
核心思路
选择排序和插入排序相似,也分已排序区间和未排序区间,选择排序每次会从未排序区间中找到最小元素,将其放到已排序区间的末尾,但是不想插入排序那样移动数组,选择排序会每次进行交换
4 5 6 3 2 1
第一次 1 5 6 3 2 4
第二次 1 2 6 3 5 4以此类推
代码实现
package Sort;
import java.util.Arrays;
public class SelectSort {
public static void main(String[] args) {
int a[]={55,65,98,78,458,62,32,14,578,210,21};
Slectsort(a);
System.out.println(Arrays.toString (a));
}
//选择排序
public static void Slectsort(int a[]){
for (int i=0;i<a.length-1;i++){
int local=i;
for (int j=i+1;j<a.length;j++){
if (a[j]<a[local]){
local=j;
}
}
if(local!=i){
swap(a,i,local);
}
}
}
//完成数组两元素间交换
public static void swap(int[] arr,int a,int b){
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}
分析
时间复杂度:O(n^2)
空间复杂度:O(n)
交换次数:n
稳定性:不稳定
冒泡排序
核心思路
冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩互换,一次冒泡会让至少一个元素移动到它应该在的位置,重复n次,就完成了n个数据的排序工作。
4 5 6 3 2 1
第一次冒泡结果:4 5 6 3 2 1=>4 5 3 6 2 1=>4 5 3 2 6 1=>4 5 3 2 1 6
第二次冒泡结果:4 5 3 2 1 6=>4 3 5 2 1 6=>4 3 2 5 1 6=>4 3 2 1 5 6
第三次冒泡结果:4 3 2 1 5 6=>3 4 2 1 5 6=>3 2 4 1 5 6=>3 2 1 4 5 6
第四次冒泡结果:3 2 1 4 5 6=>2 3 1 4 5 6=>2 1 3 4 5 6
第五次冒泡结果:2 1 3 4 5 6=>1 2 3 4 5 6
代码实现
package Sort;
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int data[]={4,5,6,3,2,1};
bubbleSort(data);
System.out.println(Arrays.toString(data));
}
public static void bubbleSort(int arr[]){
int n=arr.length;
for (int i=0;i<n-1;i++){ //冒泡排序的次数n-1
boolean flag = true; //加一个标记
for (int j=0;j<n-1-i;j++){ //冒泡实现j=n-1-i是因为每冒泡一次都会确定一个数的位置
if (arr[j]>arr[j+1]){ //当不执行此条if语句时,说明冒泡排序没有进行本身顺序就是排好的flag依然为true从下边if语句中跳出外层循环没必要再进行冒泡
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
flag =false;
/*
* arr[j]=arr[j]+arr[j+1];
* arr[j+1]=arr[j]-arr[j+1];
* arr[j]=arr[j]-arr[j+1];
*/
}
}
if (flag){ //if()括号里条件为true才会执行
break;
}
}
}
}
分析
时间复杂度:O(n^2)
空间复杂度:O(n)
交换次数:交换次数还是比较多的
稳定性:稳定
快速排序
核心思路
45 28 80 90 50 16 100 10
基准数:一般就是取要排序序列的第一个
第一次的基准数:45
从序列的后边往前找,找到比基准数小的数进行对换:
10 28 80 90 50 16 100 45
从序列的前边往后边找比基准数大的进行对换
10 28 45 90 50 16 100 80
重复执行以上操作
10 28 16 90 50 16 100 80
10 28 16 45 50 90 100 80
以基准数分为3部分,左边的比基准数小,右边的比基准数大
{10 28 16} 45 {50 90 100 80}
到此第一次以45位基准数的排序完成了
代码实现
package Sort;
import java.lang.reflect.Array;
import java.util.Arrays;
public class QuicklySort {
public static void qSort(int data[],int left,int right){// left表示左边从哪开始,right表示右边在哪开始
int base =data[left]; //去基准书为每段序列的第一个数
int ll=left; //表示从左边找的位置
int rr=right; //表示从右边找的位置
while (ll<rr){ //ll=rr时表示以某数为基准数的交换就找完了
//第一步:从后边往前找比基准数小的数
while (ll<rr && data[rr]>=base){ //data[rr]<base时跳出循环
rr--;
}
if (ll<rr){ //表示找到有比基准数小的数
int temp=data[rr];
data[rr]=data[ll];
data[ll]=temp;
ll++; //此处ll++是每次交换完后下次比较时从下一个位置的数开始
}
//第二步:从前边往后找比基准数大的数
while (ll<rr && data[ll]<=base){ //data[rr]>base时跳出循环
ll++;
}
if (ll<rr){ //表示找到有比基准数大的数
int temp=data[rr];
data[rr]=data[ll];
data[ll]=temp;
rr--;
}
}
//递归分成三部分,左右继续快排直到完成
if(left<ll){ //加上判断left和ll大小防止没找到,及基准数为最小的那个数
qSort(data, left,ll-1); //进行完一轮后分为三部分:ll=rr对应的是23行循环终止时ll和29行rr的值(即此次快排基准数的位置),
}
if (right>rr){ //加上判断right和rr大小防止没找到,及基准数为最大的那个数
qSort(data, rr+1, right);
}
}
public static void main(String[] args) {
int a[]={45, 28, 80, 90, 50, 16, 100, 10};
qSort(a, 0, a.length-1);
System.out.println(Arrays.toString(a));
}
}
分析
时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:不稳定
图解
快排和归并的对比
1.归并排序处理过程是由下到上,先处理子问题,然后合并
2.快排是从上到下,先分区,再处理子问题不用合并
快排的优化就是优化基准数的选择
1.取三个数的中间
各种排序对比
对比
选择各种排序方法
1.分析场景:稳定还是不稳定
2.看数据量:数据量很小的时候有限选择插入排序,比如就50个100个数
3.分析空间
综上所述:没有一个固定的排序算法,都是根据场景需求分析,如果不会分析就用归并和快排
C++和java中的应用
C++中qSort中用的快排加插入排序
jdk里面的arrays.sort 一种是基础数据类型:int double 用的是快排, 对象排序:用的是归并+timeSort (timeSort是对归并的优化)