();
+ for (int i = 0; i < n; i++) { + int num = nums[i]; + int targetVal = target - num; + arrayMap.put(targetVal, i); + } + for (int i = 0; i < n; i++) { + int num = nums[i]; + if (arrayMap.containsKey(num)) { + int index = arrayMap.get(num); + if (index> i) {
+ return new int[]{i, index};
+ } else {
+ return new int[]{index, i};
+ }
+ }
+ }
+ return new int[0];
+ }
+
+ /**
+ * 暴力破解法
+ * 时间复杂度:o(n^2)
+ * 空间复杂度:O(n)
+ * @param nums
+ * @param target
+ * @return
+ */
+ private int[] forceSolution(int[] nums, int target) {
+ int n = nums.length;
+ for (int i = 0; i < n; i++) { + int num = nums[i]; + int val = target - num; + for (int j = i + 1; j < n; j++) { + if (nums[j] == val) { + return new int[]{i, j}; + } + } + } + return new int[0]; + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/TwoSumII.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/TwoSumII.java new file mode 100644 index 0000000..79147f1 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/TwoSumII.java @@ -0,0 +1,62 @@ +package com.bruis.algorithminjava.algorithm.leetcode; + +/** + * @Description + * @Author luohaiyang + * @Date 2022/4/28 + */ +public class TwoSumII { + public int[] twoSum(int[] numbers, int target) { + return twoPointer(numbers, target); + } + + /** + * 双指针 + * 时间复杂度:O(n) + * 空间复杂度:O(1) + * @param numbers + * @param target + * @return + */ + private int[] twoPointer(int[] numbers, int target) { + int n = numbers.length; + if (n < 2) { + return numbers; + } + int i = 0, j = n - 1; + while (i < j) { + if (numbers[i] + numbers[j] == target) { + return new int[]{i + 1, j + 1}; + } + if (numbers[i] + numbers[j]> target) {
+ j--;
+ } else {
+ i++;
+ }
+ }
+ return new int[0];
+ }
+
+ /**
+ * 暴力法:
+ * 时间复杂度:O(n^2)
+ * 空间复杂度:O(1)
+ * @param numbers
+ * @param target
+ * @return
+ */
+ private int[] forceSolution(int[] numbers, int target) {
+ int n = numbers.length;
+ if (n < 2) { + return numbers; + } + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (numbers[i] + numbers[j] == target) { + return new int[]{i + 1, j + 1}; + } + } + } + return new int[0]; + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/IsPalindrome.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/IsPalindrome.java new file mode 100644 index 0000000..d75488f --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/IsPalindrome.java @@ -0,0 +1,41 @@ +package com.bruis.algorithminjava.algorithm.leetcode.array; + +/** + * + * 125 + * + * 验证回文串 + * + * https://leetcode-cn.com/problems/valid-palindrome/ + * + * + * @author LuoHaiYang + */ +public class IsPalindrome { + public boolean isPalindrome(String str) { + int head = 0, tail = str.length() - 1; + char a, b; + while(head < tail) { + a = str.charAt(head); + b = str.charAt(tail); + if(!Character.isLetterOrDigit(a)) { + head ++; + } else if(!Character.isLetterOrDigit(b)) { + tail --; + } else { + if(Character.toLowerCase(a) != Character.toLowerCase(b)) { + return false; + } + head ++; + tail --; + } + } + return true; + } + + public static void main(String[] args) { + IsPalindrome isPalindrome = new IsPalindrome(); + String test = "race a car"; + System.out.println(isPalindrome.isPalindrome(test)); + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumGap.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumGap.java new file mode 100644 index 0000000..522d1f0 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumGap.java @@ -0,0 +1,170 @@ +package com.bruis.algorithminjava.algorithm.leetcode.array; + +import java.util.Arrays; + +/** + * 最大间距 + * + * url:https://leetcode-cn.com/problems/maximum-gap/ + * + * @author LuoHaiYang + */ +public class MaximumGap { + + /** + * 基于桶排序 + * 时间复杂度:O(N) + * 空间复杂度:O(N) + * @param nums + * @return + */ + public int maximumGapOptimize2(int[] nums) { + if (nums.length < 2) return 0; + int len = nums.length; + + // 找出最大值和最小值 为了方便后面确定桶的数量 + int max = -1, min = Integer.MAX_VALUE; + for (int i = 0; i < len; i++) { + max = Math.max(nums[i], max); + min = Math.min(nums[i], min); + } + + // 排除nums全部为一样的数字,nums = [1,1,1,1,1,1]; + if (max - min == 0) return 0; + // 用于存放每个桶的最大值 + int[] bucketMin = new int[len - 1]; + // 用于存放每个桶的最小值 + int[] bucketMax = new int[len - 1]; + Arrays.fill(bucketMax, -1); + Arrays.fill(bucketMin, Integer.MAX_VALUE); + + // 确定桶的间距 + int interval = (int)Math.ceil((double)(max - min) / (len - 1)); + for (int i = 0; i < len; i++) { + // 找到每一个值所对应桶的索引 + int index = (nums[i] - min) / interval; + if (nums[i] == min || nums[i] == max) continue; + // 更新每个桶的数据 + bucketMax[index] = Math.max(bucketMax[index], nums[i]); + bucketMin[index] = Math.min(bucketMin[index], nums[i]); + } + + // maxGap 表示桶之间最大的差距 + int maxGap = 0; + // preMax 表示前一个桶的最大值 + int preMax = min; + for (int i = 0; i < len - 1; i++) { + // 表示某一个桶为空 + // 但凡某一个桶不为空,都会在前面的数据中更新掉bucketMax的值 + if (bucketMax[i] == -1) continue; + maxGap = Math.max(bucketMin[i] - preMax, maxGap); + preMax = bucketMax[i]; + } + // [1,10000000] + maxGap = Math.max(maxGap, max - preMax); + return maxGap; + } + + /** + * 基数排序: + * 时间复杂度:O(N) + * 空间复杂度:O(N) + * @param nums + * @return + */ + public int maximumGapOptimize(int[] nums) { + int n = nums.length; + if (n < 2) { + return 0; + } + long exp = 1; + int[] buf = new int[n]; + int maxVal = Arrays.stream(nums).max().getAsInt(); + + while (maxVal>= exp) {
+ int[] cnt = new int[10];
+ for (int i = 0; i < n; i++) { + int digit = (nums[i] / (int) exp) % 10; + cnt[digit]++; + } + for (int i = 1; i < 10; i++) { + cnt[i] += cnt[i - 1]; + } + for (int i = n - 1; i>= 0; i--) {
+ int digit = (nums[i] / (int) exp) % 10;
+ buf[cnt[digit] - 1] = nums[i];
+ cnt[digit]--;
+ }
+ System.arraycopy(buf, 0, nums, 0, n);
+ exp *= 10;
+ }
+
+ int ret = 0;
+ for (int i = 1; i < n; i++) { + ret = Math.max(ret, nums[i] - nums[i - 1]); + } + return ret; + } + + public int maximumGap(int[] nums) { + if (nums == null || nums.length < 2) { + return 0; + } + // 排序 + quickSort(nums); + int n = nums.length; + + int max = nums[1] - nums[0]; + + for (int i = 2; i < n; i++) { + max = max(max, nums[i] - nums[i-1]); + } + return max; + } + + private void quickSort(int[] nums) { + int n = nums.length; + quickSort3ways(nums, 0, n-1); + } + + private void quickSort3ways(int[] nums, int left, int right) { + if (left>= right) {
+ return;
+ }
+ int p = nums[left];
+ int i = left + 1, lt = left, gt = right + 1;
+
+ while (i < gt) { + if (nums[i] < p) { + swap(nums, i, lt + 1); + i++; + lt++; + } else if (nums[i]> p) {
+ swap(nums, i, gt - 1);
+ gt--;
+ } else {
+ i++;
+ }
+ }
+ swap(nums, left, lt);
+ quickSort3ways(nums, left, lt - 1);
+ quickSort3ways(nums, gt, right);
+ }
+
+ private int max(int i, int j) {
+ return Math.max(i, j);
+ }
+
+ private void swap(int[] nums, int i, int j) {
+ int tmp = nums[i];
+ nums[i] = nums[j];
+ nums[j] = tmp;
+ }
+
+ public static void main(String[] args) {
+ int[] test = {3,6,9,1,20,15,11,30,31};
+ MaximumGap maximumGap = new MaximumGap();
+// System.out.println(maximumGap.maximumGap(test));
+ System.out.println(maximumGap.maximumGapOptimize2(test));
+ }
+}
diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/array/MaximumProductSubarray.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumProductSubarray.java
similarity index 96%
rename from src/main/java/com/bruis/algorithminjava/algorithm/array/MaximumProductSubarray.java
rename to src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumProductSubarray.java
index 2df3ade..b0785f4 100644
--- a/src/main/java/com/bruis/algorithminjava/algorithm/array/MaximumProductSubarray.java
+++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumProductSubarray.java
@@ -1,4 +1,4 @@
-package com.bruis.algorithminjava.algorithm.array;
+package com.bruis.algorithminjava.algorithm.leetcode.array;
/**
* @author LuoHaiYang
diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ReversePairs.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ReversePairs.java
new file mode 100644
index 0000000..fc2d98c
--- /dev/null
+++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ReversePairs.java
@@ -0,0 +1,179 @@
+package com.bruis.algorithminjava.algorithm.leetcode.array;
+
+import java.util.Arrays;
+
+/**
+ * 逆序对
+ *
+ * url: https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/
+ *
+ * @author LuoHaiYang
+ */
+public class ReversePairs {
+
+ /* ================================ 解法一 ================================*/
+
+ /**
+ * 暴力解法O(n^2),超时
+ *
+ * @param nums
+ * @return
+ */
+ public int reversePairs2(int[] nums) {
+ int n = nums.length;
+ if (n < 2) { + return 0; + } + int reverseNum = 0; + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (nums[i]> nums[j]) {
+ reverseNum++;
+ }
+ }
+ }
+ return reverseNum;
+ }
+
+ /* ================================ 解法二 ================================*/
+
+ /**
+ * 使用自顶向下的归并排序算法计算逆序对,用来额外的空间。
+ *
+ * @param nums
+ * @return
+ */
+ public int reversePairs(int[] nums) {
+ int n = nums.length;
+ if (n < 2) { + return 0; + } + return getReversePairs(nums); + } + + private int getReversePairs(int[] nums) { + int n = nums.length; + return getReversePairs(nums, 0, n - 1); + } + + private int getReversePairs(int[] nums, int left, int right) { + if (left>= right) {
+ return 0;
+ }
+ int result = 0;
+ int mid = (left + right) / 2;
+ result += getReversePairs(nums, left, mid) + getReversePairs(nums, mid + 1, right) + reversePairs(nums, left, mid, right);
+ return result;
+ }
+
+ private int reversePairs(int[] nums, int left, int mid, int right) {
+ int[] aux = Arrays.copyOfRange(nums, left, right + 1);
+ int i = left, j = mid + 1;
+
+ int res = 0;
+
+ for (int k = left; k <= right; k++) { + if (i> mid) {
+ nums[k] = aux[j - left];
+ j++;
+ } else if (j> right) {
+ nums[k] = aux[i - left];
+ i++;
+ } else if (aux[i - left] <= aux[j - left]) { + nums[k] = aux[i - left]; + i++; + } else { + nums[k] = aux[j - left]; + j++; + res += (mid - i) + 1; + } + } + return res; + } + + /* ================================ 题解三(优化) ================================*/ + + /** + * + * 相比解法二时间复杂度常数和空间复杂度更低 + * + * @param nums + * @return + */ + public int reversePairs3(int[] nums) { + if (nums == null || nums.length < 2) { + return 0; + } + int[] temp = new int[nums.length]; + System.arraycopy(nums, 0, temp, 0, nums.length); + + int count = mergeCount(nums, temp, 0, nums.length - 1); + return count; + } + + private int mergeCount(int[] nums, int[] temp, int start, int end) { + if (start>= end) {
+ return 0;
+ }
+
+ int mid = (start + end)>> 1;
+ int left = mergeCount(temp, nums, start, mid);
+ int right = mergeCount(temp, nums, mid + 1, end);
+ int count = 0;
+
+ //merge()
+ //遍历左区域指针
+ int i = mid;
+ //遍历右区域指针
+ int j = end;
+
+ //临时区域指针
+ int k = end;
+ while (i>= start && j>= mid + 1) {
+ if (nums[i]> nums[j]) {
+ count += j - mid;
+ temp[k--] = nums[i--];
+ } else {
+ temp[k--] = nums[j--];
+ }
+ }
+
+ //如果还有剩下没遍历的
+ while (i>= start) {
+ temp[k--] = nums[i--];
+ }
+ while (j>= mid + 1) {
+ temp[k--] = nums[j--];
+ }
+
+ return count + left + right;
+ }
+
+ public int reversePairs4(int[] nums) {
+ if (nums == null || nums.length < 2) { + return 0; + } + int[] temp = new int[nums.length]; + System.arraycopy(nums, 0, temp, 0, nums.length); + //int count = mergeCount2(); + return 0; + } + + private int mergeCount2(int[] nums, int[] temp, int start, int end) { + if (start>= end) {
+ return 0;
+ }
+ int mid = (start + end) << 1; + //int left = mergeCount2(nums, ); + return 0; + } + + public static void main(String[] args) { + ReversePairs reversePairs = new ReversePairs(); + int[] nums = {7, 5, 6, 4}; + //int[] nums = {1,3,2,3,1}; + System.out.println(reversePairs.reversePairs3(nums)); + } + + +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ReverseVowels.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ReverseVowels.java new file mode 100644 index 0000000..5dbb8aa --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ReverseVowels.java @@ -0,0 +1,58 @@ +package com.bruis.algorithminjava.algorithm.leetcode.array; + +/** + * + * 345 + * + * https://leetcode-cn.com/problems/reverse-vowels-of-a-string/ + * + * 反转字符串中的元音字母 + * + * @author LuoHaiYang + */ +public class ReverseVowels { + + public String reverseVowels(String s) { + + char[] arr = s.toCharArray(); + int n = arr.length, left = 0, right = n - 1; + + while (left <= right) { + + // 如果不是元音,则指针右移 + while (left < n && !isVowel(arr[left])) { + left++; + } + + while (right>= 0 && !isVowel(arr[right])) {
+ right--;
+ }
+
+ if (left> right) {
+ break;
+ }
+
+ // 字符调换
+ swap(arr, left, right);
+ left++;
+ right--;
+ }
+ return new String(arr);
+ }
+
+ /**
+ *
+ * 1. 元音字母是?
+ *
+ */
+ private boolean isVowel(char ch) {
+ return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u'
+ || ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U';
+ }
+
+ private void swap(char[] arr, int i, int j) {
+ char tmp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = tmp;
+ }
+}
diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/SortColors.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/SortColors.java
new file mode 100644
index 0000000..26fe731
--- /dev/null
+++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/SortColors.java
@@ -0,0 +1,56 @@
+package com.bruis.algorithminjava.algorithm.leetcode.array;
+
+/**
+ *
+ * 颜色分类
+ *
+ * url:https://leetcode-cn.com/problems/sort-colors/
+ *
+ * @author LuoHaiYang
+ */
+public class SortColors {
+
+ public void sortColors(int[] nums) {
+ if (nums == null || nums.length < 2) { + return; + } + sort(nums, 0, nums.length - 1); + } + + private void sort(int[] nums, int left, int right) { + if (left>= right) {
+ return;
+ }
+
+ int p = nums[left];
+ int i = left + 1, lt = left, gt = right + 1;
+
+ while (i < gt) { + if (nums[i] < p) { + swap(nums, i, lt + 1); + i++; + lt++; + } else if (nums[i]> p) {
+ swap(nums, i, gt - 1);
+ gt--;
+ } else {
+ i++;
+ }
+ }
+ swap(nums, left, lt);
+ sort(nums, left, lt - 1);
+ sort(nums, gt, right);
+ }
+
+ private void swap(int[] nums, int i, int j) {
+ int tmp = nums[i];
+ nums[i] = nums[j];
+ nums[j] = tmp;
+ }
+
+ public static void main(String[] args) {
+ SortColors sortColors = new SortColors();
+ int[] test = {0, 1};
+ sortColors.sortColors(test);
+ }
+}
diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/array/SubarraySumEqualsK.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/SubarraySumEqualsK.java
similarity index 98%
rename from src/main/java/com/bruis/algorithminjava/algorithm/array/SubarraySumEqualsK.java
rename to src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/SubarraySumEqualsK.java
index 82e703f..c7a7819 100644
--- a/src/main/java/com/bruis/algorithminjava/algorithm/array/SubarraySumEqualsK.java
+++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/SubarraySumEqualsK.java
@@ -1,4 +1,4 @@
-package com.bruis.algorithminjava.algorithm.array;
+package com.bruis.algorithminjava.algorithm.leetcode.array;
import java.util.HashMap;
import java.util.Map;
diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/array/ThreeSum.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ThreeSum.java
similarity index 98%
rename from src/main/java/com/bruis/algorithminjava/algorithm/array/ThreeSum.java
rename to src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ThreeSum.java
index 65d6ea4..435fa3a 100644
--- a/src/main/java/com/bruis/algorithminjava/algorithm/array/ThreeSum.java
+++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ThreeSum.java
@@ -1,4 +1,4 @@
-package com.bruis.algorithminjava.algorithm.array;
+package com.bruis.algorithminjava.algorithm.leetcode.array;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TopKFrequentElements.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TopKFrequentElements.java
new file mode 100644
index 0000000..705e368
--- /dev/null
+++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TopKFrequentElements.java
@@ -0,0 +1,69 @@
+package com.bruis.algorithminjava.algorithm.leetcode.array;
+
+import java.util.*;
+
+/**
+ *
+ * 前K个高频元素
+ *
+ * url:https://leetcode-cn.com/problems/top-k-frequent-elements/
+ *
+ * @author LuoHaiYang
+ */
+public class TopKFrequentElements {
+
+ /**
+ *
+ * 桶排序
+ *
+ */
+ public int[] topKFrequent(int[] nums, int k) {
+ List res = new ArrayList();
+
+ if (nums == null || nums.length < 2) { + return nums; + } + Map count = new LinkedHashMap();
+ int n = nums.length;
+
+ for (int i = 0; i < n; i++) { + if (count.containsKey(nums[i])) { + count.put(nums[i], count.get(nums[i]) + 1); + } else { + count.put(nums[i], 1); + } + } + + List[] list = new List[nums.length];
+ for (int key : count.keySet()) {
+ // 让频率作为下标
+ int i = count.get(key);
+ if (list[i] == null) {
+ list[i] = new ArrayList();
+ }
+ // key表示的是元素
+ list[i].add(key);
+ }
+
+ for (int i = list.length - 1; i>= 0 && res.size() < k; i--) { + if (list[i] == null) { + continue; + } + res.addAll(list[i]); + + } + int[] result = new int[res.size()]; + for (int i = 0; i < res.size(); i++) { + result[i] = res.get(i); + } + return result; + } + + public static void main(String[] args) { + TopKFrequentElements topKFrequentElements = new TopKFrequentElements(); + //int[] test = {1,1,1,2,2,3}; + int[] test = {3,0,1,0}; + topKFrequentElements.topKFrequent(test,1); + + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/array/TwoSum.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TwoSum.java similarity index 97% rename from src/main/java/com/bruis/algorithminjava/algorithm/array/TwoSum.java rename to src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TwoSum.java index 6d8097e..08d7dcc 100644 --- a/src/main/java/com/bruis/algorithminjava/algorithm/array/TwoSum.java +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TwoSum.java @@ -1,4 +1,4 @@ -package com.bruis.algorithminjava.algorithm.array; +package com.bruis.algorithminjava.algorithm.leetcode.array; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TwoSumII.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TwoSumII.java new file mode 100644 index 0000000..deb5cff --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TwoSumII.java @@ -0,0 +1,38 @@ +package com.bruis.algorithminjava.algorithm.leetcode.array; + +/** + * 167: + * + * https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/description/?utm_source=LCUS&utm_medium=ip_redirect_q_uns&utm_campaign=transfer2china + * + * 思路:指针碰撞 + * + * @author LuoHaiYang + */ +public class TwoSumII { + + public int[] twoSum(int[] numbers, int target) { + + if (numbers.length < 2) { + return numbers; + } + + int left = 0, right = numbers.length - 1; + + while (left <= right) { + + int result = numbers[left] + numbers[right]; + + if (result == target) { + int[] res = {left + 1, right + 1}; + return res; + } else if (result> target) {
+ right --;
+ } else {
+ left ++;
+ }
+ }
+
+ return numbers;
+ }
+}
diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/BinarySearch.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/BinarySearch.java
new file mode 100644
index 0000000..b6de14f
--- /dev/null
+++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/BinarySearch.java
@@ -0,0 +1,31 @@
+package com.bruis.algorithminjava.algorithm.sort;
+
+/**
+ *
+ * 二分查找法
+ *
+ * @author LuoHaiYang
+ */
+public class BinarySearch {
+
+ public static int binarySearch(int[] arr, int n, int target) {
+
+ // 在 [left, right]范围里寻找target
+ int left = 0, right = n - 1;
+
+ while (left <= right) { + int mid = (right + left) / 2; + int nums = arr[mid]; + + if (nums == target) { + return mid; + } else if (nums> target) {
+ left = mid + 1;
+ } else {
+ // nums < target + right = mid - 1; + } + } + return -1; + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/BucketSort.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/BucketSort.java new file mode 100644 index 0000000..08c7be4 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/BucketSort.java @@ -0,0 +1,57 @@ +package com.bruis.algorithminjava.algorithm.sort; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 桶排序 + * + * @author LuoHaiYang + */ +public class BucketSort { + /* 排序原理: + + 桶排序本质就是空间换时间:时间复杂度为:O(n) + + 顺序从待排数组中取出数字,首先6被取出,然后把6入6号桶,这个过程类似这样:空桶[ 待排数组[ 0 ] ] = 待排数组[ 0 ] + [6 2 4 1 5 9] 待排数组 + [0 0 0 0 0 0 6 0 0 0] 空桶 + [0 1 2 3 4 5 6 7 8 9] 桶编号(实际不存在) + 顺序从待排数组中取出下一个数字,此时2被取出,将其放入2号桶,是几就放几号桶 + [6 2 4 1 5 9] 待排数组 + [0 0 2 0 0 0 6 0 0 0] 空桶 + [0 1 2 3 4 5 6 7 8 9] 桶编号(实际不存在) + 3,4,5,6省略,过程一样,全部入桶后变成下边这样 + [6 2 4 1 5 9] 待排数组 + [0 1 2 0 4 5 6 0 0 9] 空桶 + [0 1 2 3 4 5 6 7 8 9] 桶编号(实际不存在) + */ + private int range = 0; + public BucketSort(int range) { + this.range = range; + } + public int[] doSort(int[] arr) { + // 集合数组 + List[] aux = new LinkedList[range];
+ for (int i = 0; i < aux.length; i++) { + aux[i] = new LinkedList();
+ }
+ for (int i = 0; i < arr.length; i++) { + aux[arr[i]].add(arr[i]); + } + for (int i = 0, j = 0; i < aux.length && j < arr.length; i++) { + for (int v : aux[i]) { + arr[j] = v; + j++; + } + } + return arr; + } + + public static void main(String[] args) { + BucketSort bucketSort = new BucketSort(10); + int[] sort = bucketSort.doSort(new int[]{4, 1, 3, 2, 20, 6, 9, 9, 21, 19}); + System.out.println(Arrays.toString(sort)); + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/Heap.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/Heap.java new file mode 100644 index 0000000..f593c19 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/Heap.java @@ -0,0 +1,122 @@ +package com.bruis.algorithminjava.algorithm.sort; + +/** + * 此堆索引从0开始 + * + * @Description + * @Author luohaiyang + * @Date 2022/4/20 + */ +public class Heap { + private int[] data; + private int count; + private int capacity; + + /** + * + * + * + * a + 1 + b c + 2 3 + d e f g + 4 5 6 7 + q w r x + 8 9 10 11 + * + * + * + * + */ + + /** + * 初始化堆 + * @param capacity + */ + public Heap(int capacity) { + this.capacity = capacity; + data = new int[capacity+1]; + count = 0; + } + + public Heap(int[] data, int capacity) { + this.data = data; + heapify(capacity); + } + + /** + * 新增一个元素 + * @param value + */ + public void insert(int value) { + if (count + 1> capacity) {
+ // 抛异常
+ }
+ data[++count] = value;
+ shiftUp(count);
+ }
+
+ /**
+ * 获取堆顶值
+ * @return
+ */
+ public int extractMax() {
+ if (count < 1) { + // 抛异常 + } + int max = data[1]; + swap(1, count--); + shiftDown(1); + return max; + } + + /** + * 堆化 + */ + public void heapify(int k) { + while (k/2>= 1) {
+ shiftDown(k/2);
+ k--;
+ }
+ }
+
+ public int size() {
+ return count;
+ }
+
+ public boolean isEmpty() {
+ return count == 0;
+ }
+
+ /**
+ * 上浮操作
+ * @param k
+ */
+ private void shiftUp(int k) {
+ while (k> 1 && data[k]> data[k/2]) {
+ swap(k, k/2);
+ k /= 2;
+ }
+ }
+
+ /**
+ * 下层操作
+ * @param k
+ */
+ private void shiftDown(int k) {
+ while (count>= k * 2) {
+ int j = k * 2;
+ if (j+1 <= count && data[j] < data[j+1]) j++; + if (data[k]>= data[j]) break;
+ swap(k, j);
+ k = j;
+ }
+ }
+
+ private void swap(int a, int b) {
+ int tmp = data[a];
+ data[a] = data[b];
+ data[b] = tmp;
+ }
+}
diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort01.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort01.java
new file mode 100644
index 0000000..00328b6
--- /dev/null
+++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort01.java
@@ -0,0 +1,101 @@
+package com.bruis.algorithminjava.algorithm.sort;
+
+import java.util.Random;
+
+/**
+ *
+ * 借助辅助空间进行堆排序
+ *
+ * @author LuoHaiYang
+ */
+public class HeapSort01 {
+
+ /**
+ * 堆化完后并没有排序完成
+ * @param arr
+ */
+ private static void heapify(int[] arr) {
+ int n = arr.length;
+ for (int i = n/2; i> 0; i--) {
+ shiftDown(i, n, arr);
+ }
+ }
+
+ /**
+ * 获取最大堆中堆顶元素
+ */
+ private static int extractMax(int[] arr) {
+ int n = arr.length;
+ int max = arr[0];
+ swap(arr, 0, --n);
+ // 让最后一个元素置0
+ arr[n] = 0;
+ shiftDown(0, n, arr);
+ return max;
+ }
+
+ /**
+ * 下沉操作
+ * @param k
+ */
+ private static void shiftDown(int k, int n, int[] arr) {
+ while (k * 2 + 1 < n) { + // 左子树节点 + int j = k * 2 + 1; + if (j + 1 < n && arr[j + 1]> arr[j]) {
+ j++;
+ }
+ if (arr[k]>= arr[j]) {
+ break;
+ }
+ swap(arr, k, j);
+ k = j;
+ }
+ }
+
+ /**
+ * 上浮操作
+ * @param k
+ */
+ private void shiftUp(int k, int[] arr) {
+ while (k> 0 && arr[(k-1)/ 2] < arr[k]) { + swap(arr, (k-1)/2, k); + k = (k-1)/2; + } + } + + private static void swap(int[] arr, int i, int j) { + int tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } + + public static int[] sort(int[] arr) { + int n = arr.length; + heapify(arr); + int[] result = new int[n]; + for (int i = 0; i < n; i++) { + result[i] = extractMax(arr); + } + return result; + } + + public static void main(String[] args) { + int n = 100; + int[] test = new int[n]; + Random random = new Random(); + for (int i = 0; i < n; i++) { + test[i] = random.nextInt(1000); + } + + sort(test); + + // 测试 + for (int i = 1; i < n; i++) { + if (test[i-1] < test[i]) { + System.out.println("Error!"); + } + } + + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort02.java similarity index 95% rename from src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort.java rename to src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort02.java index ca959cd..825987a 100644 --- a/src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort.java +++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort02.java @@ -1,16 +1,14 @@ package com.bruis.algorithminjava.algorithm.sort; -import java.util.Random; - /** * * 原地堆排序! 不需要额外的空间 * - * 这里构造出来的是一个最小堆!!!! 即数组的值依次递增 + * 这里构造出来的是一个最小堆 * * @author LuoHaiYang */ -public class HeapSort { +public class HeapSort02 { public static void sort(int[] arr) { int n = arr.length; diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/MergeSortBU.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/MergeSortBU.java new file mode 100644 index 0000000..92dc91a --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/MergeSortBU.java @@ -0,0 +1,44 @@ +package com.bruis.algorithminjava.algorithm.sort; + +import java.util.Arrays; + +/** + * + * 归并排序(自底向上) + * + * @author LuoHaiYang + */ +public class MergeSortBU { + private static void merge(int[] arr, int left, int mid, int right) { + int[] aux = Arrays.copyOfRange(arr, left, right + 1); + + int i = left, j = right + 1; + for (int k = 0; k <= right; k++) { + if (i> mid) {
+ arr[k] = aux[j - left];
+ j++;
+ } else if (j> right) {
+ arr[k] = aux[i - left];
+ i++;
+ } else if (aux[i - left]> aux[j - left]) {
+ arr[k] = aux[j - left];
+ j++;
+ } else {
+ arr[k] = aux[i - left];
+ i++;
+ }
+ }
+ }
+
+ // [a, b, c, d, e, f, g, h, i]
+ // [a,b] [c,d] [e,f] [g,h]
+ public static void sort(int[] arr) {
+ int n = arr.length;
+
+ for (int sz = 1; sz < n; sz *= 2) { + for (int i = 0; i < n - sz; i += sz + sz) { + merge(arr, i, i+sz-1, Math.min(i+sz+sz-1, n-1)); + } + } + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort.java index d10c21b..fd9c3ed 100644 --- a/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort.java +++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort.java @@ -28,8 +28,8 @@ private static int partition(int[] arr, int left, int right) { j++; swap(arr, j, i); } - swap(arr, left, j); } + swap(arr, left, j); return j; } diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort2.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort2.java new file mode 100644 index 0000000..0c1b172 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort2.java @@ -0,0 +1,65 @@ +package com.bruis.algorithminjava.algorithm.sort; + +/** + * 快速排序的优化 + * + * 对于近乎有序的数组,快速排序会退化为O(n^2)。 + * + * @author LuoHaiYang + */ +public class QuickSort2 { + + /** + * 对arr[left...right]部分进行partition操作 + * 返回p, 使得arr[left...p-1] < arr[p] ; arr[p+1...right]> arr[p]
+ *
+ * @param arr
+ * @param left
+ * @param right
+ * @return
+ */
+ private static int partition(int[] arr, int left, int right) {
+
+ //int p = arr[left];
+ // ===================================== 优化2 =====================================
+ // 避免快排退化为O(n^2)
+ swap(arr, left, (int)Math.random()*(right - left + 1) + left);
+
+ int p = arr[left];
+
+ // arr[left+1...j] < p; arr[j+1...i)> p
+ int j = left;
+ for (int i = left + 1; i <= right; i++) { + if (arr[i] < p) { + j++; + swap(arr, j, i); + } + } + swap(arr, left, j); + return j; + } + + private static void sort(int[] arr, int left, int right) { + // ===================================== 优化1 ===================================== + // 如果左右数值小于15,则通过插入排序来进行排序 + if (right - left <= 15) { + InsertionSort.sort(arr); + return; + } + + int p = partition(arr, left, right); + sort(arr, left, p-1); + sort(arr, p+1, right); + } + + public static void sort(int[] arr) { + int n = arr.length; + sort(arr, 0, n-1); + } + + private static void swap(int[] arr, int i, int j) { + int tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort2Ways.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort2Ways.java new file mode 100644 index 0000000..7c8bf9d --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort2Ways.java @@ -0,0 +1,64 @@ +package com.bruis.algorithminjava.algorithm.sort; + +/** + * + * 双路快排 + * + * @author LuoHaiYang + */ +public class QuickSort2Ways { + + private static int partition(int[] arr, int left, int right) { + + swap(arr, left, (int)Math.random()*(right - left + 1) + left); + + int p = arr[left], i = left + 1, j = right; + + while(true) { + + /** + * 这里arr[i] < p 和 arr[j]> p 是为了避免出现 arr[i] == p 和 arr[j] == p的情况。
+ * 如果arr[i] == p,则直接进行了i++了,则数组的p会变得极度不平衡,即 所有小于等于p的值都分在了左边,
+ * 这种情况下,快速排序的平均时间复杂度会退化成:O(n^2)
+ *
+ */
+
+ while(i <= right && arr[i] < p) { + i++; + } + while(j>= 0 && arr[j]> p) {
+ j--;
+ }
+
+ if (i> j) {
+ break;
+ }
+
+ swap(arr, i++, j--);
+ }
+ swap(arr, left, j);
+ return j;
+ }
+
+ private static void sort(int[] arr, int left, int right) {
+ if (right - left <= 15) { + InsertionSort.sort(arr); + return; + } + + int p = partition(arr, left, right); + sort(arr, left, p - 1); + sort(arr, p + 1, right); + } + + public static void sort(int[] arr) { + int n = arr.length; + sort(arr, 0, n - 1); + } + + public static void swap(int[] arr, int i, int j) { + int tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort3Ways.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort3Ways.java new file mode 100644 index 0000000..fbf5c50 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort3Ways.java @@ -0,0 +1,58 @@ +package com.bruis.algorithminjava.algorithm.sort; + +/** + * + * 三路快排 + * + * @author LuoHaiYang + */ +public class QuickSort3Ways { + + private static void sort(int[] arr, int left, int right) { + if (right - left <= 15) { + InsertionSort.sort(arr); + return; + } + // 增加随机值,防止快排退化为O(n^2) + swap(arr,left, (int)Math.random()*(right - left - 1) + left); + + int p = arr[left]; + + // [p...................................................right] + // p + // lt + // i + // gt + // arr[left+1...lt] < p arr[lt+1...i) = p arr[gt...right]> p
+ int lt = left, gt = right + 1, i = left + 1;
+
+ while ( i < gt) { + if (arr[i] < p) { + swap(arr, lt+1, i); + i++; + lt++; + } else if (arr[i]> p) {
+ swap(arr, i, gt-1);
+ gt--;
+ } else {// arr[i] == v
+ i++;
+ }
+ }
+ swap(arr, left, lt);
+ // 继续对[left,lt]进行排序
+ sort(arr, left, lt-1);
+ // 继续对[gt, right]进行排序
+ sort(arr, gt, right);
+ }
+
+ public static void sort(int[] arr) {
+ int n = arr.length;
+ sort(arr, 0, n-1);
+ }
+
+ private static void swap(int[] arr, int i, int j) {
+ int tmp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = tmp;
+ }
+}
diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/ShellSort.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/ShellSort.java
new file mode 100644
index 0000000..d084aef
--- /dev/null
+++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/ShellSort.java
@@ -0,0 +1,32 @@
+package com.bruis.algorithminjava.algorithm.sort;
+
+/**
+ *
+ * 希尔排序
+ *
+ * @author LuoHaiYang
+ */
+public class ShellSort {
+ public static void sort(int[] arr) {
+ int n = arr.length;
+
+ int h = 1;
+
+ while (h < n / 3) { + h = 3 * h + 1; + } + + while (h>= 1) {
+ for (int i = h; i < n; i++) { + int e = arr[i]; + int j = i; + for (; j>= h && e < arr[j-h]; j -= h) { + arr[j] = arr[j-h]; + } + arr[j] = e; + } + + h /= 3; + } + } +} diff --git a/src/main/java/com/bruis/algorithminjava/datastructures/heap/IndexMapHeap.java b/src/main/java/com/bruis/algorithminjava/datastructures/heap/IndexMapHeap.java new file mode 100644 index 0000000..6de104a --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/datastructures/heap/IndexMapHeap.java @@ -0,0 +1,239 @@ +package com.bruis.algorithminjava.datastructures.heap; + +import java.util.Arrays; +import java.util.Random; + +/** + * + * 索引堆 + * + * @author LuoHaiYang + */ +public class IndexMapHeap { + /** + * 存储数据的数组 + */ + private int[] arr; + /** + * index元素值就是arr的索引 + */ + private int[] index; + /** + * 数组存储容量大小 + */ + private int count; + /** + * 容量 + */ + private int capacity; + + public IndexMapHeap(int capacity) { + this.capacity = capacity; + this.count = 0; + // 让索引从0开始 + arr = new int[capacity + 1]; + // 让索引从0开始 + index = new int[capacity + 1]; + } + + public boolean isEmpty() { + return count == 0; + } + + public int size() { + return count; + } + + + /** + * 插入新元素 + * @param i + * @param item + */ + public void insert(int i, int item) { + if (i + 1> capacity) {
+ throw new IllegalArgumentException("容量已满, 插入失败");
+ }
+
+ arr[++i] = item;
+ index[++count] = i;
+ shiftUp(count);
+ }
+
+ /**
+ * 获取最大索引堆中所以为i的元素
+ * @param i
+ * @return
+ */
+ public int getItem(int i) {
+ if (i < 0 && i + 1> capacity) {
+ throw new IllegalArgumentException("错误!索引越界.");
+ }
+ return arr[i+1];
+ }
+
+ /**
+ * 获取索引堆中堆顶的元素(注意堆中元素是arr的索引,即index数组的元素)
+ * @return
+ */
+ public int getMaxIndex() {
+ if (count < 1) { + throw new IllegalArgumentException("异常!堆中没有元素!"); + } + // 由于索引堆中元素也是从1开始,所以需要-1,从0开始。 + return index[1] - 1; + } + + /** + * 获取最大索引堆中堆顶元素的值,即索引堆中存储的最大数据 + * @return + */ + public int extractMax() { + if (count < 1) { + throw new IllegalArgumentException("错误!索引堆中不存在元素"); + } + int ret = arr[index[1]]; + // 取出堆顶元素数据后,需要把最大元素和index末尾元素进行替换,然后做下沉操作 + swap(index, 1, count); + count--; + shiftDown(1); + return ret; + } + + /** + * 获取最大索引堆中堆顶的索引 + * @return + */ + public int extractMaxIndex() { + if (count < 1) { + throw new IllegalArgumentException("错误!索引堆中不存在元素"); + } + int ret = index[1] - 1; + swap(index, 1, count); + count--; + shiftDown(1); + return ret; + } + + // ============================= 上浮操作 ============================= + + /** + * 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引 + * @param k + */ + private void shiftUp(int k) { + // 堆顶元素则直接跳过 + while (k> 1 && arr[index[k/2]] < arr[index[k]]) { + swap(index, k, k/2); + k /= 2; + } + } + + // ============================= 下沉操作 ============================= + + /** + * 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引 + * + * 由于是由1开始计算索引,所以左子树为 2*k + * + * @param k + */ + private void shiftDown(int k) { + // 如果左子树所以 <= 元素总数 + while ( 2 * k <= count) { + int j = 2 * k; + if (j + 1 <= count && arr[index[j+1]]> arr[index[j]]) {
+ j++;
+ }
+ if (arr[index[k]]>= arr[index[j]]) {
+ break;
+ }
+ // 更换索引值
+ swap(index, k, j);
+ k = j;
+ }
+ }
+
+ // ============================= 更新堆元素优先级 =============================
+
+ /**
+ *
+ *
+ *
+ * @param i
+ * @param item
+ */
+ public void change(int i, int item) {
+ i++;
+ // 将所有堆中索引为i的元素修改为item
+ arr[i] = item;
+
+ // 由于直接在i位置修改为新元素;
+ // 所以需要查找出 index[j] = i的位置,即arr[index[j]] = item;
+ // 然后上浮和下沉(先后顺序不影响)
+ for (int j = 1; j <= count; j++) { + if (index[j] == i) { + shiftUp(j); + shiftDown(j); + return; + } + } + } + + private void swap(int[] arr, int i, int k) { + int tmp = arr[i]; + arr[i] = arr[k]; + arr[k] = tmp; + } + + // ============================= 更新堆元素优先级 ============================= + + public boolean testIndexes() { + int[] copyIndex = new int[count + 1]; + + for (int i = 0; i <= count; i++) { + copyIndex[i] = index[i]; + } + + copyIndex[0] = 0; + Arrays.sort(copyIndex); + + for (int i = 2; i <= count; i++) { + if (copyIndex[i-1] + 1 != copyIndex[i]) { + System.out.println("错误,索引堆排序错误!"); + break; + } + } + return true; + } + + public void testSort(int[] arr) { + for (int i = 1; i < arr.length; i++) { + if (arr[i-1] < arr[i]) { + System.out.println("索引堆排序失败!"); + } + } + } + + public static void main(String[] args) { + int n = 10; + IndexMapHeap indexMapHeap = new IndexMapHeap(n); + Random random = new Random(); + for (int i = 0; i < n; i++) { + // insert中仅仅一个shiftUp操作是不能保证索引堆数据的排好序了 + indexMapHeap.insert(i,random.nextInt(1000)); + } + + // 判断索引堆索引是否是连续 + System.out.println(indexMapHeap.testIndexes()); + + int[] result = new int[n]; + for (int i = 0; i < n; i++) { + result[i] = indexMapHeap.extractMax(); + } + + indexMapHeap.testSort(result); + + } + +} diff --git a/src/main/java/com/bruis/algorithminjava/utils/SortTestHelper.java b/src/main/java/com/bruis/algorithminjava/utils/SortTestHelper.java new file mode 100644 index 0000000..12ab6b2 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/utils/SortTestHelper.java @@ -0,0 +1,156 @@ +package com.bruis.algorithminjava.utils; + +import java.lang.reflect.Method; + +/** + * @author LuoHaiYang + */ +public class SortTestHelper { + /** + * SortTestHelper不允许产生任何实例 + */ + private SortTestHelper(){} + + /** + * 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] + * @param n + * @param rangeL + * @param rangeR + * @return + */ + public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) { + + assert rangeL <= rangeR; + + Integer[] arr = new Integer[n]; + + for (int i = 0; i < n; i++) { + arr[i] = new Integer((int) (Math.random() * (rangeR - rangeL + 1) + rangeL)); + } + return arr; + } + + /** + * 生成一个近乎有序的数组 + * 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 + * swapTimes定义了数组的无序程度: + * swapTimes == 0 时, 数组完全有序 + * swapTimes 越大, 数组越趋向于无序 + * @param n + * @param swapTimes + * @return + */ + public static Integer[] generateNearlyOrderedArray(int n, int swapTimes){ + + Integer[] arr = new Integer[n]; + for( int i = 0 ; i < n ; i ++ ) { + arr[i] = new Integer(i); + } + + for( int i = 0 ; i < swapTimes ; i ++ ){ + int a = (int)(Math.random() * n); + int b = (int)(Math.random() * n); + int t = arr[a]; + arr[a] = arr[b]; + arr[b] = t; + } + + return arr; + } + + /** + * 打印arr数组的所有内容 + * @param arr + */ + public static void printArray(Object[] arr) { + + for (int i = 0; i < arr.length; i++){ + System.out.print( arr[i] ); + System.out.print( ' ' ); + } + System.out.println(); + + return; + } + + /** + * 判断arr数组是否有序 + * @param arr + * @return + */ + public static boolean isSorted(Comparable[] arr){ + + for( int i = 0 ; i < arr.length - 1 ; i ++ ) { + if (arr[i].compareTo(arr[i + 1])> 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 测试sortClassName所对应的排序算法排序arr数组所得到结果的正确性和算法运行时间
+ * 将算法的运行时间打印在控制台上
+ * @param sortClassName
+ * @param arr
+ */
+ public static void testSort(String sortClassName, Comparable[] arr){
+
+ // 通过Java的反射机制,通过排序的类名,运行排序函数
+ try{
+ // 通过sortClassName获得排序函数的Class对象
+ Class sortClass = Class.forName(sortClassName);
+ // 通过排序函数的Class对象获得排序方法
+ Method sortMethod = sortClass.getMethod("sort",new Class[]{Comparable[].class});
+ // 排序参数只有一个,是可比较数组arr
+ Object[] params = new Object[]{arr};
+
+ long startTime = System.currentTimeMillis();
+ // 调用排序函数
+ sortMethod.invoke(null,params);
+ long endTime = System.currentTimeMillis();
+
+ assert isSorted( arr );
+
+ System.out.println( sortClass.getSimpleName()+ " : " + (endTime-startTime) + "ms" );
+ }
+ catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 测试sortClassName所对应的排序算法排序arr数组所得到结果的正确性和算法运行时间
+ * 将算法的运行时间以long类型返回, 单位为毫秒(ms)
+ *
+ * @param sortClassName
+ * @param arr
+ * @return
+ */
+ public static long testSort2(String sortClassName, Comparable[] arr){
+
+ // 通过Java的反射机制,通过排序的类名,运行排序函数
+ try{
+ // 通过sortClassName获得排序函数的Class对象
+ Class sortClass = Class.forName(sortClassName);
+ // 通过排序函数的Class对象获得排序方法
+ Method sortMethod = sortClass.getMethod("sort",new Class[]{Comparable[].class});
+ // 排序参数只有一个,是可比较数组arr
+ Object[] params = new Object[]{arr};
+
+ long startTime = System.currentTimeMillis();
+ // 调用排序函数
+ sortMethod.invoke(null,params);
+ long endTime = System.currentTimeMillis();
+
+ assert isSorted( arr );
+
+ return endTime - startTime;
+ }
+ catch(Exception e){
+ e.printStackTrace();
+ }
+
+ return 0;
+ }
+}