数据结构算法爬坑日记七

算法复杂度

时间频度:一个算法花费的时间与算法中语句的执行次数成正比,一个算法中执行语句次数为语句频度/时间频度,
记为T(n)
时间复杂度:T(n)/f(n),当n趋向无穷大时,比值为一个不等于0的常数,则称f(n)T(n)的同量级函数,记作
T(n)=O(f(n)),O(f(n))为算法的时间复杂度
 ** 计算方法
  ** 忽略常数项
  ** 只保留最高次数项
  ** 忽略最高次数项的系数
常见的时间复杂度
 ** 常数阶 O(1) 通常为代码的执行语句不随某个变量的变化而变化
 ** 对数阶 O(log2(n)) 循环语句i的增加以某个倍数增加
 ** 线性阶 O(n) 一层循环
 ** 线性对数阶 O(nlog2(n)) 两层循环,一层的i为倍数增加,另一层自然增长 
 ** 平方阶 O(n^2) 两层循环
 ** 立方阶 O(n^3) 三层循环
 ** k次方阶 O(n^k) k层循环
 ** 指数阶 O(2^n)
从上到下时间复杂度大小依次增长
空间复杂度:一个算法占用的内存与n成正比,缓存技术就是利用空间换时间

排序算法

常见排序算法分类
内部排序(将需要处理的数据加载到内存中进行排序)
  ** 插入排序
    ** 直接插入排序
    ** 希尔排序
  ** 选择排序
    ** 简单选择排序
    ** 堆排序
  ** 交换排序
    ** 冒泡排序
    ** 快速排序
  ** 归并排序
  ** 基数排序
外部排序(数据量大,无法全部加载到内存,借助外部存储进行排序)

冒泡排序

基本思想:对待排序序列进行从前往后依次比较相邻元素的值,如果发现二者与规定的规则不符合则交换,这样符合
我们预定规则的元素会逐渐向后移动

代码实现
//冒泡排序
public class BubblingSort {
    public static void main(String[] args) {
        int[] arr = {10, 8, 4, 5, 1};
        int temp; // 中间数
        boolean flag=false;//一轮下来是否进行交换过的标志
        System.out.println("排序前"+ Arrays.toString(arr));
        // 控制进行的轮数
        for (int i = 0; i < arr.length - 1; i++) {
            //控制每轮两数比较的次数
            for (int j = 0; j < arr.length - 1 - i; j++) {
                //如果不符合排序规则,两数交换并且标识置为true
                if(arr[j]>arr[j+1]){
                    flag=true;
                    temp=arr[j+1];
                    arr[j+1]=arr[j];
                    arr[j]=temp;
                }
            }
            System.out.println("第"+(i+1)+"轮交换后排序后"+ Arrays.toString(arr));
            //如果进行交换过,将标志重新置为false,如果没有交换过,则已经排序成功
            if(flag){
                flag=false;
            }else {
                break;
            }
        }
    }
}
时间复杂度为O(n^2) 80000个元素的数组测试平均为13s

选择排序

选择排序属于内部排序法,从欲排序的数据中,按指定的规则选出某一元素,再按照规定交换位置
基本思想:从整个排序的数据中选出最小值与第一个元素进行交换,然后再去掉第一个元素从剩下的元素选出
最小值与第一个元素进行交换,以此类推直到此数据循环结束

代码示例
//选择排序
public class SelectSort {
    public static void main(String[] args) {
        int[] arr = {10, 8, 4, 5, 1};
        System.out.println("排序前 " + Arrays.toString(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]) {
                    minIndex = j;
                    min = arr[j];
                }
            }
            //如果最小值下标改变就将最小值与指定位置进行交换
            if (minIndex != i) {
                arr[minIndex] = arr[i];
                arr[i] = min;
            }
            System.out.println("第" + (i + 1) + "次排序后 " + Arrays.toString(arr));
        }
    }
}
时间复杂度为O(n^2) 80000个元素的数组测试平均为4s

插入排序

插入排序也属于内部排序法,是对欲排序元素以插入的方式找到该元素的适当位置
基本思想:将一个n个元素的待排序数据看做一个有序表一个无序表,有序表有一个元素,无序表n-1个元素,排序过
程中每次从无序表取出一个元素,将他与有序表内元素进行比较以找到需要插入的位置

代码实现
//插入排序
public class InsertSort {
    public static void main(String[] args) {
        int[] arr = {10, 8, 4, 5, 1};
        for (int i = 1; i < arr.length; i++) {
            int insertIndex = i - 1;//待插入数据前一位下标
            int insertValue = arr[i];//待插入的值
            //如果待插入数据的值小于前一位的值将前一位后移然后与前一位的上一位比较
            while (insertIndex >= 0 && insertValue < arr[insertIndex]) {
                arr[insertIndex + 1] = arr[insertIndex];
                insertIndex--;
            }
            //退出循环时,待插入的值不小于前一位的值或前面已经没数据了
            //此时插入的位置就是前一位的索引+1,如果前一位下标没变,无需插入
            if (insertIndex + 1 != i) {
                arr[insertIndex + 1] = insertValue;
            }
            System.out.println("第" + i + "轮插入后 " + Arrays.toString(arr));
        }
    }
}
时间复杂度为O(n^2) 80000个元素的数组测试平均为1s

希尔排序

以从小到大为例,在插入排序中,如果最小的数在后面,则在移动时,出现的问题就是移动的次数过多
希尔排序就是为了解决此问题的一种改进版插入排序
思想:
把需要排序的数据根据下标进行一定增量分组,对每组使用直接插入排序,增量逐渐减少,直到增量减至为1,
算法终止

交换法代码实现
//希尔排序,交换法
public class ShellSort {
    public static void main(String[] args) {
        int[] arr = {8, 9, 5, 6, 0, 1, 3, 2, 4, 7};
        int temp;//交换中间数
        //希尔排序增量的变化,以二倍缩小直到为1
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            //增量每次缩小时,进行对数据移动
            for (int i = gap; i < arr.length; i++) {
                //每轮循环的比较
                for (int j = i - gap; j >= 0; j -= gap) {
                    //如果大于下一个位置的数就交换
                    if (arr[j] > arr[j + gap]) {
                        temp = arr[j + gap];
                        arr[j + gap] = arr[j];
                        arr[j] = temp;
                    }
                }
            }
            System.out.println(Arrays.toString(arr));
        }
    }
}
80000个元素的数组测试平均为9s,反而变慢了

移位法
//希尔排序 移位法
public class ShellInsertSort {
    public static void main(String[] args) {
        int[] arr = {8, 9, 5, 6, 0, 1, 3, 2, 4, 7};
        //增量依次变小
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            //从增量大小开始,向后循环到数组末尾
            for (int i = gap; i < arr.length; i++) {
                int index = i;//待插入数据索引
                int value = arr[index]; //待插入数据的值
                //如果待插入数据的值小于前一位的值将前一位后移
                while (index - gap >= 0 && arr[index - gap] > value) {
                    arr[index] = arr[index - gap];
                    index -= gap;
                }
                //退出循环时,待插入的值不小于前一位的值或前面已经没数据了
                if (index != i) {
                    arr[index] = value;
                }
            }
            System.out.println(Arrays.toString(arr));
        }
    }
}
80000个元素的数组测试平均已经不到1s 8百万个数据时平均23s
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值