码迷,mamicode.com
首页 > 编程语言 > 详细

算法路漫漫(一) 简单排序

时间:2021-06-20 18:14:51      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:ted   出错   原理   二进制   描述   strong   插入排序   insert   二分法   

1.认识时间复杂度

常数时间的操作:一个操作如果和数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。
时间复杂度为一个算法流程中,常数操作数量的指标。常用O(读作big O)来表示。具体来说,在常数操作数量的表达式中,只要高阶项,不要低阶项,也不要高阶项的系数,
剩下的部分如果记为f(N),那么时间复杂度为O(f(N))。评价一个算法流程的好坏,先看时间复杂度的指标,然后再分析不同数据样本下的实际运行时间,也就是常数项时间。

衡量算法复杂度

1.内存(Memory)
2.时间(Time)
3.指令的数量(Number of Steps)
4.特定操作的数量
    磁盘访问数量
    网络包数量
5.渐进复杂度(Asymptotic Complexity)

算法的运行时间与什么相关

1.输入的数据。(例如:如果数据已经是排好序的,时间消耗可能会减少。)
2.输入数据的规模。(例如:6 和 6 * 1093.运行时间的上限。(因为运行时间的上限是对使用者的承诺。)

算法分析要保持大局观(Big Idea),其基本思路:

1.忽略掉那些依赖于机器的常量。
2.关注运行时间的增长趋势。

比如:T(n) = n3 + 99n3 + 9999 的趋势就相当于 T(n) = Θ(n3)。

渐近记号(Asymptotic Notation)通常有 O、 Θ 和 Ω 记号法。big O 表示按算法最差表现估算,big θ  表示按算法平均表现估算,big Ω 表示按算法最好表现估算。尽管技术上 Θ 记号较为准确,但通常仍然使用 O 记号表示。

使用 O 记号法(Big O Notation)表示最坏运行情况的上界。例如,

1.线性复杂度 O(n) 表示每个元素都要被处理一次。
2.平方复杂度 O(n2) 表示每个元素都要被处理 n 次。
Notation Intuition Informal Definition
技术图片

f is bounded above by g asymptotically

技术图片

技术图片

Two definitions :
Number theory:

f is not dominated by g asymptotically

Complexity theory:

f is bounded below by g asymptotically

技术图片

技术图片

f is bounded both above and below by g asymptotically

技术图片

 

 2.简单排序

2.1 选择排序

选择排序(Select Sort) 是直观的排序,通过确定一个 Key 最大或最小值,再从带排序的的数中找出最大或最小的交换到对应位置。再选择次之。双重循环时间复杂度为 O(n^2) 

 技术图片

    private void sellectionSorted(int[] arr){
        if(arr == null || arr.length <=1){
            return;
        }
        // i ~ N-1
        for(int i=0;i<arr.length-1;i++){
            int minIndex=i;
            // i ~ N-1 get min
            for(int j=i+1;j<arr.length;j++){
                minIndex = arr[j] < arr[minIndex] ? j : minIndex;    
            }
            swap(arr ,minIndex,i);
        }
    }


    private void swap(int[] arr, int a, int b){
        int tmp = arr[a];
        arr[a] = arr[b];
        arr[b] = tmp;
    }

2.2 冒泡排序

冒泡排序(Bubble Sort) 最为简单的一种排序,通过重复走完数组的所有元素,通过打擂台的方式两个两个比较,直到没有数可以交换的时候结束这个数,再到下个数,直到整个数组排好顺序。因一个个浮出所以叫冒泡排序。双重循环时间 O(n^2)

 技术图片

    private void bubbleSorted(int[] arr){
        if(arr == null || arr.length <=1){
            return;
        }
        // i ~ N-1
        for(int i=arr.length-1;i>0;i--){
            // i ~ N-1 set max to the end of arr
            for(int j=0;j<i;j++){
                if(arr[j+1] < arr[j]) {
                    swap(arr ,j+1,j);
                } 
            }
            
        }
    }

    // 异或运算
    private void swap(int[] arr, int a, int b){
        arr[a] = arr[a]^arr[b];
        arr[b] = arr[a]^arr[b];
        arr[a] = arr[a]^arr[b];
    }

2.3 插入排序

插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

技术图片

    private void insertSorted(int[] arr){
        if(arr == null || arr.length <=1){
            return;
        }
        // 0 ~1 compare and swap
        // 0 ~2 compare and swap
        for(int i=0;i<arr.length;i++){
            // i ~ N-1 compare and swap
            for(int j=i;j>0;j--){
                if(arr[j-1] > arr[j]) {
                    swap(arr ,j-1,j);
                } 
            }
            
        }
    }

    // 异或运算
    private void swap(int[] arr, int a, int b){
        arr[a] = arr[a]^arr[b];
        arr[b] = arr[a]^arr[b];
        arr[a] = arr[a]^arr[b];
    }

2.4 二分法

二分法查找,也称为折半法,是一种在有序数组中查找特定元素的搜索算法。首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复上面的的操作。如果某一步数组为空,则表示找不到目标元素。二分法查找的时间复杂度O(logn)。

    private int searchMatch(int[] arr, int low, int high, int target){
        if(low > high){
            return -1;
        }
        int mid = low + ((high-low)>>1);

        // 
        if(arr[mid] == target){
            return mid;
        } else if(arr[mid] < target){
            // search in [mid+1, high]
            return searchMatch(arr, mid+1, high, target);
        } else {
            // search in [low, mid-1]
            return searchMatch(arr, low, mid-1, target);
        }
    }

一般下面几个场景适合二分查找

1.在一个有序数组中,查找某个数是否存在

2.在一个有序数组中,查找>=某个数最左侧位置

3. 在一个无序数组中,任何相邻两数不相等,寻找局部最小值

3.补充

3.1 异或运算

1. 0^N=N, N^N=0

2.异或运算满足交换率和结合率
A^B = B^A, A^(B^C) = (A^B)^C
3.同样一批数,异或运算,先后顺序变化 不影响结果
A^B^...^Z = Z^Y^...^A
4.无进位加法,相同为0,不同为1;
int a= 3= 011
int b= 5= 101
int c= a^b = 011^101=110=6

3.2 取出一个数对应二进制最右侧的1对应的整数

// 与上自己的取反加1
int
a= A & (~A+1);

 3.3 对数器

1.有一个你想要测的方法A
2.实现一个绝对正确但是复杂度不好的方法B
3.实现一个随机样本产生器
4.实现比对的方法
5.把方法A和方法B比对很多次来验证方法B是否正确。
6.如果有一个样本使得比对出错,打印样本分析是哪个方法出错
7.当样本数量很多时比对测试(假设10万次测试)依然正确,可以确定方法A已经正确

算法路漫漫(一) 简单排序

标签:ted   出错   原理   二进制   描述   strong   插入排序   insert   二分法   

原文地址:https://www.cnblogs.com/hlkawa/p/14883359.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!