1 选择排序SelectionSort
最简单,也有优化空间
如何计算时间和空间复杂度
算法的验证 随机数据生成器 对数器
写算法程序的哲学
思想:就是先找到最小的放到第一个(第一个原本的和最小的互换),在找第二小的
for(int i=0:i<arr.length-1;i++){
int minpos=i;//假设当前第一个就是最小的
for(int j=i+1;j<arr.length;j++){
if(arr[j]<arr[minpos])
minpos=j;//取出最小的那个数的位置,找出了下来进行交换
}//这里可能小伙伴们会疑惑为什么不直接交换数据,反而先找索引了。
因为假如是从第一个数开始的,他需要从前往后一直比较。如果碰到一个比它小的就交换值 ,太麻烦了 。时间上没有交换索引块。
if(minpos!=i)
int temp=arr[i];
arr[i]=arr[minpos];
arr[minpos]=temp;
}
冒泡排序移动数据有3条赋值语句,而选择排序的交换位置的只有1条赋值语句,因此在有序度相同的情况下,冒泡排序时间复杂度是选择排序的3倍,所以,选择排序性能更好
(原因就在与进行位置索引,交换,简单)
选择排序,可以优化 ,后面的一次循环,可以找到一个最小值,同时找到一个最大值,最小值放前面,最大值放后面
https://www.bilibili.com/video/BV14i4y1T7Af?p=7
后续:1 独立完成代码编写 2如何验证
3思考还有没有优化的空间
4写一个程序证明选择排序不稳定
2 冒泡排序 BubbleSort
public class BubbleSort {
public static void bubbleSort(int [] arrs) {
for (int i = arrs.length - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (arrs[j] > arrs[j+1]) {
int temp = arrs[j];
arrs[j] = arrs[j+1];
arrs[j+1] = temp;
}
}
}
}
public static void main(String[] args) {
int [] a = new int [] {9, 5, 1, 2, 7, 3, 4, 8, 6};
BubbleSort.bubbleSort(a);
// 打印展示排序结果
Arrays.stream(a).forEach(System.out::println);
}
}
思路:升序就是每一循环结束,把最大的放最后(它是相邻的相互交换)
作业:独立完成冒泡排序并验证,并修改算法,使其最好复杂度为0(n)
最好的情况下时间复杂度两个for循环是n的平方,为什么结论是n,如何进行优化得到n,好像可以优化进行提前结束。
3 插入排序(InsertionSort)
对于基本有序的数组最好用
稳定
1.冒泡排序和插入排序的时间复杂度都是 O(n^2),都是原地排序算法(就是排序过程中不申请过多的存储空间,只利用原来存储的待排数据的存储空间进行比较和交换),为什么插入排序要比冒泡排序更受欢迎呢?
public class InsertionSort {
public static void sort(int [] arrs){
// 1、循环购买玩具:模拟玩具的增加过程
for (int i = 0; i < arrs.length; i++) { // 从左到右 --> 循环
// 2、对自己已有的玩具进行排序
// for(int j = 0; j < i; j++) { // 和循环同向-数据比较:部分数据位置错乱!-数据交换位置
for(int j = i-1; j >= 0; j--) { // 数据比较--> 从右往左
// 3、对玩具进行喜爱程度(数字大小)排序:交换数据--> 正确的结果
if (arrs[j] > arrs[j+1]) {
// 交换数据/玩具
int temp = arrs[j];
arrs[j] = arrs[j+1];
arrs[j+1] = temp;
}
}
}
}
public static void main(String[] args) {
int [] a = new int [] {10, 8, 100, 78, 66, 33, 88};
InsertionSort.sort(a);
Arrays.stream(a).forEach(System.out::println);
}
}
4 快速排序(QuickSort)
算法的思想:采用分治法(将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。)
求解:从整个数组中随机挑选一个元素作为基准,数组中小于基准的元素全部移到左边,大于的移到右边,即以该基准作为分界点。接着便可以按照此思想,递归的处理左边部分数组和右边部分数组。
import java.util.Arrays;
/**
* 排序方式:快速排序的操作方式较高
* 空间复杂度O(log n) 时间复杂度(n log n)
*/
public class QuickSort {
public static void sort(int [] a, int left, int right) {
// 设置排序结束的条件
if( left > right ){
return;
}
// 记录左边编号、记录右边编号
int i = left, j = right;
// 记录基准数字
int base = a[left];
// 核心算法
while (i != j){
// 右侧编号查找数字
while(j > i && a[j] >= base) {
j--;
}
// 左侧编号查找数字
while(i < j && a[i] <= base) {
i++;
}
// 数字交换
if(i < j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
// 基准数字 和 i位置数字的交换
a[left] = a[i];
a[i] = base;
// i位置是基准数字,不再参与排序过程
// 左侧数字进行二次分类
sort(a, left, i - 1);
// 右侧数字进行二次分类
sort(a, i + 1, right);
}
//这个是方法的重载 ,参数和上面那个不一样。
public static void sort(int [] a){
sort(a, 0, a.length-1);
}
public static void main(String[] args) {
int [] a = {5,2,12,6,67,3,2,3,6,5,23,243,32,567,67,878,3,34,6,6,345,23,21,3,45,100,45,23,2,3,45};
QuickSort.sort(a);
System.out.println(Arrays.toString(a));
}
}
```其空间复杂度为log n,时间复杂度为nlog n