排序算法
1.选择排序
1.1.算法思路
(1)选择排序比目泡排序的效率高。高在交换位置的次数上。
(2)选择排序交换位置是有意义的
(3)循环一次,然后找出参加比较的这堆数据中最小的,拿着这个最小的值和最前面的教据“交换位置”。
1.2 复杂度分析
不管原始数组是否有序,时间复杂度都是O(n2),因为没一个数都要与其他数比较一次,(n-1)2次,分解:n2-2n+1, 去掉低次幂和常数,剩下n2,所以最后的时间复杂度是n2
空间复杂度是O(1),因为只定义了两个辅助变量,与n的大小无关,所以空间复杂为O(1);
1.3 动态演示

1.4 Java代码如下
public static void main(String[]args){ int[]a={3,1,6,2,5}; int count=0; int no=0; for (int i=0;i<a.length-1;i++){ //i的值恰好是剩下要比元素的第一个 int min=i; for(int j=i+1;j<a.length;j++){ //j的值和i,构成所以剩下要比的元素 count++; if(a[min]>a[j]){ min=j; } } if (min!=i){ //如果比较出来的最小值下标不是i int temp; //则将最小值min下标与i下标进行交换,保证了每次外循环后最小值在最左边 temp=a[min]; a[min]=a[i]; a[i]=temp; no++; } } for(int i=0;i<a.length;i++) { System.out.print(a[i]+" "); } System.out.println('\n'+"比较次数:"+count+"交换次数:"+no); } }
1.5 大致过程
参与比较的数据:31625(这一堆参加比较的数据中最左边的元素下标是0)
第1次循坏之后的结果是:
1 3 6 2 5
参与比较的数据:3625(这一堆参加比较的数据中最左边的元素下标是1)
第2次循环之后的结果是:
2 6 3 5
参与比较的薮据:6 3 5
第3次循坏之后的结果是:
3 6 5
参与比较的教据:6 5
第4次循坏之后的结果是:
5 6
注意:5条教据,循环4次。
2.直接插入排序
2.1 算法思路
(1)从第二位开始遍历,
(2)当前数(第一趟是第二位数)与前面的数依次比较,如果前面的数大于当前数,则将这个数放在当前数的位置上,当前数的下标-1,
(3)重复以上步骤,直到当前数不大于前面的某一个数为止,这时,将当前数,放到这个位置,
(4))1-3步就是保证当前数的前面的数都是有序的,内层循环的目的就是将当前数插入到前面的有序序列里
(5)重复以上3步,直到遍历到最后一位数,并将最后一位数插入到合适的位置,插入排序结束。
2.2 复杂度
时间复杂度:插入算法,就是保证前面的序列是有序的,只需要把当前数插入前面的某一个位置即可。所以如果数组本来就是有序的,则数组的最好情况下时间复杂度为O(n)
如果数组恰好是倒=倒序,比如原始数组是5 4 3 2 1,想要排成从小到大,则每一趟前面的数都要往后移,一共要执行n-1 + n-2 + … + 2 + 1 = n * (n-1) / 2 = 0.5 * n2 - 0.5 * n次,去掉低次幂及系数,所以最坏情况下时间复杂度为O(n2)
平均时间复杂度(n+n2 )/2,所以平均时间复杂度为O(n2)
空间复杂度:插入排序算法,只需要两个变量暂存当前数,以及下标,与n的大小无关,所以空间复杂度为:O(1)
2.3 动态演示

2.4 Java代码如下
public class StraightInsertionSort { public static void insertSort(int[] a) { int i, j, insertNote;// 要插入的数据 for (i = 1; i < a.length; i++) {// 从数组的第二个元素开始循环将数组中的元素插入 insertNote = a[i];// 设置数组中的第2个元素为第一次循环要插入的数据 j = i - 1; while (j >= 0 && insertNote < a[j]) { a[j + 1] = a[j];// 如果要插入的元素小于第j个元素,就将第j个元素向后移动 j--; } a[j + 1] = insertNote;// 直到要插入的元素不小于第j个元素,将insertNote插入到数组中 } } public static void main(String[] args) { int a[] = { 38,65,97,76,13,27,49 }; insertSort(a); System.out.println(Arrays.toString(a)); } }
3.快速排序
3.1 算法思路
先从数列中取出一个数,作为基准数(简单取第一个数作为基准数)分区过程:将比基准数大的数字全放在其右边、小于等于它的数放在其左边,再对左右区间重复第一步、第二步,直到各个区间只有一个数(递归)
3.2 复杂度分析
(1)时间复杂度:
最坏情况就是每一次取到的元素就是数组中最小/最大的,这种情况其实就是冒泡排序了(每一次都排好一个元素的顺序)
这种情况时间复杂度就好计算了,就是冒泡排序的时间复杂度:T[n] = n * (n-1) = n^2 + n;
最好情况下是O(nlog2n),推导过程如下:
(递归算法的时间复杂度公式:T[n] = aT[n/b] + f(n))
(2)空间复杂度

3.4 Java代码如下
public class QuickSort { public static void main(String[] args) { //给出无序数组 int arr[] = {4,3,8,6,0,9,1,2,5,7}; //输出无序数组 System.out.println(Arrays.toString(arr)); //快速排序 quickSort(arr); //partition(arr,0,arr.length-1); //输出有序数组 System.out.println(Arrays.toString(arr)); } public static void quickSort(int[] arr){ int low = 0; int high = arr.length-1; quickSort(arr,low,high); } private static void quickSort(int[] arr, int low, int high) {//递归何时结束? if(low<high) { //分区操作,将一个数组分成两个分区,返回分区界限的索引 int index = partition(arr, low, high); //对左分区进行快排 quickSort(arr, low, index - 1); //对右分区进行快排 quickSort(arr, index + 1, high); } } private static int partition(int[] arr, int low, int high) { //指定左指针i和右指针j int i = low; int j = high; //将第一个数作为基准值。挖坑 int x = arr[low]; //使用循环实现分区操作 while (i<j){// //1.从右向左移动j,找到第一个小于基准值的值arr[j] while(arr[j]>=x&&i<j){ j--; } //2.将右侧找到的小于基准数的值加入到左边的(坑)位置,左指针向中间移动一个位置i++ if(i<j){ arr[i] = arr[j]; i++; } //3.从左向右移动i,找到第一个大于等于基准值的值arr[i] while(arr[i]<x&&i<j){ i++; } //4.将左侧找到的大于等于基准数的值加入到右边的(坑)位置,右指针向中间移动一个位置j-- if(i<j){ arr[j] = arr[i]; j--; } } //使用基准值填坑,这就是基准值的最终位置 arr[i]=x; //arr[j]=y; //返回基准值位置索引 return i; //return j; } }
4.冒泡排序
4.1 算法思路
(1)每一次循环结束之后,都要找出最大的数据,放到参与比较的这堆数据的最右边。(冒出最大的那个气泡。)
(2)核心 :拿着左边的数字和右边的数字比对,当左边〉右边的时候,交换位置。
4.2 复杂度
(1)不管原始数组是否有序,时间复杂度都是O(n2),因为没一个数都要与其他数比较一次,(n-1)2次,分解:n2+2n-1, 去掉低次幂和常数,剩下n2,所以最后的时间复杂度是n2
(2)空间复杂度是O(1),因为只定义了一个辅助变量,与n的大小无关,所以空间复杂度为O(1)
4.3 动态演示

4.4 Java代码如下
public static void main(String[]args){ int []arr={3,2,7,6,8}; //定义一个数组 int count=0; //定义count变量,用与记录比较次数 for (int i=arr.length-1;i>0;i--){ //外循环:限制内循环比较的范围, for (int j=0;j<i;j++){ //当内循环循环一次时最大值在最右边,无需再做比较,所以范围-1 count++; //内循环:每次循环一次,确保最大值在最右边 if (arr[j]>arr[j+1]){ int k=arr[j]; arr[j]=arr[j+1]; arr[j+1]=k; } } } for (int i = 0; i<arr.length; i++){ //打印已经排列好了的数组 System.out.print(arr[i]+" "); } System.out.println("比较次数:"+count); }
4.5 大致过程
3,2,7,6,8
第次循环:(最大的跑到最右边。)
2,3,7,6,8(3和2比较,2< 3,所以2和3交换位置)
2,3,7,6,8(虽然不需要交换位置:但是3和7还是需要比较一次。)
2, 3,6,7,8(7和6交换位置))
2, 3,6,7,8(虽然不需要交换位置:但是3和7还是需要比较一次。)
经过第次循环,此时剩下参与比较的数据:2,3,6,7
第2次循环:
2, 3,6,7(2和3比较,不需要交换位置)
2,3,6,7(3和比较,不需要交换位匿)
2, 3,6,7(6和7比较,不需要交换位置)
经过第2次循环,此时剩下参与比较的数据:2,3,6
第3次循环:
2,3,6(2和3比较,不需要交换位置)
2,3,6 ( 3和6比较,不需要交换位置)
经过第3次循环,此时剩下参与比较的数据:2,3
第4次循环:
2,3(2和3比较,不需要交换位置)
浙公网安备 33010602011771号