排序的稳定性和复杂度
不稳定:
选择排序(selection sort)— O(n2)
快速排序(quicksort)— O(nlogn) 平均时间, O(n2) 最坏情况; 对于大的、乱序串列一般认为是最快的已知排序
堆排序 (heapsort)— O(nlogn)
希尔排序 (shell sort)— O(nlogn)
基数排序(radix sort)— O(n·k); 需要 O(n) 额外存储空间 (K为特征个数)
稳定:
插入排序(insertion sort)— O(n2)
冒泡排序(bubble sort) — O(n2)
归并排序 (merge sort)— O(n log n); 需要 O(n) 额外存储空间
二叉树排序(Binary tree sort) — O(nlogn); 需要 O(n) 额外存储空间
计数排序 (counting sort) — O(n+k); 需要 O(n+k) 额外存储空间,k为序列中Max-Min+1
桶排序 (bucket sort)— O(n); 需要 O(k) 额外存储空间
-----------------------------每种排序的原理和实现----------------------------
1、冒泡排序
冒泡排序(Bubble Sort)是一种典型的交换排序算法,通过交换数据元素的位置进行排序。
一、算法基本思想
(1)基本思想
冒泡排序的基本思想就是:从无序序列头部开始,进行两两比较,根据大小交换位置,直到最后将最大(小)的数据元素交换到了无序队列的队尾,从而成为有序序列的一部分;下一次继续这个过程,直到所有数据元素都排好序。
算法的核心在于每次通过两两比较交换位置,选出剩余无序序列里最大(小)的数据元素放到队尾。
(2)运行过程
冒泡排序算法的运作如下:
1、比较相邻的元素。如果第一个比第二个大(小),就交换他们两个。
2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大(小)的数。
3、针对所有的元素重复以上的步骤,除了最后已经选出的元素(有序)。
4、持续每次对越来越少的元素(无序元素)重复上面的步骤,直到没有任何一对数字需要比较,则序列最终有序。
(3)示例
二、算法实现(核心代码)
Java实现:
public static void bubble_sort(int[] arr) { int i, j, temp, len = arr.length; for (i = 0; i < len - 1; i++){ for (j = 0; j < len - 1 - i; j++) if (arr[j] > arr[j + 1]) { temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; }
}
}
冒泡排序的性能分析和算法优化(外层循环优化)
问题:
有的冒泡经过第一轮的交换已经是有序的了,如:2 1 3 4。数据越多的时候越慢,非常不适合大数据的排序
解决办法
如果用一个flag来判断一下,当前数组是否已经有序,如果有序就退出循环,这样可以明显的提高冒泡排序的性能。
package bubbleSort;
import java.util.Arrays;
import org.junit.Test;
/**
* 冒泡排序的性能分析和算法优化(外层循环优化)
* @author dell
*
*/
public class BubbeSort02 {
@Test
public void test1(){
boolean flag = true;
int[] arr = {2,1,3,4,5};
int temp;
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-1-i; j++) {
if(arr[j]>arr[j+1]){
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
flag=false;
}
}
if(!flag){
//没有发生交换则退出循环;
break;
}
}
System.out.println(Arrays.toString(arr));
}
}
冒泡排序第二种优化(内层循环优化)
/** * 冒泡排序的性能分析和算法优化(内层循环优化) */ @Test public void test2(){ int[] arr = {22,1,10,5}; //标记最后一次交换的位置 for (int i = 0; i < arr.length-1; i++) { int flag = 0; int temp; for (int j = 0; j < arr.length-i-1; j++) { if(arr[j]>arr[j+1]){ temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; //当位置发生改变,flag的值就发生变化 flag=1; } } //判断标志位flag有没有发生变化,没有就直接结束内层循环 if(flag==0){ return; } } System.out.println(Arrays.toString(arr)); } }
-----------------------------------快速排序--------------------------
一、算法基本思想
选择一个关键值作为基准值。比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的)。一般选择序列的第一个元素。
一次循环:从后往前比较,用基准值和最后一个值比较,如果比基准值小的交换位置,如果没有继续比较下一个,直到找到第一个比基准值小的值才交换。找到这个值之后,又从前往后开始比较,如果有比基准值大的,交换位置,如果没有继续比较下一个,直到找到第一个比基准值大的值才交换。直到从前往后的比较索引>从后往前比较的索引,结束第一次循环,此时,对于基准值来说,左右两边就是有序的了。
接着分别比较左右两边的序列,重复上述的循环。
二、算法实现(核心代码)
Java实现:
public class FastSort{ public static void main(String []args){ System.out.println("Hello World"); int[] a = {12,20,5,16,15,1,30,45,23,9}; int start = 0; int end = a.length-1; sort(a,start,end); for(int i = 0; i<a.length; i++){ System.out.println(a[i]); } } public void sort(int[] a,int low,int high){ int start = low; int end = high; int key = a[low]; while(end>start){ //从后往前比较 while(end>start&&a[end]>=key) //如果没有比关键值小的,比较下一个,直到有比关键值小的交换位置,然后又从前往后比较 end--; if(a[end]<=key){ int temp = a[end]; a[end] = a[start]; a[start] = temp; } //从前往后比较 while(end>start&&a[start]<=key)//如果没有比关键值大的,比较下一个,直到有比关键值大的交换位置 start++; if(a[start]>=key){ int temp = a[start]; a[start] = a[end]; a[end] = temp; } //此时第一次循环比较结束,关键值的位置已经确定了。左边的值都比关键值小,右边的值都比关键值大,但是两边的顺序还有可能是不一样的,进行下面的递归调用 } //递归 if(start>low) sort(a,low,start-1);//左边序列。第一个索引位置到关键值索引-1 if(end<high) sort(a,end+1,high);//右边序列。从关键值索引+1到最后一个 } }
-----------------------------------选择排序---------------------------
a) 原理:每一趟从待排序的记录中选出最小的元素,顺序放在已排好序的序列最后,直到全部记录排序完毕。也就是:每一趟在n-i+1(i=1,2,…n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。基于此思想的算法主要有简单选择排序、树型选择排序和堆排序。(这里只介绍常用的简单选择排序)
b) 简单选择排序的基本思想:给定数组:int[] arr={里面n个数据};第1趟排序,在待排序数据arr[1]~arr[n]中选出最小的数据,将它与arrr[1]交换;第2趟,在待排序数据arr[2]~arr[n]中选出最小的数据,将它与r[2]交换;以此类推,第i趟在待排序数据arr[i]~arr[n]中选出最小的数据,将它与r[i]交换,直到全部排序完成。
c) 举例:数组 int[] arr={5,2,8,4,9,1};
-------------------------------------------------------
第一趟排序: 原始数据:5 2 8 4 9 1
最小数据1,把1放在首位,也就是1和5互换位置,
排序结果:1 2 8 4 9 5
-------------------------------------------------------
第二趟排序:
第1以外的数据{2 8 4 9 5}进行比较,2最小,
排序结果:1 2 8 4 9 5
-------------------------------------------------------
第三趟排序:
除1、2以外的数据{8 4 9 5}进行比较,4最小,8和4交换
排序结果:1 2 4 8 9 5
-------------------------------------------------------
第四趟排序:
除第1、2、4以外的其他数据{8 9 5}进行比较,5最小,8和5交换
排序结果:1 2 4 5 9 8
-------------------------------------------------------
第五趟排序:
除第1、2、4、5以外的其他数据{9 8}进行比较,8最小,8和9交换
排序结果:1 2 4 5 8 9
-------------------------------------------------------
注:每一趟排序获得最小数的方法:for循环进行比较,定义一个第三个变量temp,首先前两个数比较,把较小的数放在temp中,然后用temp再去跟剩下的数据比较,如果出现比temp小的数据,就用它代替temp中原有的数据。具体参照后面的代码示例,相信你在学排序之前已经学过for循环语句了,这样的话,这里理解起来就特别容易了。
代码示例:
//选择排序 public class SelectionSort { public static void main(String[] args) { int[] arr={1,3,2,45,65,33,12}; System.out.println("交换之前:"); for(int num:arr){ System.out.print(num+" "); } //选择排序的优化 for(int i = 0; i < arr.length - 1; i++) {// 做第i趟排序 int k = i; for(int j = k + 1; j < arr.length; j++){// 选最小的记录 if(arr[j] < arr[k]){ k = j; //记下目前找到的最小值所在的位置 } } //在内层循环结束,也就是找到本轮循环的最小的数以后,再进行交换 if(i != k){ //交换a[i]和a[k] int temp = arr[i]; arr[i] = arr[k]; arr[k] = temp; } } System.out.println(); System.out.println("交换后:"); for(int num:arr){ System.out.print(num+" "); } } }
-----------------------------插入排序---------------------------------------
https://blog.csdn.net/qq_28081081/article/details/80594386