数据结构与算法【Java版】:第三课

排序算法的介绍:

分类:

  • 内部排序(使用内存):插入排序(直接插入排序、希尔排序)、选择排序(简单选择排序、堆排序)、交换排序(冒泡排序、快速排序)、归并排序、基数排序。
  • 外部排序(使用内存和外存结合): 

算法的时间复杂度:

时间频度:一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。

  • T(n):算法中的基本操作语句的重复执行次数是问题规模n的某个函数,
  • 辅助函数f(n):当n趋近于无穷大时,T(n) / f(n) 的极限值为不等于零的常数,称f(n)是T(n)的同数量级函数,
  • 记作 T(n)=O( f(n) ),称O( f(n) )  为算法的渐进时间复杂度,简称时间复杂度

计算时间复杂度的方法:

  • 用常数1代替运行时间中的所有加法常数  T(n)=n²+7n+6  => T(n)=n²+7n+1
  • 修改后的运行次数函数中,只保留最高阶项  T(n)=n²+7n+1 => T(n) = n²
  • 去除最高阶项的系数 T(n) = n² => T(n) = n² => O(n²)

常见的时间复杂度:

常数阶O(1)、对数阶O(log2n)、线性阶O(n)、线性对数阶O(nlog2n)、平方阶O(n^2)、立方阶O(n^3)、k次方阶O(n^k)、指数阶O(2^n)。规模增大,效率越低。

平均时间复杂度和最坏时间复杂度:

算法的空间复杂度(Space Complexity):该算法所耗费的存储空间,它也是问题规模n的函数。

冒泡排序 

代码实现:

package com.jiao.algorithm.sort;

import java.util.Arrays;

public class BubbleSort {
    public static void main(String[] args) {
        //时间复杂度:O(n^2)  n=7个数 n-1=6比较次数 n-1-i=6,5,4,3,2,1每轮比次数
        int[] arr = {10,8,6,5,3,-1,-2};  //定义数组放要排序的数字
        System.out.println("原数字为:"+Arrays.toString(arr));
        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;
                }
            }
            System.out.printf("第 %d 轮比较后的数组为:%s \n",i+1, Arrays.toString(arr));
        }
    }
}

测试结果:

优化冒泡排序:如果某一次排序位置都不变,直接break退出。(flag标识符)

package com.jiao.algorithm.sort;

import java.util.Arrays;

public class BubbleSort {
    public static void main(String[] args) {
        //时间复杂度:O(n^2)  n=7个数 n-1=6比较次数 n-1-i=6,5,4,3,2,1每轮比次数
        int[] arr = {10,12,6,7,3,-1,-2};  //定义数组放要排序的数字
        System.out.println("原数字为:"+Arrays.toString(arr));
        bubbleSort(arr);
        System.out.printf("排序后的数组为:%s \n", Arrays.toString(arr));
    }

    //封装
    public static void bubbleSort(int[] arr) {
        int temp;   //用于比较的临时变量
        boolean flag = false;   //优化算法 标识符
        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]) {    //从小到大排序
                    flag = true;    //该次有交换
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
            //System.out.printf("第 %d 轮比较后的数组为:%s \n",i+1, Arrays.toString(arr));
            if (!flag) {
                break;  //   该次没有交换,说明剩下的已经排好序,直接退出
            } else {
                flag = false;   //  复位
            }
        }
    }

}

 测试8000个随机数排序所耗时间:

package com.jiao.algorithm.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

public class BubbleSort {
    public static void main(String[] args) {

        //生成80000个随机数
        int[] array = new int[80000];
        for (int i = 0; i < 80000; i++) {
            array[i] = (int)(Math.random() * 80000);    // [0,1)*80000
        }

        Date date1 = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr1 = sdf.format(date1);
        System.out.println("排序前时间:"+dateStr1);

        bubbleSort(array);

        Date date2 = new Date();
        String dateStr2 = sdf.format(date2);
        System.out.println("排序后时间:"+dateStr2);

    }

    //封装
    public static void bubbleSort(int[] arr) {
    ...
    }

}

测试时间:

选择排序 

 代码实现:

package com.jiao.algorithm.sort;

import java.util.Arrays;

public class SelectSort {
    public static void main(String[] args) {
        int[] arr = {101,34,119,5,62,36,84,2};
        System.out.println("选择排序前为:"+Arrays.toString(arr));
        selectSort(arr);
        System.out.println("选择排序后为:"+Arrays.toString(arr));

    }

    //方法
    public static void selectSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {  //轮数
            int minIndex = i;   //最小数的下标
            int min = arr[i];   //最小的数    //每轮过后前一个为最小,后移一位
            for (int j = i+1; j < arr.length; j++) {  //每轮次数
                if (min > arr[j]) {
                    min = arr[j];
                    minIndex = j;//找到最小数的值和下标
                }
            }
            if (i != minIndex) {    //最小值下标和当前的arr[i]下标一样,说明arr[i]为最小,不需要交换
                arr[minIndex] = arr[i];
                arr[i] = min;
            }
            System.out.printf("第%d轮排序后:%s \n",i+1,Arrays.toString(arr));
        }
    }

}

 测试结果:

 测试8000个随机数排序所耗时间:

插入排序 

 代码:

package com.jiao.algorithm.sort;

import java.util.Arrays;

public class InsertSort {
    public static void main(String[] args) {
        int[] arr = {89,76,44,32,12,4};
        System.out.println("插入排序前的数据:"+Arrays.toString(arr));
        insertSort(arr);
        System.out.println("插入排序后的数据:"+Arrays.toString(arr));
    }

    //封装
    public static void insertSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {  //轮数
            int insertVal = arr[i+1];   //待插入的数
            int insertIndex = i;    //待插入数的前一个坐标
            while (insertIndex >= 0 && insertVal < arr[insertIndex]) {    //假如还有要比较的数 或者 待插入的数与前者相比较小
                arr[insertIndex + 1] = arr[insertIndex];    //待比较的数后移
                insertIndex--;
            }
            arr[insertIndex+1] = insertVal; //最后比较完了, 最小的数下标就是i, 把待插入的数放进去就可以了
            System.out.printf("第%d轮的数据为:%s \n",i+1, Arrays.toString(arr));
        }
    }

}

 测试结果:

测试8000个随机数排序所耗时间:

 优化(但是时间差不多):

...
if (insertIndex+1 != i) {   //优化,假如插入的数已经在此轮比前一个比较大,不需要后移
    arr[insertIndex+1] = insertVal; //最后比较完了, 最小的数下标就是i, 把待插入的数放进去就可以了
}
...

希尔排序 (一种插入排序:缩小增量排序)

交换法-代码:【难以理解】

package com.jiao.algorithm.sort;

import java.util.Arrays;

public class ShellSort {
    public static void main(String[] args) {
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        System.out.println("原始数据是:"+Arrays.toString(arr));
        shellSortByChange(arr);
    }

    //封装 插入用交换法
    public static void shellSortByChange(int[] arr) {
        int temp = 0;
        int num = 1; //轮数统计
        for (int gap = arr.length/2; gap > 0 ; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                //遍历各组的元素(gap组,每组len/gap个元素),步长gap
                for (int j = i-gap; j>=0 ; j -= gap) {
                    if (arr[j] > arr[j+gap]) {
                        temp = arr[j];
                        arr[j] = arr[j+gap];
                        arr[j+gap] = temp;
                    }
                }
            }
            System.out.printf("第%d轮后的排序为:%s\n",num,Arrays.toString(arr));
            num++;
        }
    }

    //交换法 分步骤分析
    public static void shellSortByChangeTest(int[] arr) {
        int temp = 0;
        //第一轮,10个数分5组
        for (int i = 5; i < arr.length; i++) {
            //遍历各组的元素(5组,每组2个元素),步长5
            for (int j = i-5; j>=0 ; j -= 5) {
                if (arr[j] > arr[j+5]) {
                    temp = arr[j];
                    arr[j] = arr[j+5];
                    arr[j+5] = temp;
                }
            }
        }
        System.out.println("第一轮后的排序为:"+ Arrays.toString(arr));

        //第二轮,10个数分2组
        for (int i = 2; i < arr.length; i++) {
            //遍历各组的元素(2组,每组5个元素),步长2
            for (int j = i-2; j>=0 ; j -= 2) {
                if (arr[j] > arr[j+2]) {
                    temp = arr[j];
                    arr[j] = arr[j+2];
                    arr[j+2] = temp;
                }
            }
        }
        System.out.println("第二轮后的排序为:"+ Arrays.toString(arr));

        //第三轮,10个数分1组
        for (int i = 1; i < arr.length; i++) {
            //遍历各组的元素(5组,每组2个元素),步长5
            for (int j = i-1; j>=0 ; j -= 1) {
                if (arr[j] > arr[j+1]) {
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        System.out.println("第三轮后的排序为:"+ Arrays.toString(arr));
    }

}

测试结果:

 80000数据进行测试时间:

移位法-代码:【重要】

package com.jiao.algorithm.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

public class ShellSort {
    public static void main(String[] args) {
        /*int[] arr = {8,9,1,7,2,3,5,4,6,0};
        System.out.println("原始数据是:"+Arrays.toString(arr));
        shellSortByChange(arr);*/

        //生成80000个随机数
        int[] array = new int[80000];
        for (int i = 0; i < 80000; i++) {
            array[i] = (int)(Math.random() * 80000);    // [0,1)*80000
        }

        Date date1 = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr1 = sdf.format(date1);
        System.out.println("排序前时间:"+dateStr1);

        shellSortByMove(array);

        Date date2 = new Date();
        String dateStr2 = sdf.format(date2);
        System.out.println("排序后时间:"+dateStr2);
    }

    //希尔排序 插入用移位发
    public static void shellSortByMove(int[] arr) {
        //增量gap,并逐步缩小增量
        for (int gap = arr.length/2; gap > 0 ; gap /=2) {
            //从gap个元素,逐个对其所在的组进行直接插入排序
            for (int i = gap; i < arr.length ; i++) {
                int j = i;
                int temp = arr[j]; //临时变量
                if (arr[j] < arr[j - gap]) {
                    while (j-gap >=0 && temp < arr[j-gap]) {    //移动
                        arr[j] = arr[j-gap];
                        j -= gap;
                    }
                    //当退出while循环,就把temp给找到的位置
                    arr[j] = temp;
                }
                //System.out.println(Arrays.toString(arr));
            }
        }
    }

    //封装 插入用交换法
    public static void shellSortByChange(int[] arr) {
        ...
    }

    //交换法 分步骤分析
    public static void shellSortByChangeTest(int[] arr) {
        ...
    }

}

80000数据测试:

快速排序 

 代码:【难】

package com.jiao.algorithm.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

public class QuickSort {
    public static void main(String[] args) {
        /*int[] arr = {-9,70,0,-567,78,23};
        quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));*/

        //生成80000个随机数
        int[] array = new int[8000000];
        for (int i = 0; i < 8000000; i++) {
            array[i] = (int)(Math.random() * 8000000);    // [0,1)*80000
        }

        Date date1 = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr1 = sdf.format(date1);
        System.out.println("排序前时间:"+dateStr1);

        quickSort(array,0,array.length-1);

        Date date2 = new Date();
        String dateStr2 = sdf.format(date2);
        System.out.println("排序后时间:"+dateStr2);
    }

    public static void  quickSort(int[] arr, int left, int right) {
        int l = left; //左下标
        int r = right; //右下标
        int pivot = arr[(left+right)/2]; //中轴值
        int temp = 0; //临时变量,用于交换使用
        //让比pivot小的放左边,比pivot大的放右边
        while (l < r) {
            while (arr[l] < pivot) {    //在pivot左边找比它大的退出
                l++;
            }
            while (arr[r] > pivot) {    //在pivot右边找比它小的退出
                r--;
            }
            if (l >= r) {   //找到最后,左右两边都满足pivot左小右大
                break;
            }
            //交换
            temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;

            //防止死循环
            if (arr[l] == pivot) {  //前移
                r--;
            }
            if (arr[r] == pivot) {  //后移
                l++;
            }
        }

        //递归
        if (l == r) {   //l++,l--,防止栈溢出
            l++;
            r--;
        }
        //向左递归
        if (left < r) {
            quickSort(arr,left,r);
        }
        //向右递归
        if (right > l) {
            quickSort(arr,l,right);
        }

    }

}

测试800万数据时间:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值