常用算法

一、冒泡算法

冒泡排序(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

原文地址:https://www.cnblogs.com/shier-dong/p/15324351.html