所有算法代码下载可以访问此GitHub地址:https://github.com/pu2014/myAlgorithm
java 所有排序算法
java 常用的排序有Collections.sort 和 Arrays.sort的排序方法其中Collections.sort()对集合实现排序,其源码为:
@SuppressWarnings({"unchecked", "rawtypes"})
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
可以看出是内部是利用Arrays.sort()将集合转化的数组实现排序。Arrays.sort使用了两种排序方法,快速排序和优化的归并排序。快速排序主要是对那些基本类型数据(int,short,long等)排序, 而归并排序用于对Object类型进行排序。
排序原则:
- 若你需要排序的是基本数据类型,则选择快速排序。若你需要排序的是引用数据类型,则选择归并排序。(基于稳定性考虑)因为基本数据类型之间无差异,不需要考虑排序算法稳定性,而归并排序则可以实现算法的稳定性。
- 当你需要排序的样本数量小于60,直接选择插入排序,虽然插入排序的时间复杂度为O(N²),我们是忽略常数项得出来的O(N²),但在魔数60以内,插入排序的时间复杂度为O(N²)的劣势体现不出来,反而插入排序常数项很低,导致在小样本情况下,插入排序极快。 如果一开始数组容量很大,但可以分治处理分
治后如果数组容量(L>R - 60)小于60,可以直接选择插排。当大样本下考虑情况1。
插入排序 N^2
private static void insertSort(int[] arr) {
if(arr.length < 2 || arr == null)
return;
for (int i = 1; i < arr.length; i++) { // 0 - (i- 1)已排好序,将新来元素arr[i]插入到已排好序的数组中
for (int j = i - 1; j >= 0; j--) {
if(arr[j] > arr[j + 1]){
swap(arr,j,j+1);
}
}
}
}
快速排序 NlogN
private static void quickSort(int[] arr) {
quickSorting(arr,0,arr.length - 1);
}
private static void quickSorting(int[] arr, int left, int right) {
if(left < right) {
int[] index = partition(arr, left, right);
quickSorting(arr, left, index[0] - 1);
quickSorting(arr, index[1] + 1, right);
}
}
private static int[] partition(int[] arr, int left, int right) {
//随机选取,经典排序
int pivot = arr[(int)Math.random()*(right - left + 1) + left]; // 随机选取基准值 做partition
int i = left;
while(i <= right){
if(arr[i] < pivot){
swap(arr,i++,left++);
}else if(arr[i] > pivot){
swap(arr,i,right--);
}else {
i++;
}
}
return new int[]{left,right};
}
归并排序 NlogN
private static void mergeSort(int[] arr,int L,int R) {
if (L == R)
return;
int mid = L + ((R - L) >> 1);
mergeSort(arr,L,mid);
mergeSort(arr,mid + 1,R);
merge(arr,L,mid,R);
}
private static void merge(int[] arr, int L, int mid, int R) {
int[] ex = new int[R - L + 1];
int i = 0; //ex数组的坐标
int p = L;
int q = mid + 1;
while(p <= mid && q <= R){
ex[i++] = arr[p] < arr[q] ? arr[p++]:arr[q++];
}
while(p <= mid){
ex[i++] = arr[p++];
}
while (q <= R){
ex[i++] = arr[q++];
}
for (int j = 0; j < ex.length; j++) {
arr[L + j] = ex[j];
}
}
选择排序和冒泡排序 N^2
private static void selectSort(int[] arr) {
if(arr == null || arr.length < 2)
return;
for (int i = 0; i < arr.length; i++) {
for (int j = i; j < arr.length; j++) {
if(arr[j] < arr[i]){
swap(arr,i,j);
}
}
}
}
private static void bubbleSort(int[] arr) {
if(arr.length < 2 || arr == null){
return;
}
int temp = 0;
for (int i = arr.length -1 ; i >= 0; i--) {
for (int j = 0; j < i ; j++) {
if(arr[j] > arr[j + 1]){
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
桶排序 O(M + N)
先找出要排序的数的最大最小值。设置桶的容量。依次放入桶中。排序后按顺序出桶。
public class 排序_桶排序 {
public static void main(String[] args){
int[] arr = createArr(10);
bucketSort(arr);
System.out.println(Arrays.toString(arr));
}
private static void bucketSort(int[] arr) {
int min = getArrMin(arr);
int max = getArrMax(arr);
int len = (max -min)/10 + 1;
ArrayList<LinkedList<Integer>> bucket = new ArrayList<>(len);
for(int i = 0; i < len; i++){
bucket.add(new LinkedList<Integer>());
}
enterBucket(arr,bucket,min,len);
for(LinkedList<Integer> ll:bucket){
Collections.sort(ll);
}
outBucket(arr,bucket);
}
private static void outBucket(int[] arr, ArrayList<LinkedList<Integer>> bucket) {
int index = 0;
for(LinkedList<Integer> ll:bucket){
for(Integer i : ll){
arr[index++] = i;
}
}
}
private static void enterBucket(int[] arr, ArrayList<LinkedList<Integer>> bucket,int min,int len) {
for(int i = 0; i < arr.length; i++){
bucket.get((arr[i] - min) / 10).add(arr[i]);
}
}
private static int getArrMax(int[] arr) {
int max = Integer.MIN_VALUE;
for(int i = 0;i < arr.length;i++){
max = Math.max(max,arr[i]);
}
return max;
}
private static int getArrMin(int[] arr) {
int min = Integer.MAX_VALUE;
for(int i = 0;i <arr.length;i++){
min = Math.min(min,arr[i]);
}
return min;
}
private static int[] createArr(int n) {
int[] arr = new int[n];
for(int i = 0;i < n;i++){
arr[i] = (int)(Math.random() * 100); // 0.0-0.99 包括0
}
System.out.println(Arrays.toString(arr));
return arr;
}
}
计数排序 o(n + k)
类似桶排序,稳定
public class 排序_计数排序 {
public static void main(String[] args) {
int[] arr = createArr(10);
bucketSort(arr);
System.out.println(Arrays.toString(arr));
}
private static void bucketSort(int[] arr) {
if(arr == null || arr.length < 2){
return;
}
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int i = 0; i < arr.length; i++) {
max = Math.max(max,arr[i]);
min = Math.min(min,arr[i]);
}
int[] bucket = new int[max - min + 1];
for (int i = 0; i < arr.length; i++) {
bucket[arr[i] - min]++;
}
int i = 0;
for (int j = 0; j < bucket.length; j++) {
while (bucket[j]-- > 0){
arr[i++] = j;
}
}
}
private static int[] createArr(int n) {
int[] arr = new int[n];
for(int i = 0;i < n;i++){
arr[i] = (int)(Math.random() * 100); // 0.0-0.99 包括0
}
System.out.println(Arrays.toString(arr));
return arr;
}
}
堆排序 O(NlogN)
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
思路
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2] 小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
序列的最大值就是堆顶的根节点。 将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
public class 排序_堆排序 {
public static void main(String[] args) {
int[] arr = new int[10];
int[] arr2 = new int[10];
for(int i = 0;i < 10;i++){
arr[i] = (int)(Math.random() * 100); // 0.0-0.99 包括0
}
for(int i = 0;i < 10;i++){
arr2[i] = (int)(Math.random() * 100); // 0.0-0.99 包括0
}
System.out.println(Arrays.toString(arr));
heapSort(arr);
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.toString(arr2));
heapSort2(arr2);
System.out.println(Arrays.toString(arr2));
}
private static void heapSort2(int[] arr) {
if(arr == null || arr.length < 2){
return;
}
int heapSize = arr.length; //设置堆的大小
while (heapSize > 0){
for (int i = 0;i < heapSize;i++){
heapInsert(arr,i); //进入堆
}
swap(arr,0,--heapSize); //调整
}
}
private static void heapSort(int[] arr) {
if(arr == null || arr.length < 2){
return;
}
for (int i = 0; i < arr.length; i++) {
heapInsert(arr,i);
}
int heapSize = arr.length;
swap(arr,0,--heapSize);
while (heapSize > 0){
heapify(arr,0,heapSize);
swap(arr,0,--heapSize);
}
}
private static void heapify(int[] arr, int i, int heapSize) {
int left = i * 2 + 1;
int right = left + 1;
while(left < heapSize){
int largest = right < heapSize && arr[right] > arr[left] ? right : left;
largest = arr[largest] > arr[i] ? largest : i;
if(largest == i){
break;
}
swap(arr,largest,i);
i = largest;
left = i * 2 + 1;
right = left + 1;
}
}
private static void heapInsert(int[] arr, int i) {
while (i > 0 && arr[i] > arr[(i - 1) >> 1]) {
swap(arr, i, (i - 1) >> 1);
i = (i - 1) >> 1;
}
}
private static void swap(int arr[],int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}