排序算法

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)空间复杂度

 

   快速排序使用的空间是O(1)的,也就是个常数级;而真正消耗空间的就是递归调用了,因为每次递归就要保持一些数据:
   最优的情况下空间复杂度为:O(log2n);每一次都平分数组的情况
   最差的情况下空间复杂度为:O( n );退化为冒泡排序的情况
   所以平均空间复杂度为O(log2n)
3.3 动态演示
 

 

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比较,不需要交换位置)

 

 


   

     



 

posted @ 2021-03-10 11:25  啦隆哆  阅读(69)  评论(0)    收藏  举报