八种常用排序算法总结
2018-04-04 14:20
447 查看
八种常用排序算法分类
时间复杂度、空间复杂度及稳定性分析
不同应用场景下的排序算法选择
1、数据规模较小
待排序列基本序的情况下,可以选择直接插入排序;对稳定性不作要求宜用简单选择排序,对稳定性有要求宜用插入或冒泡
2、数据规模不是很大
完全可以用内存空间,序列杂乱无序,对稳定性没有要求,快速排序,此时要付出log(N)的额外空间;序列本身可能有序,对稳定性有要求,空间允许下,宜用归并排序
3、数据规模很大
对稳定性有求,则可考虑归并排序;对稳定性没要求,宜用堆排序
4、序列初始基本有序(正序),宜用直接插入,冒泡
算法的Java实现
import java.util.ArrayList; /** * 八大排序算法 */ public class SortAlgorithms { //选择排序 public static void selectionSort(int[] arr, int len){ for (int i = 0; i < len; i++) { int minIndex = i;//寻找[i, len)区间里的最小值下标 for (int j = i+1; j < len; j++) { if (arr[j] < arr[minIndex]){ minIndex = j; } } //将i位置的元素和最小值交换 int temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } } //插入排序:可以提前终止内层循环 public static void insertionSort(int[] arr, int len){ //第一个元素不需要进行插入操作 for (int i = 1; i < len; i++) { //寻找arr[i]合适的插入位置 int insertNum = arr[i]; int j; for (j = i; j > 0 && arr[j-1] > insertNum; j--) { //如果当前元素比前一个元素小,则交换 arr[j] = arr[j-1]; } arr[j] = insertNum; } } //冒泡排序 public static void bubbleSort(int[] arr, int len){ boolean swapped; do { swapped = false; for (int i = 1; i < len; i++) { if (arr[i-1] > arr[i]){ 4000 //交换 int temp = arr[i]; arr[i] = arr[i-1]; arr[i-1] = temp; swapped = true; } } }while (swapped); len--; } //希尔排序 public static void shellSort(int[] arr, int len){ int h = len/2; while (h>0){ //h-sort the array for (int i = h; i < len; i++) { int insertNum = arr[i]; int j; for (j = i; j >=h && insertNum < arr[j-h]; j-=h) { arr[j] = arr[j-h]; } arr[j] = insertNum; } h /= 2; } } //基于递归的归并排序 public static void mergeSort(int[] arr, int low, int high){ int mid = low + (high - low)/2; if (mid < high){ mergeSort(arr, low, mid);//左边 mergeSort(arr,mid+1, high);//右边 //左右合并 merge(arr, low, mid, high); //if (arr[mid] > arr[mid+1]){//这一步是一个优化操作,左右都是排好序的,只有当左边的最后一个元素比右边第一个大时才归并 // merge(arr, low, mid, high); //} } } //归并函数 public static void merge(int[] arr, int low, int mid, int high){ int mergeLen = high-low+1; int[] temp = new int[mergeLen]; int left = low; int right = mid+1; int i = 0; //把较小的数据放到新数组 while (left<=mid && right<=high){ if (arr[left]<arr[right]){ temp[i++] = arr[left++]; }else { temp[i++] = arr[right++]; } } //把左数组中剩余的元素复制到排序数组 while (left<=mid){ temp[i++] = arr[left++]; } //把右数组中剩余的元素复制到排序数组 while (right<=high){ temp[i++] = arr[right++]; } //用新数组覆盖原数组 for (int j = 0; j < mergeLen; j++) { arr[j + low] = temp[j]; } } //基于迭代的归并排序 public static void mergeSortBU(int[] arr, int len){ for (int sz = 1; sz <= len; sz += sz) { //对arr[i...i+sz-1]和arr[i+sz...i+2*sz-1]进行归并 for (int i = 0; i+sz < len; i += sz+sz) { merge(arr,i,i+sz-1, Math.min(i+sz+sz-1, len-1)); } } } //快速排序 public static void quickSort(int[] arr, int low, int high){ if (low < high){ int left = low; int right = high; //通过随机选取数组中的元素作为基准元素,下面这一块是快排优化的一种方法 //int random = low + (int)(Math.random()*(high-low+1)); //int tmp = arr[low]; //arr[low] = arr[random]; //arr[random] = tmp; int temp = arr[low]; while (left != right){ while (left<right && arr[right]>temp){ right--; } if (left<right){ arr[left] = arr[right]; left++; } while (left<right && arr[left]<temp){ left++; } if (left<right){ arr[right] = arr[left]; right--; } } arr[left] = temp; quickSort(arr, low,left-1); quickSort(arr,left+1, high); } } //堆排序 //使用数组存储二叉堆,根节点的索引号为0,从上往下,从左往右索引号递增1 //parent(i) = (i-1)/2 //left child(i) = i*2+1 //right child(i) = i*2+2 public static void heapSort(int[] arr, int len){ //循环建立最大堆,每次将最大堆的最大元素和数组的最后一个元素交换,再对无序的元素重新建堆 for (int i = len-1; i >0; i--) {//只剩最后一个元素时就完成排序了 buildMaxHeap(arr,i); int temp = arr[0]; arr[0] = arr[i]; arr[i] = temp; } } //建立最大堆 public static void buildMaxHeap(int[] arr, int last){ //从最后一个非叶子开始遍历,将不满足大顶堆的元素和它的左右孩子的最大值交换 for (int i = (last-1)/2; i >= 0; i--) { int k = i;//记录当前正在判断的节点 //判断是否有左孩子,有左孩子的情况下再判断是否有右孩子,然后再判断是否需要交换 while (2*k+1 <= last){ int bigIndex = 2*k+1;//左孩子的索引 if (bigIndex < last){//说明存在右孩子 if (arr[bigIndex] < arr[bigIndex+1]){//比较左右孩子的大小 bigIndex++; } } if (arr[k] < arr[bigIndex]){//父节点比其左右孩子的最大值小 int temp = arr[k]; arr[k] = arr[bigIndex]; arr[bigIndex] = temp; k = bigIndex; }else { break; } } } } //基数排序 public static void radixSort(int[] arr, int len) { //先算出最大数的位数; int max = arr[0]; for (int i = 1; i < len; i++) { max = Math.max(max, arr[i]); } int maxDigit = 0; while (max != 0) { max /= 10; maxDigit++; } int mod = 10, div = 1; ArrayList<ArrayList<Integer>> bucketList = new ArrayList<>(); for (int i = 0; i < 10; i++) bucketList.add(new ArrayList<>()); for (int i = 0; i < maxDigit; i++, mod *= 10, div *= 10) { for (int j = 0; j < len; j++) { int num = (arr[j] % mod) / div; bucketList.get(num).add(arr[j]); } int index = 0; for (int j = 0; j < bucketList.size(); j++) { for (int k = 0; k < bucketList.get(j).size(); k++) arr[index++] = bucketList.get(j).get(k); bucketList.get(j).clear(); } } } //生成有n个元素的随机数组,每一个元素的随机范围为[rangeL, rangeR] public static int[] generateRandomArray(int n, int rangeL, int rangeR){ int[] arr = new int ; for (int i = 0; i < n; i++) { arr[i] = rangeL +(int)(Math.random()*(rangeR-rangeL+1)); } return arr; } //拷贝数组 public static int[] copyIntArray(int[] arr, int len){ int[] newArr = new int[len]; for (int i = 0; i < len; i++) { newArr[i] = arr[i]; } return newArr; } public static void main(String[] args) { int n = 10000; int[] arr1 = generateRandomArray(n,0, n); int[] arr2 = copyIntArray(arr1, n); int[] arr3 = copyIntArray(arr1, n); int[] arr4 = copyIntArray(arr1, n); int[] arr5 = copyIntArray(arr1, n); int[] arr6 = copyIntArray(arr1, n); int[] arr7 = copyIntArray(arr1, n); int[] arr8 = copyIntArray(arr1, n); int[] arr9 = copyIntArray(arr1, n); System.out.println("-----------排序前-------------"); for (int i = 0; i < n; i++) { System.out.print(arr7[i]+" "); } System.out.println("\n\n*******排序时间********"); long startTime1 = System.currentTimeMillis(); selectionSort(arr1, n); long endTime1 = System.currentTimeMillis(); System.out.println("选择排序:\t" + (endTime1-startTime1)/1000.0 + "s"); long startTime2 = System.currentTimeMillis(); insertionSort(arr2, n); long endTime2 = System.currentTimeMillis(); System.out.println("插入排序:\t" + (endTime2-startTime2)/1000.0 + "s"); long startTime3 = System.currentTimeMillis(); bubbleSort(arr3, n); long endTime3 = System.currentTimeMillis(); System.out.println("冒泡排序:\t" + (endTime3-startTime3)/1000.0 + "s"); long startTime4 = System.currentTimeMillis(); shellSort(arr4, n); long endTime4 = System.currentTimeMillis(); System.out.println("希尔排序:\t" + (endTime4-startTime4)/1000.0 + "s"); long startTime5 = System.currentTimeMillis(); mergeSort(arr5,0,n-1); long endTime5 = System.currentTimeMillis(); System.out.println("自顶向下归并排序:\t" + (endTime5-startTime5)/1000.0 + "s"); long startTime6 = System.currentTimeMillis(); mergeSortBU(arr6, n); long endTime6 = System.currentTimeMillis(); System.out.println("自底向上归并排序:\t" + (endTime6-startTime6)/1000.0 + "s"); long startTime7 = System.currentTimeMillis(); quickSort(arr7,0,n-1); long endTime7 = System.currentTimeMillis(); System.out.println("快速排序:\t" + (endTime7-startTime7)/1000.0 + "s"); long startTime8 = System.currentTimeMillis(); heapSort(arr8, n); long endTime8 = System.currentTimeMillis(); System.out.println("堆排序:\t" + (endTime8-startTime8)/1000.0 + "s"); long startTime9 = System.currentTimeMillis(); radixSort(arr9, n); long endTime9 = System.currentTimeMillis(); System.out.println("基数排序:\t" + (endTime9-startTime9)/1000.0 + "s"); System.out.println("\n-----------排序后-------------"); for (int i = 0; i < n; i++) { System.out.print(arr8[i]+" "); } } }
运行效果:
相关文章推荐
- Java基础学习总结(60)——Java常用的八种排序算法
- 八种常用排序算法总结
- Java基础学习总结(60)——Java常用的八种排序算法
- 常用数据结构之排序算法总结
- Java常用的八种排序算法与代码实现
- Java常用的八种排序算法与代码实现
- 常用排序算法总结4一一归并排序
- 常用排序算法总结(上)
- 常用的八种排序算法与Java代码实现
- 常用排序算法总结8一一基数排序
- 一遍记住Java常用的八种排序算法与代码实现
- 常用排序算法总结
- Java常用的八种排序算法与代码实现
- Java常用的八种排序算法与代码实现
- 常用排序算法总结(python)
- 八种常用的排序算法 (转载)
- 总结几种常用的排序算法(含代码)
- 总结5种比较高效常用的排序算法
- 几种常用排序算法总结
- 八种排序算法总结