zoukankan      html  css  js  c++  java
  • 常用算法

    一、冒泡算法

    冒泡排序(Bubble sort)是一种简单的排序算法,它重复的走访过要排序的数列,依次比较两个元素,如果他们的顺序错误就把他们交换过来,走访数列的的工作是重复的进行直到没有再需要的交换,也就是说该数列已经完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

    步骤:

    1. 比较相邻的元素,如果第一个比第二个大,就交换他们两个
    2. 对每一对相邻元素做相同的操作,从开始第一对到最后一对,再这一点,最后的元素应该是最大的数
    3. 针对所有的元素重复以上的步骤,除了最后一个
    4. 持续每次对越来越少的元素重复以上的步骤,直到没有任何一对数字需要比较
    //冒泡排序
    $arr = [4,6,3,8,1,10,5];
    function mysort($arr){
        $count = count($arr);
        for($i=0; $i<$count; $i++){
            for($j=0; $j<$count-$i-1; $j++){
                if($arr[$j]>$arr[$j+1]){
                    $tmp = $arr[$j+1];
                    $arr[$j+1] = $arr[$j];
                    $arr[$j] = $tmp;
                }
            }
        }
        return $arr;
    }
    print_r(mysort($arr));

    2.快速排序

    在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性。

    步骤:

    1. 从数列中挑出一个元素,成为“基准”(pivot)
    2. 重新排列数列,所有元素比基准值小的放在基准前面,所有元素比基准值大的放在基准后面(相同的数可以到任一边),在这个分区退出后,该基准就处于数列的中间位置,这成为分区(partition)操作
    3. 递归的(recursive)把小于基准值的子数列和大于基准值元素的子数列排序
    //快速排序
    $arr = [1,5,3,2,10,7,4];
    function quick_sort($arr){
        $count = count($arr);
        if($count<=1){
            return $arr;
        }
        $left = $right = [];
        for($i=1; $i<$count; $i++){
            if($arr[$i] < $arr[0]){
                $left[]=$arr[$i];
            }else{
                $right[]=$arr[$i];
            }
        }
        //递归调用
        $left=quick_sort($left);
        $right=quick_sort($right);
        
        return array_merge($left, array($arr[0]),$right);
    }
    print_r(quick_sort($arr));

    3.二叉树查找

    假如数据必须是按照升序排序的,对于给定值x,从序列的中间值开始比较,如果当前位置等于x则查找成功;若x小于当前位置值则在数列的前半段查找;若x大于当前位置值则再数列的后半段查找,直到找到为止。(数据量大的时候使用)

    //二分查找
    $arr = [1,2,3,4,5,6,7,8,9,10];
    function bin_search($arr, $low, $high, $k){
        if($low<=$high){
            $mid = intval(($low+$high)/2);
            if($arr[$mid]==$k){
                return $mid;
            }elseif( $k<$arr[$mid] ){
                return bin_search($arr, $low, $mid-1, $k );
            }else{
                return bin_search($arr, $mid+1, $high, $k);
            }
        }
        return -1;
    }
    echo bin_search($arr, 0, count($arr), 8);

      

    4.选择排序

    工作原理:首先再未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从未排序序列中继续寻找最小元素存放到排序序列末尾,以此类推,直到所有元素都排序完毕

    //选择排序
    $arr = [1,3,20,9,5,4,8];
    function selectSort($arr){
        $len = count($arr);
        for($i=0; $i<$len-1; $i++){
            $p = $i;
            for($j=$i+1; $j<$len; $j++){
                $p = $arr[$p]<=$arr[$j] ? $p : $j;
            }
            if($p!=$i){
                $tmp = $arr[$p];
                $arr[$p] = $arr[$i];
                $arr[$i] = $tmp;
            }
        }
        return $arr;
    }
    print_r(selectSort($arr));

    4.雪花算法

     SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法

    其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应用十分广泛,且ID 引入了时间戳,保持自增性且不重复。

    雪花算法的结构:

    主要分为5个部分:

    1. 是 1 个 bit:0,这个是无意义的。
    2. 是 41 个 bit:表示的是时间戳。
    3. 是 10 个 bit:表示的是机房 id,0000000000,因为我传进去的就是0。
    4. 是 12 个 bit:表示的序号,就是某个机房某台机器上这一毫秒内同时生成的 id 的序号,0000 0000 0000。

    这四个部分的解释:

    1 bit,是无意义的:

    • 因为二进制里第一个 bit 为如果是 1,那么都是负数,但是我们生成的 id 都是正数,所以第一个 bit 统一都是 0。

    41 bit:表示的是时间戳,单位是毫秒。

    • 41 bit 可以表示的数字多达 2^41 - 1,也就是可以标识 2 ^ 41 - 1 个毫秒值,换算成年就是表示 69 年的时间。

    10 bit:记录工作机器 id,代表的是这个服务最多可以部署在 2^10 台机器上,也就是 1024 台机器。

    • 但是 10 bit 里 5 个 bit 代表机房 id,5 个 bit 代表机器 id。意思就是最多代表 2 ^ 5 个机房(32 个机房),每个机房里可以代表 2 ^ 5 个机器(32 台机器),这里可以随意拆分,比如拿出4位标识业务号,其他6位作为机器号。可以随意组合。

    12 bit:这个是用来记录同一个毫秒内产生的不同 id。

    • 12 bit 可以代表的最大正整数是 2 ^ 12 - 1 = 4096,也就是说可以用这个 12 bit 代表的数字来区分同一个毫秒内的 4096 个不同的 id。也就是同一毫秒内同一台机器所生成的最大ID数量为4096

    简单来说,你的某个服务假设要生成一个全局唯一 id,那么就可以发送一个请求给部署了 SnowFlake 算法的系统,由这个 SnowFlake 算法系统来生成唯一 id。这个 SnowFlake 算法系统首先肯定是知道自己所在的机器号,(这里姑且讲10bit全部作为工作机器ID)接着 SnowFlake 算法系统接收到这个请求之后,首先就会用二进制位运算的方式生成一个 64 bit 的 long 型 id,64 个 bit 中的第一个 bit 是无意义的。接着用当前时间戳(单位到毫秒)占用41 个 bit,然后接着 10 个 bit 设置机器 id。最后再判断一下,当前这台机房的这台机器上这一毫秒内,这是第几个请求,给这次生成 id 的请求累加一个序号,作为最后的 12 个 bit。

    SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。但是依赖与系统时间的一致性,如果系统时间被回调,或者改变,可能会造成id冲突或者重复。实际中我们的机房并没有那么多,我们可以改进改算法,将10bit的机器id优化,成业务表或者和我们系统相关的业务。

      其实对于分布式ID的生成策略。无论是我们上述提到的哪一种。无非需要具有以下两种特点。 自增的、不重复的。而对于不重复且是自增的,那么我们是很容易想到的是时间,而雪花算法就是基于时间戳。但是毫秒级的并发下如果直接拿来用,显然是不合理的。那么我们就要在这个时间戳上面做一些文章。至于怎么能让这个东西保持唯一且自增。就要打开自己的脑洞了。可以看到雪花算法中是基于 synchronized 锁进行实现的。

    PHP实现雪花算法:https://www.cnblogs.com/lz0925/p/11288058.html

    更多排序算法:

    https://www.cnblogs.com/mzhaox/p/11218297.html

    https://www.cnblogs.com/xiaobingch/p/12464045.html

  • 相关阅读:
    Android引导页设计
    QQ5.0左侧滑动显示效果
    QQ左侧滑动显示之按钮切换
    QQ左侧滑动显示之自定义属性
    HDU 4009——Transfer water——————【最小树形图、不定根】
    HDU 2121——Ice_cream’s world II——————【最小树形图、不定根】
    POJ 3164——Command Network——————【最小树形图、固定根】
    HDU 5532——Almost Sorted Array——————【技巧】
    UVA 10462 —— Is There A Second Way Left?——————【最小生成树、kruskal、重边】
    HDU 4081—— Qin Shi Huang's National Road System——————【次小生成树、prim】
  • 原文地址:https://www.cnblogs.com/shier-dong/p/15324351.html
Copyright © 2011-2022 走看看