文章目录
对数器
测试代码正确性
//对数器测试
//测试用的
//产生随机数组
public static void comparator(int[] arr) {
Arrays.sort(arr);
}
// for test 随机产生数组
public static int[] generateRandomArray(int maxSize, int maxValue) {
int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
}
return arr;
}
// for test
public static int[] copyArray(int[] arr) {
if (arr == null) {
return null;
}
int[] res = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
res[i] = arr[i];
}
return res;
}
// for test
public static boolean isEqual(int[] arr1, int[] arr2) {
if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
return false;
}
if (arr1 == null && arr2 == null) {
return true;
}
if (arr1.length != arr2.length) {
return false;
}
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
// for test
public static void printArray(int[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
// for test
public static void main(String[] args) {
int testTime = 500000;
int maxSize = 100;
int maxValue = 100;
boolean succeed = true;
for (int i = 0; i < testTime; i++) {
int[] arr1 = generateRandomArray(maxSize, maxValue);
int[] arr2 = copyArray(arr1);
int[] arr3 = copyArray(arr1);
newQuickSort(arr2);
comparator(arr3);
if (!isEqual(arr2, arr3)) {
succeed = false;
printArray(arr1);
printArray(arr2);
printArray(arr3);
break;
}
}
System.out.println(succeed ? "Nice!" : "Fucking fucked!");
int[] arr = generateRandomArray(maxSize, maxValue);
printArray(arr);
newQuickSort(arr);
printArray(arr);
}
交换
public static void swap(int [] nums, int i, int j){
nums[i] = nums[i] ^ nums[j];
nums[j] = nums[i] ^ nums[j];
nums[i] = nums[i] ^ nums[j];
}
public static void swap(int [] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
1. 冒泡排序
//时间复杂度严格为O(N^2)
public static void bubbleSort(int [] nums){
if(nums == null || nums.length < 2)
return;
for(int end = nums.length - 1; end >= 0; end -- ){
for(int i = 0; i < end; i++){
if(nums[i] > nums[i + 1])
utils.swap(nums, i , i+1);
}
}
}
2. 选择排序
public static void selectSort(int[] nums){
if (nums == null || nums.length < 2)
return;
for (int i = 0; i < nums.length; i++) {
int minIndex = i;
for (int j = i + 1; j < nums.length; j++) {
if(nums[j] < nums[minIndex])
minIndex = j;
}
utils.swap(nums, i, minIndex);
//utils.swap(nums, i, minIndex); //为什么会出错
}
}
3. 插入排序
小样本情况下,排序常数项很低,性能很好,常常和快排,归并结合在一起。
//好的情况为:O(N)
//一般情况:O(N^2)
//和数据情况有关系
public static void insertSort(int[] nums){
if(nums == null || nums.length < 2)
return;
for(int i = 1; i < nums.length; i++){
for(int j = i - 1; j >= 0 && nums[j] > nums[j + 1]; j-- )
utils.swap(nums, j, j+1);
}
}
4. 归并排序: 自己定义的类型
先递归在求解
//归并排序
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
mergeSort(arr, 0, arr.length - 1);
}
public static void mergeSort(int[] arr, int left, int right) {
if (left == right) {
return;
}
int mid = left + ((right - left) >> 1);
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
public static void merge(int[] arr, int left, int m, int right) {
int[] help = new int[right - left + 1];
int i = 0;
int p1 = left;
int p2 = m + 1;
while (p1 <= m && p2 <= right) {
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= m) {
help[i++] = arr[p1++];
}
while (p2 <= right) {
help[i++] = arr[p2++];
}
for (i = 0; i < help.length; i++) {
arr[left + i] = help[i];
}
}
比较器
import java.util.Arrays;
import java.util.Comparator;
public class Comparator {
public static class Student {
public String name;
public int id;
public int age;
public Student(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
}
public static class IdAscendingComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.id - o2.id;
}
}
public static class IdDescendingComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o2.id - o1.id;
}
}
public static class AgeAscendingComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age;
}
}
public static class AgeDescendingComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o2.age - o1.age;
}
}
public static void printStudents(Student[] students) {
for (Student student : students) {
System.out.println("Name : " + student.name + ", Id : " + student.id + ", Age : " + student.age);
}
System.out.println("===========================");
}
public static void main(String[] args) {
Student student1 = new Student("A", 1, 23);
Student student2 = new Student("B", 2, 21);
Student student3 = new Student("C", 3, 22);
Student[] students = new Student[] { student3, student2, student1 };
printStudents(students);
Arrays.sort(students, new IdAscendingComparator());
printStudents(students);
Arrays.sort(students, new IdDescendingComparator());
printStudents(students);
Arrays.sort(students, new AgeAscendingComparator());
printStudents(students);
Arrays.sort(students, new AgeDescendingComparator());
printStudents(students);
}
}
5. 快速排序:基础类型(int,double,float,char,short,long)
先求解在递归
package sortAlgorithm;
import java.util.Arrays;
public class QuickSort {
/**
* 时间复杂度:
* 最好:O(nlogn)
* 最坏: O(n^2)
* 平均: O(nlogn)
* 空间复杂度:O(logn ~ n)
* 稳定性: 不稳定
* @param nums
* @param left
* @param right
*/
public static void quickSort(int[] nums, int left, int right) {
if(left < right) {
int pivot = partition(nums, left, right);
quickSort(nums, left, pivot - 1);
quickSort(nums, pivot + 1, right);
}
}
public static int partition(int[] nums, int left, int right) {
int pivotIndex = left;
int pivot = nums[pivotIndex];
int l = left + 1;
int r = right;
// System.out.println("pivot: " + pivot + " 当前结果: " + Arrays.toString(nums));
// System.out.println("pivotIndex: " + pivotIndex + "; l,r: " + l + " " + r);
while(l <= r) {
if(nums[l] > pivot && nums[r] < pivot){
swap(nums, l++, r--);
System.out.println("排序过程:" + Arrays.toString(nums));
}
if(nums[l] <= pivot) l++;
if(nums[r] >= pivot) r--; //与pivot小的元素交换
}
swap(nums, pivotIndex, r);
// System.out.println("此轮结束:" + Arrays.toString(nums));
// System.out.println();
return r;
}
public static void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public static void main(String[] args) {
int [] nums = new int[]{5,2,9,4,7,6,1,3,8};
quickSort(nums, 0, nums.length - 1);
// System.out.println(Arrays.toString(nums));
}
}
优化:
public static void newQuickSort(int[] nums){
if(nums == null || nums.length == 0)
return;
newQuickSort1(nums, 0, nums.length - 1);
}
public static void newQuickSort1(int[] nums, int left, int right){
if(left < right){
swap(nums, left + (int)(Math.random() *(right - left + 1)), right);
int[] p = partition(nums, left, right);
newQuickSort1(nums, left, p[0] - 1);
newQuickSort1(nums, p[1] + 1, right);
}
}
public static int[] partition(int[] nums, int left, int right){
int less = left - 1;
int more = right;
while(left < more){
if(nums[left] < nums[right]){
swap(nums, ++less, left++);
} else if(nums[left] > nums[right]){
swap(nums, --more, left);
} else{
left++;
}
}
swap(nums, more, right);
return new int[]{less + 1, more};
}
6. 堆排序(完全二叉树)
大根堆,小根堆。从0开始(用数组存储)
左子树:2i + 1
右子树:2i + 2
父节点: (i - 1)/ 2
大根堆排序如下:
public static void heapSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 0; i < arr.length; i++) {
heapInsert(arr, i);
}
int size = arr.length;
swap(arr, 0, --size);
while (size > 0) {
heapify(arr, 0, size);
swap(arr, 0, --size);
}
}
//完全二叉树,插入后调整成大根堆。 只需比较插入节点和父节点之间的大小
public static void heapInsert(int[] arr, int index) {
while (arr[index] > arr[(index - 1) / 2]) { //子节点大于父节点,向上调整
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
public static void heapify(int[] arr, int index, int size) {
int left = index * 2 + 1;
while(left < size){
int larger = left + 1 < size && nums[left + 1] > nums[left] ? left + 1 : left;
if(nums[larger] > nums[index]){
swap(nums, larger, index);
index = larger;
left = index * 2 + 1;
} else break;
}
}
对于贪心算法,堆结构很重要。
例题: 对于一个的吐数器,不断吐出数来,每次吐出数要求能求出吐出数的中位数。
思路:大根堆里面存储吐出2/n的较小的数, 小根堆里面储存吐出2/n的较大的数。
若数为奇数,返回大根堆中的第一个数。
若数为偶数,返回大根堆和小根堆中第一个数的平均值。
优先级队列底层就是堆
priorityQueue<Student> heap = new PriorityQueue<>();
比较器不给,他就会按照内存地址排序
priorityQueue<Student> heap = new PriorityQueue<>(IdAscendingComparator);
桶排序,计数排序和基数排序的介绍
1,非基于比较的排序,与被排序的样本的实际数据状况很有关系,所以实际中并不经常使用
2,时间复杂度O(N),额外空间复杂度O(N)
3,稳定的排序
桶排序:统计。
桶:容器。
给定一个数据,求如果排序之后,相邻两数最大差值,要求时间复杂度O(N),且要求不能用非基于比较的排序。
public static int maxGap(int[] nums) {
if (nums == null || nums.length < 2) {
return 0;
}
int len = nums.length;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 0; i < len; i++) {
min = Math.min(min, nums[i]);
max = Math.max(max, nums[i]);
}
if (min == max) {
return 0;
}
boolean[] hasNum = new boolean[len + 1];
int[] maxs = new int[len + 1];
int[] mins = new int[len + 1];
int bid = 0;
for (int i = 0; i < len; i++) {
bid = bucket(nums[i], len, min, max);
mins[bid] = hasNum[bid] ? Math.min(mins[bid], nums[i]) : nums[i];
maxs[bid] = hasNum[bid] ? Math.max(maxs[bid], nums[i]) : nums[i];
hasNum[bid] = true;
}
int res = 0;
int lastMax = maxs[0];
for (int i = 1; i <= len; i++) {
if (hasNum[i]) {
res = Math.max(res, mins[i] - lastMax);
lastMax = maxs[i];
}
}
return res;
}
public static int bucket(long num, long len, long min, long max) {
return (int) ((num - min) * len / (max - min));
}
// for test
public static int comparator(int[] nums) {
if (nums == null || nums.length < 2) {
return 0;
}
Arrays.sort(nums);
int gap = Integer.MIN_VALUE;
for (int i = 1; i < nums.length; i++) {
gap = Math.max(nums[i] - nums[i - 1], gap);
}
return gap;
}
// for test
public static int[] generateRandomArray(int maxSize, int maxValue) {
int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
}
return arr;
}
// for test
public static int[] copyArray(int[] arr) {
if (arr == null) {
return null;
}
int[] res = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
res[i] = arr[i];
}
return res;
}
// for test
public static void main(String[] args) {
int testTime = 500000;
int maxSize = 100;
int maxValue = 100;
boolean succeed = true;
for (int i = 0; i < testTime; i++) {
int[] arr1 = generateRandomArray(maxSize, maxValue);
int[] arr2 = copyArray(arr1);
if (maxGap(arr1) != comparator(arr2)) {
succeed = false;
break;
}
}
System.out.println(succeed ? "Nice!" : "Fucking fucked!");
}