@Slf4j
class MyProgramApplicationTests {
// 排序数据
int[] arr = {8, 5, 97, 2, 35, 0, 1};
int length = arr.length;
/**
* 冒泡排序(每次都和后面的所有比较如果后面的小就互换位置)
*/
@Test
public void bubblingSort() {
StopWatch watch = new StopWatch();
watch.start("开始");
log.error("排序前:{}", arr);
// 每个元素都和前面的所有元素进行比较,如果前面的大于后面的则替换位置
for (int i = 0; i < length; i++) {
for (int f = i + 1; f < length; f++) {
if (arr[i] > arr[f]) {
int last = arr[i];
arr[i] = arr[f];
arr[f] = last;
}
}
}
log.error("排序后:{}", arr);
log.error("耗时:{}", watch);
}
/**
* 插入排序(根据循环把后面的数据,*依次和已经排序的数据进行比较)首次循环是第二个元素开始,第一个元素做为已排序来比较
*/
@Test
public void insertSort() {
log.error("排序前:{}", arr);
//[8, 5, 97, 2, 35, 0, 1]
// 从第二个数开始遍历
for (int i = 1; i < length; i++) {
int key = arr[i];
int j = i - 1;
// 用前面所有的数进行比较然后排序 直到i前面的数据都排完以后j--后是-1 所以需要把这个元素放在最前
// 1.1 如果没有进入下面循环相当于没改变
// 1.2 进入循环后,j的位置看判断条件,最小则放第一个,一般就在中间j也不等于-1 这样j的值替换掉
// 前面的数大于后面的数时候进行替换
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
log.error("排序后:{}", arr);
}
/**
* 选择排序(每次选择未排序的数据将最小的放在头部)
*/
@Test
public void changeSort() {
log.error("排序前:{}", arr);
//[8, 5, 97, 2, 35, 0, 1]
for (int i = 0; i < length; i++) {
int index=i;
// 第一次最小的就是arr[0]
for (int f = i + 1; f < length; f++) {
// 最小的如果大于后面未排序的就记录他的位置,直到找到最小的为止
if(arr[index]>arr[f]){
index=f;
}
}
if(index!=i){
int now=arr[i];
arr[i]=arr[index];
arr[index]=now;
}
}
log.error("排序后:{}", arr);
}
/**
* 基数排序
* 1.创建10个桶,每个桶里面都是一个list.
* 2.获取数组最大的数字,根据最大数字来判断需要循环几次,按照最大数字的位数来循环的。 while (level<=maxNum) level*=10;
* 3.首先第一次是判断个位的数字
* 4.把所有数按照取余的方式放入桶内[[110, 0, 150, 120, 6000], [1], [2], [], [124], [5, 35], [], [97], [8], [129]]
* 5.将这个二维数组重新变成一个新的一维数组 将level*10 主要下一次是要根据第二位数字取余来放入桶内
* 6.这里各个数字默认都补全了的,比如最大三位数,个位002 十位035
* 7.取十位的时候就重复4-6。[[0, 6000, 1, 2, 5, 8], [110], [120, 124, 129], [35], [], [150], [], [], [], [97]]
* 8.取百位的时候就重复4-6。[[0, 6000, 1, 2, 5, 8, 35, 97], [110, 120, 124, 129, 150], [], [], [], [], [], [], [], []]
* 9.最后一次的时候会把之前排好序的数据重新整理,大的放到指定位置[[0, 1, 2, 5, 8, 35, 97, 110, 120, 124, 129, 150], [], [], [], [], [], [6000], [], [], []]
*/
@Test
public void testBaseNumberSort(){
//[8, 5, 97, 2, 35, 0, 1]
int [] arr={8, 5, 97, 2, 35, 110,0,150, 1,120,6000,129,124};
// 获取最大的数字
int maxNum = Arrays.stream(arr).max().getAsInt();
int bucket=10;
int level=1;
// 创建桶数基本就是10个 0-9
while (level<=maxNum) {
List<List<Integer>> list=new ArrayList<>();
for(int i=0;i<bucket;i++){
list.add(new ArrayList<>());
}
// 第三次 0, 6000, 1, 2, 5, 8, 35, 97,110, 120, 124, 129, 150
for (int str : arr) {
list.get(str/ level % bucket).add(str);
}
log.error("list={}", list);
arr= list.stream().flatMapToInt(itm -> itm.stream().mapToInt(Integer::intValue)).toArray();
level*=bucket;
}
// log.error("list={}", arr);
}
/**
* 快速排序
* 1.理论。以第一个为基数,先右边和基数比对,移动到比基数小的位置,然后左边开始移动到比基数大的位置,两位置重合就是中数的位置
* 1.1 然后把基数和中数位置互换。
* 1.2 然后分成两组,左边是基数往左(0,中位数-1),右边是基数往右(中位数+1,数组长度)
* 1.3 通过多次迭代,就排序好了
* 移动的时候,从小到大是左大 右小。 从大到小就是 左小右大
*/
@Test
public void testFastSort() {
log.error("排序前:{}", arr);
quickSort(arr, 0, arr.length - 1);
log.error("排序后:{}", arr);
}
private void quickSort(int[]arr,int low,int high){
if(low<high){
int center=sort(arr,low,high);
quickSort(arr,low,center-1);
quickSort(arr,center+1,high);
}
}
/**
* 排序并且返回中位数
* @param arr
* @param ks
* @param js
* @return
*/
private int sort(int []arr,int ks,int js){
int baseNum=arr[ks];
int i=ks;
int j=js;
while(i<j){
if(i<j && baseNum<=arr[j]){
j--;
}
if(i<j && baseNum>=arr[i]){
i++;
}
if(i<j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
arr[ks]=arr[j];
arr[j]=baseNum;
return i;
}
/**
* 堆排序
* 1.构建一个大顶堆,先右子节点,右下中选最大的和节点比,如果大于互换,小于不变
* 2.把堆顶点和最后一个节点互换。这里用的是数组长度-1 所以大的就一直在后面
* 3.最后一个是最大数以后,重复上述操作,直到遍历数组那个循环结束
* 4.所有的数字就排列好了
*/
@Test
public void heapSort() {
//[8, 5, 97, 2, 35, 0, 1]
// int []arr={8, 5, 97, 2, 35, 0, 1};
log.error("排序前:{}", arr);
heapSort(arr);
log.error("排序后:{}", arr);
}
private void heapSort(int[] arr) {
int n = arr.length;
// 构建最大堆
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
// 逐个将最大值移到数组末尾
for (int i = n - 1; i > 0; i--) {
// 将当前最大值交换到数组末尾
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
// 重新构建最大堆
heapify(arr, i, 0);
}
}
/**
* 排成大顶堆
* @param arr
* @param n
* @param i
*/
private void heapify(int[] arr, int n, int i) {
int largest=i;//初始化最大索引
int left=2*i+1;//左子节点索引
int right=2*i+2;// 右子节点索引
// 如果左子节点比当前最大值大,则更新最大值的索引
if (left < n && arr[left] > arr[largest]) {
largest = left;
}
// 如果右子节点比当前最大值大,则更新最大值的索引
if (right < n && arr[right] > arr[largest]) {
largest = right;
}
// 如果最大值的索引不是当前节点索引,则交换它们,并继续向下调整堆
if (largest != i) {
int temp = arr[i];
arr[i] = arr[largest];
arr[largest] = temp;
// 递归调整堆
heapify(arr, n, largest);
}
}
/**
* 计算可以瓶盖数量
* 3个瓶盖可以换一瓶饮料
*/
@Test
public void countBottle() {
// 饮料数
int num = 92;
int mark = num;
int sumNum = num;
while (mark > 2) {
// 可以换多少瓶饮料
int a = (mark >= 3) ? mark / 3 : 0;
int b = mark % 3;
mark = a + b;
sumNum += a;
//mark 总的瓶盖
}
log.error("喝了{}瓶,剩余{}个盖子", sumNum, mark);
}
@Test
public void testExcepction() {
int a = 1, b = 0;
Integer d = null;
try {
int e = d + 1;
int c = a / b;
} catch (NullPointerException e) {
System.out.println("错误1");
} catch (Exception ex) {
System.out.println("错误2");
} finally {
System.out.println("结束");
}
}
@Test
public void testMath(){
int x=-4;
int y=2;
log.info("向上取整={}",Math.ceil(2.5));
log.info("向下取整={}",Math.floor(4.5));
log.info("绝对值={}",Math.abs(x));
log.info("x的y次幂={}",Math.pow(x,y));
log.info("最大={}", Math.max(-3,20.5));
log.info("平方根={}",Math.sqrt(y));
log.info("e的y次幂={}",Math.exp(y));
log.info("log为底={}",Math.log(2));
log.info("log10为底={}",Math.log10(10));
log.info("随机数={}",Math.random());
log.info("余数{}",8%10);
List<Integer> list=new ArrayList<>();
list.add(1); list.add(6); list.add(999999);
Integer a[]=list.toArray(new Integer[0]);
log.error("Max={}", Arrays.stream(a).max(Integer::compareTo).get());
log.error("Max={}", list.stream().max(Integer::compareTo).get());
}