排序算法
我们通常所说的排序算法往往指的是内部排序算法,即数据记录在内存中进行排序。排序算法大体可分为两种:一种是比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。另一种是非比较排序,时间复杂度可以达到O(n),主要有:计数排序,基数排序,桶排序等。
算法复杂度
冒泡排序
一组无序的数据arr[0]、arr[1]、……arr[n],按升序排列,首先比较a[0]与a[1]的值,若a[0]大于a[1]则交换两者的值,否则不变。再比较a[1]与a[2]的值,若a[1]大于a[2]则交换两者的值,否则不变。再比较a[2]与a[3],以此类推,最后比较a[n-1]与a[n]的值。这样处理一轮后,a[n]的值一定是这组数据中最大的。用相同的方法对a[0]~a[n-1]以相同处理一轮,则a[n-1]的值一定是a[0]~a[n-1]中最大的。以此循环,最后比较a[0]和a[1]位置的两个值,若a[0]大于a[1]则交换位置,否则不变。理论上总共要进行n(n-1)/2次交换。代码实现如下:
public static void bubbleSort(int[] arr) { for (int i = 1; i < arr.length; i++) { for (int j = 0; j < arr.length - i; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } }
选择排序
选择排序的工作原理:初始时在序列中找到最小(大)元素,放到序列的起始位置作为已排序序列;然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。代码实现如下:
public static void selectSort(int[] arr) { for(int i = 0; i < arr.length; i++) { int k = i; for(int j = arr.length-1; j > i; j --) { if(arr[j] < arr[k]) { k = j; } } int temp = arr[i]; arr[i] = arr[k]; arr[k] = temp; } System.out.println(Arrays.toString(arr)); }
插入排序
插入排序的工作原理:每步将一个待排序的记录,按其顺序码大小插入到前面已经排序的字序列的合适位置(从后向前找到合适位置后),直到全部插入排序完为止。
public static void inserSort (int[] arr) { int j = 0; for(int i = 0; i < arr.length; i ++) { int temp = arr[i]; for( j = i; j> 0 && temp < arr[j-1];j--) { arr[j] = arr[j-1]; } arr[j] = temp; } }
归并排序
归并排序的工作原理:通过将数组不断地二分,直到最后每个部分只包含 1 个数据。然后再对每个部分分别进行排序,最后将排序好的相邻的两部分合并在一起,这样整个数组就有序了。
public static void customMergeSort(int[] a, int[] tmp, int start,int end){ if(start < end) { int mid = (start+end)/2; customMergeSort(a,tmp,start,mid); customMergeSort(a,tmp,mid+1,end); customDoubleMerge(a,tmp,start,mid,end); } } public static void customDoubleMerge(int[] a, int[] tmp, int left,int mid,int right){ int p1 = left, p2= mid+1, k = left; while(p1 <= mid && p2 <= right) { if (a[p1] <= a[p2]) { tmp[k++] = a[p1++]; } else { tmp[k++] = a[p2++]; } } while(p1 <= mid){ tmp[k++] = a[p1++]; } while(p2 <= right){ tmp[k++] = a[p2++]; } for(int i = left; i <= right; i++) { a[i] = tmp[i]; } }
快速排序
快速排序的工作原理:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序。
public static int partition(int[] a, int low, int high) { int pivotkey = a[low]; //数组的第一个作为中轴 while (low < high) { while (low < high && a[high] >= pivotkey) --high; a[low] = a[high]; //比中轴小的记录移到低端 while (low < high && a[low] <= pivotkey) ++low; a[high] = a[low]; //比中轴大的记录移到高端 } a[low] = pivotkey; //中轴记录到尾 return low; // 返回中轴的位置 } /** * @param arr 带排序数组 * @param low 开始位置 * @param high 结束位置 */ public static void quickSort(int[] arr, int low, int high) { if (low < high) { int middle = partition(arr, low, high); //将arr数组进行一分为二 quickSort(arr, low, middle - 1); //对低字段表进行递归排序 quickSort(arr, middle + 1, high); //对高字段表进行递归排序 } }