常见排序算法
概览比较
排序算法
时间复杂度(平均)
时间复杂度(最坏)
时间复杂度(最好)
空间复杂度
稳定性
冒泡排序
O(n^2)
O(n^2)
O(n)
O(1)
稳定
选择排序
O(n^2)
O(n^2)
O(n^2)
O(1)
不稳定
插入排序
O(n^2)
O(n^2)
O(n)
O(1)
稳定
希尔排序
O(n log n)
O(n^2)
O(n)
O(1)
不稳定
归并排序
O(n log n)
O(n log n)
O(n log n)
O(n)
稳定
快速排序
O(n log n)
O(n^2)
O(n log n)
O(log n)
不稳定
堆排序
O(n log n)
O(n log n)
O(n log n)
O(1)
不稳定
基数排序
O(n*k)
O(n*k)
O(n*k)
O(n+k)
稳定
冒泡排序 1 2 3 4 5 6 7 8 9 10 11 12 13 public void bubbleSort (int [] array) { int n = array.length; for (int i = 0 ; i < n - 1 ; i++) { for (int j = 0 ; j < n - i - 1 ; j++) { if (array[j] > array[j + 1 ]) { int temp = array[j]; array[j] = array[j + 1 ]; array[j + 1 ] = temp; } } } }
选择排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static void selectionSort (int [] array) { int n = array.length; for (int i = 0 ; i < n - 1 ; i++) { int minIndex = i; for (int j = i + 1 ; j < n; j++) { if (array[j] < array[minIndex]) { minIndex = j; } } int temp = array[minIndex]; array[minIndex] = array[i]; array[i] = temp; } }
插入排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void insertionSort (int [] array) { int n = array.length; for (int i = 1 ; i < n; i++) { int key = array[i]; int j = i - 1 ; while (j >= 0 && array[j] > key) { array[j + 1 ] = array[j]; j--; } array[j + 1 ] = key; } }
希尔排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static void shellSort (int [] array) { int n = array.length; for (int gap = n / 2 ; gap > 0 ; gap /= 2 ) { for (int i = gap; i < n; i++) { int key = array[i]; int j = i; while (j >= gap && array[j - gap] > key) { array[j] = array[j - gap]; j -= gap; } array[j] = key; } } }
归并排序(递归) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 mergeSort(array, 0 , array.length - 1 ); public static void mergeSort (int [] array, int left, int right) { if (left < right) { int mid = (left + right) / 2 ; mergeSort(array, left, mid); mergeSort(array, mid + 1 , right); merge(array, left, mid, right); } } public static void merge (int [] array, int left, int mid, int right) { int n1 = mid - left + 1 ; int n2 = right - mid; int [] leftArray = new int [n1]; int [] rightArray = new int [n2]; for (int i = 0 ; i < n1; i++) { leftArray[i] = array[left + i]; } for (int j = 0 ; j < n2; j++) { rightArray[j] = array[mid + 1 + j]; } int i = 0 , j = 0 , k = left; while (i < n1 && j < n2) { if (leftArray[i] <= rightArray[j]) { array[k] = leftArray[i]; i++; } else { array[k] = rightArray[j]; j++; } k++; } while (i < n1) { array[k] = leftArray[i]; i++; k++; } while (j < n2) { array[k] = rightArray[j]; j++; k++; } }
快速排序(递归) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public static void quickSort (int [] array, int low, int high) { if (low < high) { int partitionIndex = partition(array, low, high); quickSort(array, low, partitionIndex - 1 ); quickSort(array, partitionIndex + 1 , high); } } public static int partition (int [] array, int low, int high) { int pivot = array[high]; int i = low - 1 ; for (int j = low; j < high; j++) { if (array[j] < pivot) { i++; swap(array, i, j); } } swap(array, i + 1 , high); return i + 1 ; } public static void swap (int [] array, int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; }
堆排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public static void heapSort (int [] array) { int n = array.length; buildMaxHeap(array, n); for (int i = n - 1 ; i > 0 ; i--) { swap(array, 0 , i); heapify(array, i, 0 ); } } public static void buildMaxHeap (int [] array, int n) { for (int i = n / 2 - 1 ; i >= 0 ; i--) { heapify(array, n, i); } } public static void heapify (int [] array, int n, int i) { int largest = i; int left = 2 * i + 1 ; int right = 2 * i + 2 ; if (left < n && array[left] > array[largest]) { largest = left; } if (right < n && array[right] > array[largest]) { largest = right; } if (largest != i) { swap(array, i, largest); heapify(array, n, largest); } } public static void swap (int [] array, int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; }
基数排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public static void radixSort (int [] arr) { int max = Arrays.stream(arr).max().getAsInt(); int numDigits = (int ) Math.log10(max) + 1 ; int [][] buckets = new int [10 ][arr.length]; int [] bucketSizes = new int [10 ]; for (int digit = 0 ; digit < numDigits; digit++) { for (int num : arr) { int digitValue = (num / (int ) Math.pow(10 , digit)) % 10 ; buckets[digitValue][bucketSizes[digitValue]] = num; bucketSizes[digitValue]++; } int index = 0 ; for (int i = 0 ; i < 10 ; i++) { for (int j = 0 ; j < bucketSizes[i]; j++) { arr[index] = buckets[i][j]; index++; } bucketSizes[i] = 0 ; } } }
Java已集成好的排序 列表 1 2 3 4 5 Arrays.sort(); Arrays.parallelSort(); Collections.sort(); Arrays.sort(T[] a, Comparator<? super T> c); Collections.sort(List<T> list, Comparator<? super T> c);
集合 TreeSet 和TreeMap 默认按照红黑树 (数据结构)算法排序(通过红黑树来存储元素,并根据元素的自然顺序或者自定义的比较器来进行排序)
自定义比较器 涉及到 对象数组 的比较的情况,两种方法处理:
继承comparable 接口,并实现int compareTo(T o);
方法
定义一个单独的对象比较器,继承自Comparator 接口,实现 int compare(T o1, T o2);
方法
Comparable
Comparable是java.lang
包中的一个排序接口。
只要一个类实现了这个接口就可以意味着这个类支持排序。
实现了这个类的接口的列表或者数组可以可以使用Collections.sort 或Arrays.sort 进行排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Person implements Comparable <Person > { String name; int age; public Person (String name, int age) { this .name = name; this .age = age; } @Override public int compareTo (Person person) { return this .age - person.age; } public static void main (String[] args) { Person[] persons = new Person[]{new Person("tom" , 20 ), new Person("jack" , 12 )}; for (Person p : persons) { System.out.print("name:" + p.name + ", age:" + p.age + " " ); } Arrays.sort(persons); for (Person p : persons) { System.out.print("name:" + p.name + ", age:" + p.age + " " ); } } }
Comparator
Comparator是java.util中的一个比较的接口。
如果我们想要控制某个类的次序,而这个类并没有继承Comparable接口,那么我们就可以使用Comparator接口。
比较的规则:大致和上面的规则相同,不过也有不同的地方,详情请看下面的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public void test () { Comparator<Integer> comparator = new Comparator<>() { @Override public int compare (Integer o1, Integer o2) { return 0 ; } @Override public boolean equals (Object obj) { return false ; } }; Integer[] a = {1 , 2 , 2 , 9 }; Arrays.sort(a, comparator); } class PersonComparator implements Comparator <Person > { @Override public int compare (Person p1, Person p2) { return p1.age - p2.age; } } public class Test { public static void main (String[] args) { Person[] persons = new Person[]{new Person("tom" , 20 ), new Person("jack" , 12 )}; Arrays.sort(persons, new PersonComparator()); } }
注意:比较器的泛型类型 和 被比较列表 的数据类型保持一致
总结
两者不在一个包。Comparable在java.lang中,而Comparator在java.util包中。
实现Comparable的类通常是一个我们要经常使用的类。比如:java中的String类等等。需要修改源代码。而Comparator可以在不同修改源代码的情况下,来完成比较。从了保护了代码。
两个方法各有优劣。如果你的类需要经常使用比较的操作,那么可以考虑让这个了实现Comparable接口。如果你偶尔使用比较的操作,那么可以考虑使用Comparator。