排序算法-->选择排序,插入排序,并归排序,快速排序
来源:互联网 发布:乾隆自恋知乎 编辑:程序博客网 时间:2024/06/05 03:19
package com.sort;import java.util.Arrays;import java.util.Random;import com.util.SortTestHelper;/** * 排序算法 * @author 文龙 * @version 2017-12-24 下午12:53:20 */public class Sort {/** * 选择排序: -->每次从未排序的部分选择最小进行插入 * 优点:简单 * 缺点:每一层循环都要全部遍历一次 * 时间复杂度是:n^2 * 原理:每次都 从剩余未排序的数中 选出最小的数 与前面已排序的 后一个 进行交换位置 */public static int[] selectionSort(int[] a) {for(int start = 0;start < a.length;start++) {int min = start;//查找到的最小的数的下标for(int i = start + 1;i < a.length; i++) {if(a[min] > a[i]) {min = i;}}//进行一次的交换int temp = a[start];a[start] = a[min];a[min] = temp;}return a;}/** * 插入排序 --> 每次从排序好的后一个选一个插入 * 优点: 对于近乎有序的数据,非常快,有时候比 nlogn 的算法还要快,时间复杂度甚至达到O(n)。,在很多复杂的算法中使用插入排序进行优化 * 时间复杂度:n^2 * 原理:选取 后一个 与 前面已排序的元素进行比较,插入到合适的位置 * * 与选择排序相比: 插入排序的比较的是可以提前结束的 * */public static int[] insertionSort(int[] a) {if(a.length == 1) return a;intcur = 1;//轮到哪一个元素进行插入了for(;cur < a.length; cur++) {//for里面的i为与哪一个进行对比了for(int i = cur - 1; i < a.length && i >= 0; i--) {if(a[i + 1] < a[i]) {//如果后一个比前一个小 则进行交换位置int temp = a[i + 1];a[i + 1] = a[i];a[i] = temp;} else {//如果出来比前面大的话,就不用与之前的比较了,因为前面的已经排序好了,前面的所有都会比它小break;}}}return a;}/** * 插入排序的优化版 -->上面的每次交换 都叫 两两交换(一个循环会有多次两两交换),下面 每次循环两两交换只进行一次 */public static int[] insertionSort2(int[] a) {/** * 注意: 做这些题要 先确定大体的框架,例如先 确定两个大循环,在逐渐的补充代码 */for(int cur = 1; cur < a.length; cur++) {int temp = a[cur];//把当前的下标的元素取出来int i = cur - 1;//与当前下标的上一个进行对比for(; i >= 0; i--) {if(temp < a[i]) {//如果当前的temp相对小,则将其对比的那个向后移动一个a[i + 1] = a[i];}else {//如果不小于,就是当前的temp大于或者是等于a[i],直接退出即可,因为前面的肯定都大于break;}}//因为上面将a[i]的元素给了a[i+1],则a[]的位置可以放了,但是循环结束了又减了1,在这里要加上1a[i + 1] = temp;}return a;}/** * 归并排序 * 时间复杂度:o(nlogn) * 优点:快 * 原理: 将一个数组不断的分为两部分排序(使用递归将分好的部分在继续分为两部分) *优化: 当分为的部分为一定个数时,可以使用插入排序 */public static int[] mergeSort(int[] arr) {merge_Sort(arr, 0, arr.length - 1);return arr;}//使用递归private static void merge_Sort(int[] arr,int l, int r) {if(l >= r) return;int mid = (l+r)/2;merge_Sort(arr, l, mid);merge_Sort(arr, mid + 1, r);/*//这里进行一次优化 --> 对近乎有序的数组效率很快if(arr[mid] > arr[mid + 1])*/sort(arr, l, mid, r );}//具体排序步骤private static void sort(int[] arr, int l, int mid, int r) {int[] copyArr = Arrays.copyOfRange(arr, l, r + 1);//这里复制的数组并不是和 开始传进来的一样长,而是递归 二分之后的长度int i = l;int j = mid + 1;for(int k = l;k <= r; k++) {if(i > mid) {arr[k] = copyArr[j - l];//所以如果直接使用copyArr[j]可能会越界j++;}else if (j > r) {arr[k] = copyArr[i - l];i++;}else if(copyArr[i - l] < copyArr[j - l]) {arr[k] = copyArr[i - l];i++;} else {arr[k] = copyArr[j - l];j++;}}}/** * 快速排序 -->被称为20世纪最快的算法 *时间复杂度: O(nlogn) *原理: 选择一个temp,将数组分为分小于temp和大于temp两部分。再将这两部分进行递归处理 *两个优化: *1,底层使用插入排序 *2.对于有序的数据,如果都是选择第一个作为标准值的话,那么两边就会极其的不平衡,这时候的优化是:不选择第一个数作为标准值,而是随机选择一个数作为标准值 *3,对于有很多重复的数,比如排序 1百万个 0到10 之间的数。那么这样也会很慢,因为当你选择了一个数,因为其重复出现的次数太多,也会造成两个的不平衡 *同时,如果使用三路快速排序的话 --> 将一组数据分为三个部分 大于 等于 小于 。对于 等于 的在一个排序结束,它们的位置就是已经确定的了 * @param arr * @return */public static int[] quickSort(int[] arr) {quick_Sort(arr, 0, arr.length - 1);return arr;}//这里使用递归private static void quick_Sort(int[] arr,int l,int r) {//递归结束的条件if(l >= r) return;//第一个优化可以在这里使用插入排序//返回的是小于与大于的分界线int p = partition(arr, l, r);quick_Sort(arr, l, p - 1);quick_Sort(arr, p + 1, r);}/** * 快排的具体实现步骤 * @param arr * @param l 起始位置 * @param r 结束位置 */private static int partition(int[] arr,int l, int r) {/*第二个优化,随机选择一个数,使得两遍更加平衡*/swap(arr, new Random().nextInt(r) % (r - l + 1) + l, l);//选择第一个数为标准值int v = arr[l];int j = l;int i = l + 1;for(;i <= r;i++) {if(arr[i] < v) {swap(arr, j + 1, i);j++;}}swap(arr, l, j);return j;}/** * 创建一个近乎有序的数组 * @param arr 要交换的数组 * @param n 交换的次数 * @return */public static int[] nearlyOrderedArray(int[] arr, int n) {for(;n > 0;n--) {Random random = new Random();Random random2 = new Random();int a = random.nextInt(arr.length - 1);int b = random2.nextInt(arr.length - 1);swap(arr, a, b);}return arr;}private static void swap(int[] arr,int a, int b) {int temp = arr[b];arr[b] = arr[a];arr[a] = temp;}public static void main(String[] args) {//创建排序用的数据int[] arr = SortTestHelper.generateRandomArray(10000000, 1, 1000000);int[] arr2 = Arrays.copyOf(arr, arr.length);int[] arr3 = Arrays.copyOf(arr, arr.length);//SortTestHelper.testSort(arr, "selectionSort");SortTestHelper.testSort(arr3, "quickSort");//打乱交换100次nearlyOrderedArray(arr3, 1000);//System.out.println(Arrays.toString(arr));//选择排序//SortTestHelper.testSort(arr, "selectionSort");//插入排序//SortTestHelper.testSort(arr, "insertionSort");//插入排序的优化版//SortTestHelper.testSort(arr2, "insertionSort2");//归并排序//SortTestHelper.testSort(arr, "mergeSort2");//mergeSort(arr);//System.out.println(Arrays.toString(arr));//quickSort(arr);//System.out.println(Arrays.toString(arr));//System.out.println(Arrays.toString(arr3));SortTestHelper.testSort(arr3, "quickSort");System.out.println(arr3.length);}}
阅读全文