From b55f211d489e2689898c118e747e93bb3506c2cb Mon Sep 17 00:00:00 2001 From: dolyw Date: Fri, 2 Dec 2022 16:18:58 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=97=E6=B3=95-=E5=8D=81=E5=A4=A7=E7=BB=8F?= =?UTF-8?q?=E5=85=B8=E6=8E=92=E5=BA=8F=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Algorithm/.gitignore | 32 +++ Algorithm/HELP.md | 10 + Algorithm/pom.xml | 60 +++++ .../com/algorithm/AlgorithmApplication.java | 19 ++ .../java/com/algorithm/sort/BubbleSort.java | 204 +++++++++++++++ .../java/com/algorithm/sort/BucketSort.java | 154 +++++++++++ .../java/com/algorithm/sort/CountingSort.java | 241 +++++++++++++++++ .../java/com/algorithm/sort/HeapSort.java | 91 +++++++ .../java/com/algorithm/sort/HeapSort2.java | 62 +++++ .../com/algorithm/sort/InsertionSort.java | 167 ++++++++++++ .../java/com/algorithm/sort/MergeSort.java | 199 ++++++++++++++ .../java/com/algorithm/sort/MergeSort2.java | 155 +++++++++++ .../java/com/algorithm/sort/QuickSort.java | 179 +++++++++++++ .../java/com/algorithm/sort/QuickSort2.java | 96 +++++++ .../java/com/algorithm/sort/QuickSort3.java | 113 ++++++++ .../java/com/algorithm/sort/RadixSort.java | 243 ++++++++++++++++++ .../java/com/algorithm/sort/RadixSort2.java | 49 ++++ .../com/algorithm/sort/SelectionSort.java | 189 ++++++++++++++ .../java/com/algorithm/sort/ShellSort.java | 166 ++++++++++++ .../src/main/resources/application.properties | 1 + .../algorithm/AlgorithmApplicationTests.java | 19 ++ .../java/com/example/snow/IdWorkerPatch.java | 6 +- .../config/MqConfirmReturnsConfig.java | 2 +- .../CompletableFutureController.java | 6 +- .../test/java/com/wang/other/TestOther.java | 9 + 25 files changed, 2466 insertions(+), 6 deletions(-) create mode 100644 Algorithm/.gitignore create mode 100644 Algorithm/HELP.md create mode 100644 Algorithm/pom.xml create mode 100644 Algorithm/src/main/java/com/algorithm/AlgorithmApplication.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/BubbleSort.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/BucketSort.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/CountingSort.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/HeapSort.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/HeapSort2.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/InsertionSort.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/MergeSort.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/MergeSort2.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/QuickSort.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/QuickSort2.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/QuickSort3.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/RadixSort.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/RadixSort2.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/SelectionSort.java create mode 100644 Algorithm/src/main/java/com/algorithm/sort/ShellSort.java create mode 100644 Algorithm/src/main/resources/application.properties create mode 100644 Algorithm/src/test/java/com/algorithm/AlgorithmApplicationTests.java diff --git a/Algorithm/.gitignore b/Algorithm/.gitignore new file mode 100644 index 0000000..7ed0d6b --- /dev/null +++ b/Algorithm/.gitignore @@ -0,0 +1,32 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/Algorithm/HELP.md b/Algorithm/HELP.md new file mode 100644 index 0000000..d24fdbb --- /dev/null +++ b/Algorithm/HELP.md @@ -0,0 +1,10 @@ +# Getting Started + +### Reference Documentation +For further reference, please consider the following sections: + +* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) +* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.7.5/maven-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.7.5/maven-plugin/reference/html/#build-image) +* [Spring Boot DevTools](https://docs.spring.io/spring-boot/docs/2.7.5/reference/htmlsingle/#using.devtools) + diff --git a/Algorithm/pom.xml b/Algorithm/pom.xml new file mode 100644 index 0000000..4843a12 --- /dev/null +++ b/Algorithm/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + com.algorithm + Algorithm + 0.0.1-SNAPSHOT + Algorithm + Demo project for Spring Boot + + 1.8 + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/Algorithm/src/main/java/com/algorithm/AlgorithmApplication.java b/Algorithm/src/main/java/com/algorithm/AlgorithmApplication.java new file mode 100644 index 0000000..bfd9024 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/AlgorithmApplication.java @@ -0,0 +1,19 @@ +package com.algorithm; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 算法 + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/22 9:52 + */ +@SpringBootApplication +public class AlgorithmApplication { + + public static void main(String[] args) { + SpringApplication.run(AlgorithmApplication.class, args); + } + +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/BubbleSort.java b/Algorithm/src/main/java/com/algorithm/sort/BubbleSort.java new file mode 100644 index 0000000..2bb2107 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/BubbleSort.java @@ -0,0 +1,204 @@ +package com.algorithm.sort; + +import java.util.Arrays; + +/** + * 冒泡排序 + * + * 比较相邻的元素。如果第一个比第二个大(小),就交换他们两个 + * 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对 + * 这步做完后,最后的元素会是最大(小)的数 + * 针对所有的元素重复以上的步骤,除了最后一个 + * + * 时间复杂度 + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/22 9:52 + */ +public class BubbleSort { + + /** + * 冒泡排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {5, 3, 2, 4, 9, 8, 7, 1, 6}; + + System.out.println("---------- bubbleSort1 ----------"); + bubbleSort1(Arrays.copyOf(array, array.length)); + + System.out.println("---------- bubbleSort2 ----------"); + bubbleSort2(Arrays.copyOf(array, array.length)); + + System.out.println("---------- bubbleSort3 ----------"); + bubbleSort3(Arrays.copyOf(array, array.length)); + + System.out.println("---------- bubbleSort4 ----------"); + int[] array4 = {4, 1, 2, 3, 9, 8, 7, 5, 6}; + bubbleSort4(Arrays.copyOf(array4, array.length)); + } + + /** + * 先写出一轮的冒泡排序处理,冒泡一样的交换位置到最后一位 + * + * 大于就交换位置是从小到大,每次大于后面的值才交换,最后一位是最大值 + * 小于就交换位置是从大到小,每次小于后面的值才交换,最后一位是最小值 + * + * array.length - 1,不然会超出边界,因为 array[j + 1] + * + * 当然也可以是从j = 1开始,j和j - 1进行比较,这样就不用array.length - 1了 + * 大于和小于也需要调换,大于会变成从大到小,小于会变成从小到大 + * 当然这种逆向的理解起来比较复杂一点,第二块代码是逆向的写法 + * + * @param array + */ + private static void bubbleSort1(int[] array) { + print(array); + + for (int j = 0; j < array.length - 1; j++) { + if (array[j] > array[j + 1]) { + int temp = array[j]; + array[j] = array[j + 1]; + array[j + 1] = temp; + } + } + + /*for (int j = 1; j < array.length; j++) { + if (array[j] < array[j - 1]) { + int temp = array[j]; + array[j] = array[j - 1]; + array[j - 1] = temp; + } + }*/ + + print(array); + } + + /** + * 基于一轮的冒泡排序处理,再增加一个外循环 + * 将每个位置的数字都进行一轮冒泡交换 + * 这样一个最基础的冒泡排序就完成了 + * + * 给定一个count记录循环次数 + * + * @param array + */ + private static void bubbleSort2(int[] array) { + print(array); + + // count记录循环次数 + int count = 0; + + for (int i = 0; i < array.length; i++) { + for (int j = 0; j < array.length - 1; j++) { + count++; + if (array[j] > array[j + 1]) { + int temp = array[j]; + array[j] = array[j + 1]; + array[j + 1] = temp; + } + } + } + System.out.println("count: " + count); + + print(array); + } + + /** + * 优化版本,内循环减去i就行了 + * 每次冒泡后到i位置的数字都已经排序好了 + * 所以就没必要重复排 + * + * 可以看到count次数少了一半 + * + * @param array + */ + private static void bubbleSort3(int[] array) { + print(array); + + // count记录循环次数 + int count = 0; + + for (int i = 0; i < array.length; i++) { + for (int j = 0; j < array.length - i - 1; j++) { + if (array[j] > array[j + 1]) { + int temp = array[j]; + array[j] = array[j + 1]; + array[j + 1] = temp; + } + count++; + } + } + + // 还有一种外循环i反过来循环的,意思差不多,就是逆向的 + /*for (int i = array.length - 1; i > 0 ; i--) { + for (int j = 0; j < i; j++) { + count++; + if (array[j] > array[j + 1]) { + int temp = array[j]; + array[j] = array[j + 1]; + array[j + 1] = temp; + } + } + }*/ + System.out.println("count: " + count); + + print(array); + } + + /** + * 优化版本v2,假定数组某些数已经有序 + * 在每轮交换处理可以定一个标记,如果这轮比较都没有交换位置的话 + * 说明数据已经有序,可以直接结束 + * + * 给定一个count记录循环次数 + * 换一个存在某些数有序的数组,可以看到count次数又会变少 + * + * @param array + */ + private static void bubbleSort4(int[] array) { + print(array); + + // count记录循环次数 + int count = 0; + + for (int i = 0; i < array.length; i++) { + // 设定一个标记 + boolean mark = Boolean.TRUE; + + for (int j = 0; j < array.length - i - 1; j++) { + if (array[j] > array[j + 1]) { + int temp = array[j]; + array[j] = array[j + 1]; + array[j + 1] = temp; + mark = Boolean.FALSE; + } + count++; + } + + // 若为true,则表示此次循环没有进行交换 + if (mark) { + // 也就是待排序列已经有序,排序已经完成,直接结束 + break; + } + } + + System.out.println("count: " + count); + + print(array); + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } + +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/BucketSort.java b/Algorithm/src/main/java/com/algorithm/sort/BucketSort.java new file mode 100644 index 0000000..8d510d5 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/BucketSort.java @@ -0,0 +1,154 @@ +package com.algorithm.sort; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 桶排序 + * 适用于存储数的数据范围很小的情况下 + * + * @author wliduo[i@dolyw.com] + * @date 2022/12/01 10:03 + */ +public class BucketSort { + + /** + * 桶排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {5, 12, 10, 9, 6, 9, 7, 9, -9, -8, 5, 7, 8, 5, 6, 6, -6, -5, 7, 9, 8, 5, 15}; + + System.out.println("---------- bucketSort1 ----------"); + bucketSort1(Arrays.copyOf(array, array.length)); + + System.out.println("---------- bucketSort2 ----------"); + bucketSort2(Arrays.copyOf(array, array.length)); + } + + /** + * 桶排序基础版本,指定bucketSize为5 + * 存数时减去最小值,支持负数 + * + * @param array + */ + private static void bucketSort1(int[] array) { + print(array); + + int bucketSize = 5; + int minValue = array[0]; + int maxValue = array[0]; + for (int value : array) { + if (value < minValue) { + minValue = value; + } else if (value > maxValue) { + maxValue = value; + } + } + + int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1; + int[][] buckets = new int[bucketCount][0]; + + // 利用映射函数将数据分配到各个桶中 + for (int i = 0; i < array.length; i++) { + int index = (int) Math.floor((array[i] - minValue) / bucketSize); + buckets[index] = arrAppend(buckets[index], array[i]); + } + + int pos = 0; + for (int[] bucket : buckets) { + if (bucket.length <= 0) { + continue; + } + // 对每个桶进行排序,这里使用了插入排序 + bucket = insertSort(bucket); + for (int value : bucket) { + array[pos] = value; + pos++; + } + } + + print(array); + } + + /** + * 自动扩容,并保存数据 + * + * @param array + * @param value + */ + private static int[] arrAppend(int[] array, int value) { + array = Arrays.copyOf(array, array.length + 1); + array[array.length - 1] = value; + return array; + } + + /** + * 插入排序 + * + * @param array + * @return + */ + private static int[] insertSort(int[] array) { + for (int i = 1; i < array.length; i++) { + int current = array[i]; + int j = i; + while (j > 0 && (current < array[j - 1])) { + array[j] = array[j - 1]; + j--; + } + if (j != i) { + array[j] = current; + } + } + return array; + } + + /** + * 桶排序使用ArrayList实现,指定bucketSize为5 + * ArrayList支持负数存取 + * + * @param array + */ + private static void bucketSort2(int[] array) { + print(array); + + int bucketSize = 5; + List[] buckets = new ArrayList[bucketSize]; + // 初始化 + for (int i = 0; i < buckets.length; i++) { + buckets[i] = new ArrayList(); + } + // 将待排序序列放入对应桶中 + for (int i = 0; i < array.length; i++) { + // 计算对应的桶号 + int index = array[i] / 10; + buckets[index].add(array[i]); + } + // 排序输出 + for (int k = 0, pos = 0; k < buckets.length; k++) { + // 每个桶内进行排序 + buckets[k].sort(null); + for (int j = 0; j < buckets[k].size(); j++) { + array[pos] = (int) buckets[k].get(j); + pos++; + } + } + + print(array); + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/CountingSort.java b/Algorithm/src/main/java/com/algorithm/sort/CountingSort.java new file mode 100644 index 0000000..f47d3bb --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/CountingSort.java @@ -0,0 +1,241 @@ +package com.algorithm.sort; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.PriorityQueue; + +/** + * 计数排序 + * 适用于存储数的数据范围很小的情况下 + * + * @author wliduo[i@dolyw.com] + * @date 2022/12/01 10:03 + */ +public class CountingSort { + + /** + * 计数排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {5, 12, 10, 9, 6, 9, 7, 9, 9, 8, 5, 7, 8, 5, 6, 6, 6, 5, 7, 9, 8, 5, 15}; + + System.out.println("---------- countingSort1 ----------"); + countingSort1(Arrays.copyOf(array, array.length)); + + int[] array2 = {5, 12, 10, 9, 6, 9, 7, 9, -9, -8, 5, 7, 8, 5, 6, 6, -6, -5, 7, 9, 8, 5, 15}; + + System.out.println("---------- countingSort2 ----------"); + countingSort2(Arrays.copyOf(array2, array2.length)); + + System.out.println("---------- countingSort3 ----------"); + countingSort3(Arrays.copyOf(array, array.length)); + + System.out.println("---------- countingSort4 ----------"); + countingSort4(Arrays.copyOf(array2, array2.length)); + } + + /** + * 计数排序基础版本,不稳定,不支持负数 + * 使用最大值计算需要几个bucket + * + * 只用最大值计算这样会导致bucket过大浪费 + * + * @param array + */ + private static void countingSort1(int[] array) { + print(array); + + // 找到最大值计算需要几个bucket + int maxValue = 0; + for (int value : array) { + if (maxValue < value) { + maxValue = value; + } + } + // 创建bucket + int bucketLen = maxValue + 1; + int[] bucket = new int[bucketLen]; + // 遍历数组,将值放入bucket中 + for (int value : array) { + bucket[value]++; + } + // 输出bucket的值 + for (int i = 0, pos = 0; i < bucketLen; i++) { + while (bucket[i] > 0) { + array[pos] = i; + pos++; + bucket[i]--; + } + } + + System.out.println("bucketLen " + bucketLen); + print(array); + } + + /** + * 计数排序优化版本,不稳定,支持负数 + * 使用最大值和最小值计算极值差+1个bucket + * + * 可以看到bucket数量变小了 + * 存数时减去最小值,支持负数 + * + * @param array + */ + private static void countingSort2(int[] array) { + print(array); + + // 找到最大值和最小值计算需要几个bucket + int maxValue = array[0], minValue = array[0]; + for (int value : array) { + if (maxValue < value) { + maxValue = value; + } else if (minValue > value) { + minValue = value; + } + } + // 创建bucket + int bucketLen = maxValue - minValue + 1; + int[] bucket = new int[bucketLen]; + // 遍历数组,将值放入bucket中 + for (int value : array) { + // 优化减小了bucket的大小 + int index = value - minValue; + bucket[index]++; + // bucket[value - minValue]++; + } + // print(bucket); + // 输出bucket的值,按存取的方式取出元素 + for (int i = 0, pos = 0; i < bucket.length; i++) { + // 根据bucket数组中存的次数去取排列好的元素 + while (bucket[i] > 0) { + array[pos] = minValue + i; + pos++; + bucket[i]--; + } + } + + System.out.println("bucketLen " + bucketLen); + print(array); + } + + /** + * 计数排序优化版本v2,利用累加数组做到算法稳定,不支持负数 + * 使用最大值计算需要几个bucket + * + * @param array + */ + private static void countingSort3(int[] array) { + print(array); + + // 找到最大值计算需要几个bucket + int maxValue = 0; + for (int value : array) { + if (maxValue < value) { + maxValue = value; + } + } + // 创建bucket + int bucketLen = maxValue + 1; + int[] bucket = new int[bucketLen]; + // 遍历数组,将值放入bucket中 + for (int value : array) { + bucket[value]++; + } + + print(bucket); + + int[] tempArray = new int[array.length]; + // 利用累加数组计算出元素下标 + for (int i = 1; i < bucket.length; i++) { + bucket[i] = bucket[i] + bucket[i - 1]; + } + + print(bucket); + + // 利用累加数组的方式取出元素,从最后一位开始 + for (int i = array.length - 1; i >= 0; i--) { + // 取出原数组每一位的值 + int value = array[i]; + // 将其-1后得到的就是它的在bucket中的下标 + bucket[value]--; + // 根据bucket加下标得到该元素最终在有序数组中的下标 + int pos = bucket[value]; + // 赋值到新数组对应的下标位置 + tempArray[pos] = array[i]; + } + + System.out.println("bucketLen " + bucketLen); + print(tempArray); + } + + /** + * 计数排序优化版本v3,利用累加数组做到算法稳定,支持负数 + * 使用最大值和最小值计算极值差+1个bucket + * 存数时减去最小值,支持负数 + * + * @param array + */ + private static void countingSort4(int[] array) { + print(array); + + // 找到最大值和最小值计算需要几个bucket + int maxValue = array[0], minValue = array[0]; + for (int value : array) { + if (maxValue < value) { + maxValue = value; + } else if (minValue > value) { + minValue = value; + } + } + // 创建bucket + int bucketLen = maxValue - minValue + 1; + int[] bucket = new int[bucketLen]; + // 遍历数组,将值放入bucket中 + for (int value : array) { + // 优化减小了bucket的大小 + int index = value - minValue; + bucket[index]++; + // bucket[value - minValue]++; + } + + // print(bucket); + + int[] tempArray = new int[array.length]; + // 利用累加数组计算出元素下标 + for (int i = 1; i < bucket.length; i++) { + bucket[i] = bucket[i] + bucket[i - 1]; + } + + // print(bucket); + + // 利用累加数组的方式取出元素,从最后一位开始 + for (int i = array.length - 1; i >= 0; i--) { + // 取出原数组每一位的值 + int value = array[i] - minValue; + // 将其-1后得到的就是它的在bucket中的下标 + bucket[value]--; + // 根据bucket加下标得到该元素最终在有序数组中的下标 + int pos = bucket[value]; + // 赋值到新数组对应的下标位置 + tempArray[pos] = array[i]; + } + + System.out.println("bucketLen " + bucketLen); + // print(array); + print(tempArray); + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/HeapSort.java b/Algorithm/src/main/java/com/algorithm/sort/HeapSort.java new file mode 100644 index 0000000..cd91863 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/HeapSort.java @@ -0,0 +1,91 @@ +package com.algorithm.sort; + +/** + * 堆排序 - 数组实现 + * + * @author wliduo[i@dolyw.com] + * @date 2022/12/01 10:03 + */ +public class HeapSort { + + /** + * 堆排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {10, 8, 12, 9, 5, 3, 7, 1, 6, 4, 2, 11}; + + System.out.println("---------- heapSort ----------"); + + print(array); + + int len = array.length; + + buildHeap(array, len); + + for (int i = len - 1; i > 0; i--) { + int temp = array[0]; + array[0] = array[i]; + array[i] = temp; + + len--; + heapify(array, 0, len); + } + + print(array); + } + + /** + * 构建堆 + * + * @param array + * @param len + */ + private static void buildHeap(int[] array, int len) { + for (int i = (int) Math.floor(len / 2); i >= 0; i--) { + heapify(array, i, len); + } + } + + /** + * 堆调整 + * + * @param array + * @param i + * @param len + */ + private static void heapify(int[] array, int i, int len) { + int left = 2 * i + 1; + int right = 2 * i + 2; + int largest = i; + + if (left < len && array[left] > array[largest]) { + largest = left; + } + + if (right < len && array[right] > array[largest]) { + largest = right; + } + + if (largest != i) { + int temp = array[i]; + array[i] = array[largest]; + array[largest] = temp; + + heapify(array, largest, len); + } + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/HeapSort2.java b/Algorithm/src/main/java/com/algorithm/sort/HeapSort2.java new file mode 100644 index 0000000..d4feb99 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/HeapSort2.java @@ -0,0 +1,62 @@ +package com.algorithm.sort; + +import java.util.Comparator; +import java.util.PriorityQueue; + +/** + * 堆排序 - PriorityQueue实现 + * + * PriorityQueue默认是一个小顶堆 + * 可以通过传入自定义的Comparator函数来实现大顶堆 + * + * https://blog.csdn.net/chuyangxunfeng/article/details/124648524 + * + * @author wliduo[i@dolyw.com] + * @date 2022/12/01 10:03 + */ +public class HeapSort2 { + + /** + * 堆排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {10, 8, 12, 9, 5, 3, 7, 1, 6, 4, 2, 11}; + + System.out.println("---------- heapSort ----------"); + + print(array); + + // PriorityQueue heap = new PriorityQueue(); + // 创建大顶堆,默认小顶堆 + PriorityQueue heap = new PriorityQueue<>(new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return o2 - o1; + } + }); + + for (int i = 0; i < array.length; i++) { + heap.offer(array[i]); + } + + for (int i = 0; i < array.length; i++) { + array[i] = heap.poll(); + } + + print(array); + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/InsertionSort.java b/Algorithm/src/main/java/com/algorithm/sort/InsertionSort.java new file mode 100644 index 0000000..59acbd7 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/InsertionSort.java @@ -0,0 +1,167 @@ +package com.algorithm.sort; + +import java.util.Arrays; + +/** + * 插入排序 + * + * 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列 + * 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置 + * 如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面 + * + * 和打扑克牌类似 + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/22 9:52 + */ +public class InsertionSort { + + /** + * 插入排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {5, 3, 2, 4, 9, 8, 7, 1, 6}; + + System.out.println("---------- insertionSort1 ----------"); + insertionSort1(Arrays.copyOf(array, array.length)); + + System.out.println("---------- insertionSort2 ----------"); + insertionSort2(Arrays.copyOf(array, array.length)); + + System.out.println("---------- insertionSort3 ----------"); + insertionSort3(Arrays.copyOf(array, array.length)); + } + + /** + * 先写出一轮的插入插入处理 + * + * 设定是从第2个数往前插入 + * + * @param array + */ + private static void insertionSort1(int[] array) { + print(array); + + int current = array[2]; + + // 从第2个开始比较,没有小于的数据后结束循环进行插入 + int j = 2; + while (j > 0 && (current < array[j - 1])) { + array[j] = array[j - 1]; + j--; + } + + // j不等于2,说明找到了比其小的数,才进行插入 + if (j != 2) { + array[j] = current; + } + + // 使用交换的方式 + /*for (int j = 2; j > 0; j--) { + if (array[j] < array[j - 1]) { + int temp = array[j]; + array[j] = array[j - 1]; + array[j - 1] = temp; + } + }*/ + + print(array); + } + + /** + * 基于一轮的插入排序处理,再增加一个外循环 + * + * 这样一个最基础的插入排序就完成了 + * + * @param array + */ + private static void insertionSort2(int[] array) { + print(array); + + for (int i = 0; i < array.length; i++) { + int current = array[i]; + + // 从后往前的开始比较,没有小于的数据后结束循环进行插入 + int j = i; + while (j > 0 && (current < array[j - 1])) { + array[j] = array[j - 1]; + j--; + } + + // j和i不一致说明找到了比其小的数,才进行插入 + if (j != i) { + array[j] = current; + } + } + + // 使用交换的方式 + /*for (int i = 0; i < array.length; i++) { + for (int j = i + 1; j > 0; j--) { + if (array[j] < array[j - 1]) { + int temp = array[j]; + array[j] = array[j - 1]; + array[j - 1] = temp; + } + } + }*/ + + print(array); + } + + /** + * 优化版本,边界处理 + * i可以直接从1开始,0的只有一个元素无需处理 + * + * 交换的方式的话,优化i < array.length - 1 + * + * @param array + */ + private static void insertionSort3(int[] array) { + print(array); + + // 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素无需处理 + for (int i = 1; i < array.length; i++) { + int current = array[i]; + + // 从后往前的开始比较,没有小于的数据后结束循环进行插入 + int j = i; + while (j > 0 && (current < array[j - 1])) { + array[j] = array[j - 1]; + j--; + } + + // j和i不一致说明找到了比其小的数,才进行插入 + if (j != i) { + array[j] = current; + } + } + + // 使用交换的方式 + /*for (int i = 0; i < array.length - 1; i++) { + for (int j = i + 1; j > 0; j--) { + if (array[j] < array[j - 1]) { + int temp = array[j]; + array[j] = array[j - 1]; + array[j - 1] = temp; + } + } + }*/ + + print(array); + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } + +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/MergeSort.java b/Algorithm/src/main/java/com/algorithm/sort/MergeSort.java new file mode 100644 index 0000000..05726c9 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/MergeSort.java @@ -0,0 +1,199 @@ +package com.algorithm.sort; + +import java.util.Arrays; + +/** + * 归并排序 - 原生实现 + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/28 9:52 + */ +public class MergeSort { + + /** + * 归并排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {1, 3, 5, 7, 9, 2, 4, 6, 8}; + + System.out.println("---------- mergeSort1 ----------"); + mergeSort1(Arrays.copyOf(array, array.length)); + + int[] array2 = {3, 4, 5, 2, 7, 8, 9, 1, 6}; + + System.out.println("---------- mergeSort2 ----------"); + mergeSort2(Arrays.copyOf(array2, array2.length)); + + int[] array3 = {5, 3, 2, 9, 4, 8, 7, 6, 1}; + + System.out.println("---------- mergeSort3 ----------"); + mergeSort3(Arrays.copyOf(array3, array3.length)); + } + + /** + * 先写出一轮的归并处理 + * + * @param array + */ + private static void mergeSort1(int[] array) { + print(array); + + // 计算中间位置 + int midIndex = array.length / 2; + // 临时数组 + int[] tempArray = new int[array.length]; + + int i = 0, j = midIndex + 1, k = 0; + // j为中间位置+1,i和j对半进行比较,哪个小就放哪个 + while (i <= midIndex && j < array.length) { + // <=,这样保证前面的和后面相等数,前面先下去,保证稳定性 + if (array[i] <= array[j]) { + tempArray[k] = array[i]; + i++; + k++; + } else { + tempArray[k] = array[j]; + j++; + k++; + } + } + // 对比完,多余剩下的数 + while (i <= midIndex) { + tempArray[k] = array[i]; + i++; + k++; + } + while (j < array.length) { + tempArray[k] = array[j]; + j++; + k++; + } + + print(tempArray); + } + + /** + * 抽取方法进行归并验证 + * + * @param array + */ + private static void mergeSort2(int[] array) { + + print(array); + + // rightIndex 传 length - 1 + merge(array, 0, 2, 4); + + print(array); + + merge(array, 5, 6, 8); + + print(array); + } + + /** + * 抽取合并方法 + * + * @param array + * @param leftIndex + * @param midIndex + * @param rightIndex + */ + private static void merge(int[] array, int leftIndex, int midIndex, int rightIndex) { + // 数组长度需要 + 1,因为 rightIndex 传的 length - 1 + int[] tempArray = new int[rightIndex + 1 - leftIndex]; + + int i = leftIndex, j = midIndex + 1, k = 0; + // j为中间位置+1,i和j对半进行比较,哪个小就放哪个 + while (i <= midIndex && j < rightIndex + 1) { + // <=,这样保证前面的和后面相等数,前面先下去,保证稳定性 + if (array[i] <= array[j]) { + tempArray[k++] = array[i++]; + } else { + tempArray[k++] = array[j++]; + } + } + // 对比完,多余剩下的数 + while (i <= midIndex) { + tempArray[k++] = array[i++]; + } + while (j < rightIndex + 1) { + tempArray[k++] = array[j++]; + } + + // 将结果赋值给原数组 + for (int m = 0; m < tempArray.length; m++) { + array[leftIndex + m] = tempArray[m]; + } + + print(tempArray); + + } + + /** + * 基础版本,进行递归处理 + * + * @param array + */ + private static void mergeSort3(int[] array) { + + print(array); + + sort(array, 0, array.length - 1); + + print(array); + + System.out.println("---------- analysis ----------"); + System.out.println("[5 3 2 9 4] [8 7 6 1]"); + System.out.println("[5 3 2] [9 4]"); + System.out.println("[5 3] [2]"); + System.out.println("[5] [3]"); + System.out.println("[9] [4]"); + System.out.println("[8 7] [6 1]"); + System.out.println("[8] [7]"); + System.out.println("[6] [1]"); + } + + /** + * 递归方法 + * + * @param array + * @param leftIndex + * @param rightIndex + */ + private static void sort(int[] array, int leftIndex, int rightIndex) { + // System.out.println(leftIndex + "--" + rightIndex); + if (leftIndex == rightIndex) { + return; + } + + // 两种都是一样的结果,计算两个下标的中间下标 + // int minIndex = (leftIndex + rightIndex) / 2; + // 右下标减去左下标的差值的部分除以 2 得出差值的中间值,加左下标的部分得到总的中间下标 + int minIndex = leftIndex + (rightIndex - leftIndex) / 2; + + sort(array, leftIndex, minIndex); + sort(array, minIndex + 1, rightIndex); + + merge(array, leftIndex, minIndex, rightIndex); + // 优化版本,已经有序的两个数不进行重复归并 + /*if (array[minIndex] > (array[minIndex + 1])) { + merge(array, leftIndex, minIndex, rightIndex); + }*/ + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } + +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/MergeSort2.java b/Algorithm/src/main/java/com/algorithm/sort/MergeSort2.java new file mode 100644 index 0000000..4e34826 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/MergeSort2.java @@ -0,0 +1,155 @@ +package com.algorithm.sort; + +import java.util.Arrays; + +/** + * 归并排序 - 截取数组方式 + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/28 9:52 + */ +public class MergeSort2 { + + /** + * 归并排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {1, 3, 5, 7, 2, 4, 6, 8, 9}; + + System.out.println("---------- mergeSort1 ----------"); + mergeSort1(Arrays.copyOf(array, array.length)); + + int[] array2 = {5, 3, 2, 9, 4, 8, 7, 6, 1}; + + System.out.println("---------- mergeSort2 ----------"); + mergeSort2(Arrays.copyOf(array2, array2.length)); + } + + /** + * 截取数组方式 + * 先写出一轮的归并处理 + * + * @param array + */ + private static void mergeSort1(int[] array) { + print(array); + + // 计算中间位置 + int midIndex = array.length / 2; + // 临时数组 + int[] leftArray = Arrays.copyOfRange(array, 0, midIndex); + int[] rightArray = Arrays.copyOfRange(array, midIndex, array.length); + + int[] tempArray = new int[leftArray.length + rightArray.length]; + + int i = 0; + while (leftArray.length > 0 && rightArray.length > 0) { + if (leftArray[0] <= rightArray[0]) { + tempArray[i++] = leftArray[0]; + leftArray = Arrays.copyOfRange(leftArray, 1, leftArray.length); + } else { + tempArray[i++] = rightArray[0]; + rightArray = Arrays.copyOfRange(rightArray, 1, rightArray.length); + } + } + + while (leftArray.length > 0) { + tempArray[i++] = leftArray[0]; + leftArray = Arrays.copyOfRange(leftArray, 1, leftArray.length); + } + + while (rightArray.length > 0) { + tempArray[i++] = rightArray[0]; + rightArray = Arrays.copyOfRange(rightArray, 1, rightArray.length); + } + + print(tempArray); + } + + /** + * 截取数组方式基础版本,归并排序 + * + * @param array + */ + private static void mergeSort2(int[] array) { + print(array); + + array = sort(array); + + print(array); + } + + /** + * 截取数组方式递归方法 + * + * @param tempArray + * @return + */ + private static int[] sort(int[] tempArray) { + // print(tempArray); + if (tempArray.length < 2) { + return tempArray; + } + + // 计算中间位置 + int midIndex = tempArray.length / 2; + + // System.out.println(midIndex); + + // 计算左右两个数组 + int[] leftArray = Arrays.copyOfRange(tempArray, 0, midIndex); + int[] rightArray = Arrays.copyOfRange(tempArray, midIndex, tempArray.length); + + return merge(sort(leftArray), sort(rightArray)); + } + + /** + * 截取数组方式归并方法 + * + * @param leftArray + * @param rightArray + * @return + */ + private static int[] merge(int[] leftArray, int[] rightArray) { + int[] tempArray = new int[leftArray.length + rightArray.length]; + + int i = 0; + while (leftArray.length > 0 && rightArray.length > 0) { + if (leftArray[0] <= rightArray[0]) { + tempArray[i++] = leftArray[0]; + leftArray = Arrays.copyOfRange(leftArray, 1, leftArray.length); + } else { + tempArray[i++] = rightArray[0]; + rightArray = Arrays.copyOfRange(rightArray, 1, rightArray.length); + } + } + + while (leftArray.length > 0) { + tempArray[i++] = leftArray[0]; + leftArray = Arrays.copyOfRange(leftArray, 1, leftArray.length); + } + + while (rightArray.length > 0) { + tempArray[i++] = rightArray[0]; + rightArray = Arrays.copyOfRange(rightArray, 1, rightArray.length); + } + + print(tempArray); + return tempArray; + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } + +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/QuickSort.java b/Algorithm/src/main/java/com/algorithm/sort/QuickSort.java new file mode 100644 index 0000000..8ab6881 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/QuickSort.java @@ -0,0 +1,179 @@ +package com.algorithm.sort; + +import java.util.Arrays; + +/** + * 单轴双路快速排序,交换法(Hoare) + * + * 轴(基准)选择方式有:首尾元素,随机选取,三数取中法 + * 这里采用首元素 + * + * 三数取中法,取首中尾三个数中间的那个数 + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/28 9:52 + */ +public class QuickSort { + + /** + * 快速排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {5, 3, 7, 9, 4, 8, 2, 6, 1}; + + System.out.println("---------- quickSort1 ----------"); + quickSort1(Arrays.copyOf(array, array.length)); + + System.out.println("---------- quickSort2 ----------"); + quickSort2(Arrays.copyOf(array, array.length)); + + System.out.println("---------- quickSort3 ----------"); + quickSort3(Arrays.copyOf(array, array.length)); + + } + + /** + * 先写出一轮的快速排序处理 + * 设定 pivot = 0 的轴进行快排 + * + * 从左边开始,找到一个小于pivot的数 + * 从右边开始,找到有个大于pivot的数 + * 然后进行交换,输出可以看到,数据进行了两组交换 + * + * @param array + */ + private static void quickSort1(int[] array) { + print(array); + + // 设定 pivot = 0 的轴进行快排 + int pivot = 0; + int left = pivot + 1, right = array.length - 1; + + while (left <= right) { + while (left <= right && array[left] <= array[pivot]) { + left++; + } + while (left <= right && array[right] >= array[pivot]) { + right--; + } + if (left <= right) { + int temp = array[left]; + array[left] = array[right]; + array[right] = temp; + + // System.out.println("left " + left + " right " + right); + print(array); + } + } + + // System.out.println("left " + left + " right " + right); + // 交换轴,右下标是比轴小的数据,所以轴和右下标交换 + int temp = array[pivot]; + array[pivot] = array[right]; + array[right] = temp; + + print(array); + } + + /** + * 抽取公共方法 + * + * @param array + */ + private static void quickSort2(int[] array) { + print(array); + + int partitionIndex = partition(array, 0, array.length - 1); + // System.out.println("partitionIndex " + partitionIndex); + + // print(array); + } + + /** + * 抽取方法 + * + * @param array + * @param left + * @param right + * @return + */ + private static int partition(int[] array, int left, int right) { + int pivot = left; + int i = pivot + 1, j = right; + + while (i <= j) { + while (i <= j && array[i] <= array[pivot]) { + i++; + } + while (i <= j && array[j] >= array[pivot]) { + j--; + } + if (i <= j) { + int temp = array[i]; + array[i] = array[j]; + array[j] = temp; + + // System.out.println("i " + i + " j " + j); + print(array); + } + } + + // System.out.println("s i " + i + " j " + j); + + // 交换轴,右下标是比轴小的数据,所以轴和右下标交换 + int temp = array[left]; + array[left] = array[j]; + array[j] = temp; + + print(array); + + return j; + } + + /** + * 递归处理,基础版本 + * + * @param array + */ + private static void quickSort3(int[] array) { + print(array); + + sort(array, 0, array.length - 1); + + // print(array); + } + + /** + * 递归方法 + * + * @param array + * @param left + * @param right + */ + private static void sort(int[] array, int left, int right) { + if (left >= right) { + return; + } + + int partitionIndex = partition(array, left, right); + // System.out.println("left " + left + " right " + right + " partitionIndex " + partitionIndex); + sort(array, left, partitionIndex - 1); + sort(array, partitionIndex + 1, right); + + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } + +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/QuickSort2.java b/Algorithm/src/main/java/com/algorithm/sort/QuickSort2.java new file mode 100644 index 0000000..ab51f50 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/QuickSort2.java @@ -0,0 +1,96 @@ +package com.algorithm.sort; + +import java.util.Arrays; + +/** + * 单轴单路快速排序,前后指针法,pivot 这里采用首元素 + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/28 9:52 + */ +public class QuickSort2 { + + /** + * 快速排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {5, 3, 7, 9, 4, 8, 2, 6, 1}; + + System.out.println("---------- quickSort3 ----------"); + quickSort3(Arrays.copyOf(array, array.length)); + } + + /** + * 抽取方法 + * 单轴单路快速排序,前后指针法,pivot 这里采用首元素 + * + * @param array + * @param left + * @param right + * @return + */ + private static int partition(int[] array, int left, int right) { + int pivot = left; + int index = pivot + 1; + for (int i = index; i <= right; i++) { + if (array[i] < array[pivot]) { + int temp = array[i]; + array[i] = array[index]; + array[index] = temp; + index++; + } + } + int temp = array[pivot]; + array[pivot] = array[index - 1]; + array[index - 1] = temp; + print(array); + return index - 1; + } + + /** + * 递归处理,基础版本 + * + * @param array + */ + private static void quickSort3(int[] array) { + print(array); + + sort(array, 0, array.length - 1); + + // print(array); + } + + /** + * 递归方法 + * + * @param array + * @param left + * @param right + */ + private static void sort(int[] array, int left, int right) { + if (left >= right) { + return; + } + + int partitionIndex = partition(array, left, right); + // System.out.println("left " + left + " right " + right + " partitionIndex " + partitionIndex); + sort(array, left, partitionIndex - 1); + sort(array, partitionIndex + 1, right); + + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } + +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/QuickSort3.java b/Algorithm/src/main/java/com/algorithm/sort/QuickSort3.java new file mode 100644 index 0000000..6d4b584 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/QuickSort3.java @@ -0,0 +1,113 @@ +package com.algorithm.sort; + +import java.util.Arrays; + +/** + * 单轴双路快速排序,挖坑法,pivot 这里采用首元素 + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/28 9:52 + */ +public class QuickSort3 { + + /** + * 快速排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {5, 3, 7, 9, 4, 8, 2, 6, 1}; + + System.out.println("---------- quickSort3 ----------"); + quickSort3(Arrays.copyOf(array, array.length)); + } + + /** + * 抽取方法 + * 单轴双路快速排序,挖坑法,pivot 这里采用首元素 + * + * @param array + * @param left + * @param right + * @return + */ + private static int partition(int[] array, int left, int right) { + int pivot = array[left]; + int i = left, j = right; + + while (i < j) { + // 从右向左找出比pivot小的数据 + while (i <= j && array[j] > pivot) { + j--; + } + // 找到后立即放入左边坑中,当前位置变为新的"坑" + if (i < j) { + array[i] = array[j]; + i++; + } + // 从左向右找出比pivot大的数据 + while (i <= j && array[i] <= pivot) { + i++; + } + // 找到后立即放入右边坑中,当前位置变为新的"坑" + if (i < j) { + array[j] = array[i]; + j--; + } + } + + // System.out.println("s i " + i + " j " + j); + + // 将最开始存储的分界值放入当前的"坑"中 + array[j] = pivot; + + print(array); + + return j; + } + + /** + * 递归处理,基础版本 + * + * @param array + */ + private static void quickSort3(int[] array) { + print(array); + + sort(array, 0, array.length - 1); + + // print(array); + } + + /** + * 递归方法 + * + * @param array + * @param left + * @param right + */ + private static void sort(int[] array, int left, int right) { + if (left >= right) { + return; + } + + int partitionIndex = partition(array, left, right); + // System.out.println("left " + left + " right " + right + " partitionIndex " + partitionIndex); + sort(array, left, partitionIndex - 1); + sort(array, partitionIndex + 1, right); + + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } + +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/RadixSort.java b/Algorithm/src/main/java/com/algorithm/sort/RadixSort.java new file mode 100644 index 0000000..3a2ac8e --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/RadixSort.java @@ -0,0 +1,243 @@ +package com.algorithm.sort; + +import java.util.Arrays; + +/** + * 基数排序 + * + * @author wliduo[i@dolyw.com] + * @date 2022/12/01 10:03 + */ +public class RadixSort { + + /** + * 基数排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {5, 122, 102, 95, 63, 70, 88, 73, 88, 81, 555, 666, 729, 19, 28, 45, 1115}; + + System.out.println("---------- radixSort1 ----------"); + radixSort1(Arrays.copyOf(array, array.length)); + + int[] array2 = {5, 122, 102, 95, 63, -7, 88, 73, 88, 81, -555, -666, 729, -19, 28, 45, 1115}; + + System.out.println("---------- radixSort2 ----------"); + radixSort2(Arrays.copyOf(array2, array2.length)); + + System.out.println("---------- radixSort3 ----------"); + radixSort3(Arrays.copyOf(array2, array2.length)); + } + + /** + * 基数排序基础版本,不支持负数 + * + * @param array + */ + private static void radixSort1(int[] array) { + print(array); + + int[] tempArray = new int[array.length]; + int[] counter = new int[10]; + + // 使用最大值计算位数 + int maxValue = array[0]; + for (int value : array) { + if (maxValue < value) { + maxValue = value; + } + } + // 获取位数 + int maxDigit = getNumLength(maxValue); + for (int i = 0; i < maxDigit; i++) { + int division = (int) Math.pow(10, i); + // System.out.println(division); + + for (int j = 0; j < array.length; j++) { + int num = array[j] / division % 10; + counter[num]++; + } + + // 累加数组保证稳定 + for (int m = 1; m < counter.length; m++) { + counter[m] = counter[m] + counter[m - 1]; + } + + // 利用累加数组的方式取出元素,从最后一位开始 + for (int n = array.length - 1; n >= 0; n--) { + // 取出所在counter下标 + int num = array[n] / division % 10; + // 将其-1后得到的就是它的在counter中的下标 + counter[num]--; + // 根据counter加下标得到该元素最终在有序数组中的下标 + int pos = counter[num]; + // 赋值到新数组对应的下标位置 + tempArray[pos] = array[n]; + } + + // 将tempArray复制到array + // System.arraycopy(tempArray, 0, array, 0, array.length); + array = Arrays.copyOf(tempArray, tempArray.length); + // 将counter数组值全部填充置为0,重新开始下一轮 + Arrays.fill(counter, 0); + + print(array); + } + + // print(array); + } + + /** + * 获取数字位数 + * + * @param num + * @return + */ + private static int getNumLength(long num) { + if (num == 0) { + return 1; + } + int length = 0; + for (long temp = num; temp != 0; temp /= 10) { + length++; + } + return length; + } + + /** + * 基数排序优化版本,支持负数 + * + * 考虑负数的情况,扩展一倍队列数 + * 其中[0-9]对应负数,[10-19]对应正数(bucket + 10) + * + * @param array + */ + private static void radixSort2(int[] array) { + print(array); + + int[] tempArray = new int[array.length]; + // 考虑负数的情况,扩展一倍队列数,其中[0-9]对应负数,[10-19]对应正数(bucket + 10) + int[] counter = new int[20]; + + // 使用最大值计算位数 + int maxValue = array[0]; + for (int value : array) { + if (maxValue < value) { + maxValue = value; + } + } + // 获取位数 + int maxDigit = getNumLength(maxValue); + for (int i = 0; i < maxDigit; i++) { + int division = (int) Math.pow(10, i); + // System.out.println(division); + + for (int j = 0; j < array.length; j++) { + int num = array[j] / division % 10; + // 值大于等于0,存放在10-19的正数区域 + // 其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10) + num = num + 10; + counter[num]++; + } + + // 累加数组保证稳定 + for (int m = 1; m < counter.length; m++) { + counter[m] = counter[m] + counter[m - 1]; + } + + // 利用累加数组的方式取出元素,从最后一位开始 + for (int n = array.length - 1; n >= 0; n--) { + // 取出所在counter下标 + int num = array[n] / division % 10; + // 值大于等于0,存放在10-19的正数区域 + // 其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10) + num = num + 10; + // 将其-1后得到的就是它的在counter中的下标 + counter[num]--; + // 根据counter加下标得到该元素最终在有序数组中的下标 + int pos = counter[num]; + // 赋值到新数组对应的下标位置 + tempArray[pos] = array[n]; + } + + // 将tempArray复制到array + // System.arraycopy(tempArray, 0, array, 0, array.length); + array = Arrays.copyOf(tempArray, tempArray.length); + // 将counter数组值全部填充置为0,重新开始下一轮 + Arrays.fill(counter, 0); + + print(array); + } + + // print(array); + } + + /** + * 基数排序优化版本v2,使用二维数组实现,支持负数 + * + * @param array + */ + private static void radixSort3(int[] array) { + print(array); + + // 使用最大值计算位数 + int maxValue = array[0]; + for (int value : array) { + if (maxValue < value) { + maxValue = value; + } + } + // 获取位数 + int maxDigit = getNumLength(maxValue); + int mod = 10; + int dev = 1; + + for (int i = 0; i < maxDigit; i++, dev = dev * 10, mod = mod * 10) { + // 考虑负数的情况,扩展一倍队列数,其中[0-9]对应负数,[10-19]对应正数(bucket + 10) + int[][] counter = new int[mod * 2][0]; + + // 放入桶 + for (int j = 0; j < array.length; j++) { + int bucket = ((array[j] % mod) / dev) + mod; + counter[bucket] = arrayAppend(counter[bucket], array[j]); + } + + // 稳定的,使用二维数组存放了值 + int pos = 0; + for (int[] bucket : counter) { + for (int value : bucket) { + array[pos++] = value; + } + } + + print(array); + } + + // print(array); + } + + /** + * 自动扩容,并保存数据 + * + * @param arr + * @param value + */ + private static int[] arrayAppend(int[] arr, int value) { + arr = Arrays.copyOf(arr, arr.length + 1); + arr[arr.length - 1] = value; + return arr; + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/RadixSort2.java b/Algorithm/src/main/java/com/algorithm/sort/RadixSort2.java new file mode 100644 index 0000000..df719a4 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/RadixSort2.java @@ -0,0 +1,49 @@ +package com.algorithm.sort; + +/** + * 基数排序 - 字符排序 + * + * https://blog.csdn.net/qq_35344198/article/details/107615053 + * https://blog.csdn.net/lhj520cb/article/details/119456573 + * + * @author wliduo[i@dolyw.com] + * @date 2022/12/01 10:03 + */ +public class RadixSort2 { + + /** + * 基数排序算法 + * + * @param args + */ + public static void main(String[] args) { + // 字符排序 + String[] strArray = {"cni", "efz", "omv", "kbv", "pl", "acj", "agd", "ef"}; + + System.out.println("---------- radixSortStr1 ----------"); + radixSortStr1(strArray); + } + + /** + * 基数排序字符排序基础版本 + * + * @param strArray + */ + private static void radixSortStr1(String[] strArray) { + print(strArray); + + // print(array); + } + + /** + * 打印数组 + * + * @param strArray + */ + private static void print(String[] strArray) { + for (String value : strArray) { + System.out.print(value + " "); + } + System.out.println(); + } +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/SelectionSort.java b/Algorithm/src/main/java/com/algorithm/sort/SelectionSort.java new file mode 100644 index 0000000..db6268f --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/SelectionSort.java @@ -0,0 +1,189 @@ +package com.algorithm.sort; + +import java.util.Arrays; + +/** + * 选择排序 + * + * 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置 + * 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾 + * 重复第二步,直到所有元素均排序完毕 + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/22 9:52 + */ +public class SelectionSort { + + /** + * 选择排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {5, 3, 2, 4, 9, 8, 7, 1, 6}; + + System.out.println("---------- selectionSort1 ----------"); + selectionSort1(Arrays.copyOf(array, array.length)); + + System.out.println("---------- selectionSort2 ----------"); + selectionSort2(Arrays.copyOf(array, array.length)); + + System.out.println("---------- selectionSort3 ----------"); + selectionSort3(Arrays.copyOf(array, array.length)); + + System.out.println("---------- selectionSort4 ----------"); + selectionSort4(Arrays.copyOf(array, array.length)); + } + + /** + * 先写出一轮的选择排序处理 + * + * 可以看到最小的数字交换到第一个了 + * + * @param array + */ + private static void selectionSort1(int[] array) { + print(array); + + // 记录最小下标位置 + int minIndex = 0; + + for (int j = 0; j < array.length; j++) { + if (array[j] < array[minIndex]) { + minIndex = j; + } + } + + // 将最小下标值进行交换 + int temp = array[0]; + array[0] = array[minIndex]; + array[minIndex] = temp; + + print(array); + } + + /** + * 基于一轮的选择排序处理,再增加一个外循环 + * 将每个位置的数字都进行一轮选择交换 + * 这样一个最基础的选择排序就完成了 + * + * @param array + */ + private static void selectionSort2(int[] array) { + print(array); + + // count记录循环次数 + int count = 0; + + for (int i = 0; i < array.length; i++) { + // 记录最小下标位置 + int minIndex = i; + + for (int j = i; j < array.length; j++) { + count++; + if (array[j] < array[minIndex]) { + minIndex = j; + } + } + + // 将最小下标值进行交换 + int temp = array[i]; + array[i] = array[minIndex]; + array[minIndex] = temp; + } + + System.out.println("count: " + count); + + print(array); + } + + /** + * 优化版本,边界处理优化 + * + * 应该从j=i+1开始,i为0时,如果j=i + * 那就是array[0]和array[0]比较了一次 + * + * 外循环也应该i < array.length - 1,也是一样 + * 不进行-1的话结尾array[8]和array[8]多比较了一次 + * + * @param array + */ + private static void selectionSort3(int[] array) { + print(array); + + // count记录循环次数 + int count = 0; + + for (int i = 0; i < array.length - 1; i++) { + // 记录最小下标位置 + int minIndex = i; + + for (int j = i + 1; j < array.length; j++) { + if (array[j] < array[minIndex]) { + minIndex = j; + } + count++; + } + + // 将最小下标值进行交换 + int temp = array[i]; + array[i] = array[minIndex]; + array[minIndex] = temp; + } + + System.out.println("count: " + count); + + print(array); + } + + /** + * 优化版本v2,交换可以优化,不是每次都需要交换 + * + * 如果下标是一样的,说明当前数就是最小的 + * 没必要自己和自己交换了 + * + * @param array + */ + private static void selectionSort4(int[] array) { + print(array); + + // count记录循环次数 + int count = 0; + + for (int i = 0; i < array.length - 1; i++) { + // 记录最小下标位置 + int minIndex = i; + + for (int j = i + 1; j < array.length; j++) { + if (array[j] < array[minIndex]) { + minIndex = j; + } + count++; + } + + // 最小下标位置和i不相等说明找到新的最小数才进行交换 + if (minIndex != i) { + int temp = array[i]; + array[i] = array[minIndex]; + array[minIndex] = temp; + } + } + + System.out.println("count: " + count); + + print(array); + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } + +} diff --git a/Algorithm/src/main/java/com/algorithm/sort/ShellSort.java b/Algorithm/src/main/java/com/algorithm/sort/ShellSort.java new file mode 100644 index 0000000..e91fac2 --- /dev/null +++ b/Algorithm/src/main/java/com/algorithm/sort/ShellSort.java @@ -0,0 +1,166 @@ +package com.algorithm.sort; + +import java.util.Arrays; + +/** + * 希尔排序,又称递减(缩小)增量排序 + * 它与插入排序的不同之处在于,它通过比较相距一定间隔的元素来进行 + * 各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止 + * + * 增量计算方式有两种 + * 1. 常规折半计算 array.length / 2,用序列 {n/2,(n/2)/2...1} 来表示 + * 2. knuth 序列(克努特序列),h = 3*h + 1,(1,4,13,40,121...) + * + * https://www.runoob.com/data-structures/shell-sort.html + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/25 15:04 + */ +public class ShellSort { + + /** + * 希尔排序算法 + * + * @param args + */ + public static void main(String[] args) { + int[] array = {10, 8, 12, 9, 5, 3, 7, 1, 6, 4, 2, 11}; + + System.out.println("---------- shellSort1 ----------"); + shellSort1(Arrays.copyOf(array, array.length)); + + System.out.println("---------- shellSort2 ----------"); + shellSort2(Arrays.copyOf(array, array.length)); + + System.out.println("---------- shellSort3 ----------"); + shellSort3(Arrays.copyOf(array, array.length)); + } + + /** + * 先写出第一轮排序,把插入复制过过来 + * 增加为12个数,按间隔,gap设定为4 + * 要改为 while (j - gap >= 0 大于等0,不然第一位数无法被排序 + * + * 可以看到每4个间隔比较的数都进行了插入排序 + * + * @param array + */ + private static void shellSort1(int[] array) { + print(array); + + int gap = 4; + + // 从下标为 gap 开始,因为要和上一个 gap 比较,所以从 gap 开始 + for (int i = gap; i < array.length; i++) { + int current = array[i]; + + // 从后往前的开始比较,没有小于的数据后结束循环进行插入 + int j = i; + while (j - gap >= 0 && (current < array[j - gap])) { + array[j] = array[j - gap]; + j = j - gap; + } + + // j和i不一致说明找到了比其小的数,进行插入 + if (j != i) { + array[j] = current; + } + } + + print(array); + } + + /** + * 基础版本,增加外循环,在此我们选择常规折半计算 array.length / 2 + * 递减增量以 gap = gap / 2 的方式,用序列 {n/2,(n/2)/2...1} 来表示 + * + * while (j - gap >= 0 也相等于 j - gap > -1 也相等于 j > gap - 1 + * + * @param array + */ + private static void shellSort2(int[] array) { + print(array); + + for (int gap = array.length / 2; gap > 0; gap = gap / 2) { + + // 从下标为 gap 开始,因为要和上一个 gap 比较,所以从 gap 开始 + for (int i = gap; i < array.length; i++) { + int current = array[i]; + + // 从后往前的开始比较,没有小于的数据后结束循环进行插入 + int j = i; + // while (j - gap >= 0 && (current < array[j - gap])) { + while (j > gap - 1 && (current < array[j - gap])) { + array[j] = array[j - gap]; + j = j - gap; + } + + // j和i不一致说明找到了比其小的数,进行插入 + if (j != i) { + array[j] = current; + } + } + + System.out.println(gap); + print(array); + } + + // print(array); + } + + /** + * 优化版本,使用 knuth 序列计算出对应的递减增量 gap,h = 3*h + 1 + * + * @param array + */ + private static void shellSort3(int[] array) { + print(array); + + // 计算增量 + int gap = 1; + while (gap < array.length / 3) { + gap = 3 * gap + 1; + } + + while (gap > 0) { + + // 从下标为 gap 开始,因为要和上一个 gap 比较,所以从 gap 开始 + for (int i = gap; i < array.length; i++) { + int current = array[i]; + + // 从后往前的开始比较,没有小于的数据后结束循环进行插入 + int j = i; + // while (j - gap >= 0 && (current < array[j - gap])) { + while (j > gap - 1 && (current < array[j - gap])) { + array[j] = array[j - gap]; + j = j - gap; + } + + // j和i不一致说明找到了比其小的数,进行插入 + if (j != i) { + array[j] = current; + } + } + + System.out.println(gap); + print(array); + + // 重新计算增量 + gap = (gap - 1) / 3; + } + + // print(array); + } + + /** + * 打印数组 + * + * @param array + */ + private static void print(int[] array) { + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } +} diff --git a/Algorithm/src/main/resources/application.properties b/Algorithm/src/main/resources/application.properties new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Algorithm/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/Algorithm/src/test/java/com/algorithm/AlgorithmApplicationTests.java b/Algorithm/src/test/java/com/algorithm/AlgorithmApplicationTests.java new file mode 100644 index 0000000..4ebf446 --- /dev/null +++ b/Algorithm/src/test/java/com/algorithm/AlgorithmApplicationTests.java @@ -0,0 +1,19 @@ +package com.algorithm; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * 算法 + * + * @author wliduo[i@dolyw.com] + * @date 2022/11/22 9:52 + */ +@SpringBootTest +class AlgorithmApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/SpringBoot/DistributedID/src/main/java/com/example/snow/IdWorkerPatch.java b/SpringBoot/DistributedID/src/main/java/com/example/snow/IdWorkerPatch.java index 73c2bad..1c37aaf 100644 --- a/SpringBoot/DistributedID/src/main/java/com/example/snow/IdWorkerPatch.java +++ b/SpringBoot/DistributedID/src/main/java/com/example/snow/IdWorkerPatch.java @@ -81,12 +81,12 @@ public IdWorkerPatch(long workerId, long datacenterId, long sequence) { /** * 机器ID所占的位数 */ - private long workerIdBits = 4L; + private long workerIdBits = 5L; /** * 数据标识ID所占的位数 */ - private long datacenterIdBits = 4L; + private long datacenterIdBits = 5L; /** * 支持的最大机器ID,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) @@ -101,7 +101,7 @@ public IdWorkerPatch(long workerId, long datacenterId, long sequence) { /** * 序列在ID中占的位数 */ - private long sequenceBits = 10L; + private long sequenceBits = 12L; /** * 机器ID向左移12位 diff --git a/SpringBoot/RabbitMQ/Producer/src/main/java/com/example/config/MqConfirmReturnsConfig.java b/SpringBoot/RabbitMQ/Producer/src/main/java/com/example/config/MqConfirmReturnsConfig.java index 0c1bff8..a9c1cef 100644 --- a/SpringBoot/RabbitMQ/Producer/src/main/java/com/example/config/MqConfirmReturnsConfig.java +++ b/SpringBoot/RabbitMQ/Producer/src/main/java/com/example/config/MqConfirmReturnsConfig.java @@ -44,7 +44,7 @@ public void confirm(CorrelationData correlationData, boolean b, String s) { System.out.println(b); System.out.println(s); // 需要在发送的时候同时传递correlationData才能获取 - // 提前使用Id和消息内容绑定在缓存,Id可以任意 + // 提前使用Id和消息内容绑定在缓存或者数据库消息记录表,Id可以任意 // 或者也可以直接将Id设置为消息体即可 System.out.println(correlationData.toString()); /*ReturnedMessage returnedMessage = correlationData.getReturned(); diff --git a/SpringBoot/ThreadPool/src/main/java/com/example/controller/CompletableFutureController.java b/SpringBoot/ThreadPool/src/main/java/com/example/controller/CompletableFutureController.java index 79f13ee..bcba8ab 100644 --- a/SpringBoot/ThreadPool/src/main/java/com/example/controller/CompletableFutureController.java +++ b/SpringBoot/ThreadPool/src/main/java/com/example/controller/CompletableFutureController.java @@ -10,11 +10,12 @@ import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; import java.util.concurrent.ThreadPoolExecutor; /** - * AsyncController + * CompletableFutureController + * + * https://www.cnblogs.com/happyliu/archive/2018/08/12/9462703.html * * @author wliduo[i@dolyw.com] * @date 2020/5/19 14:46 @@ -58,6 +59,7 @@ public String run1() throws Exception { } catch (Exception e) { } + throw new RuntimeException(); }); CompletableFuture completableFuture2 = CompletableFuture.runAsync(() -> { try { diff --git a/TestWeb/src/test/java/com/wang/other/TestOther.java b/TestWeb/src/test/java/com/wang/other/TestOther.java index 2bde709..78e2822 100644 --- a/TestWeb/src/test/java/com/wang/other/TestOther.java +++ b/TestWeb/src/test/java/com/wang/other/TestOther.java @@ -1,5 +1,7 @@ package com.wang.other; +import cn.hutool.core.text.StrPool; +import cn.hutool.core.util.StrUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.fastjson.JSON; import com.wang.model.HttpCode; @@ -360,6 +362,13 @@ public void testMoney() { System.out.println(new BigDecimal("A0")); } + @Test + public void testNode() { + String node = "orderList[12]"; + String index = node.substring(node.indexOf(StrPool.BRACKET_START) + 1, node.indexOf(StrPool.BRACKET_END)); + System.out.println(index); + } + public static void main(String[] args) throws Exception { /** * 准备发送端