PHP基礎算法

<?php
/*1、冒泡排序

基本思想:

對須要排序的數組從後往前(逆序)進行多遍的掃描,當發現相鄰的兩個數值的次序與排序要求的規則不一致時,就將這兩個數值進行交換。這樣比較小(大)的數值就將逐漸從後面向前面移動。
*/
function mysort($arr)
{
    for($i = 0; $i < count($arr); $i++)
    {
        $isSort = false;
        for ($j=0; $j< count($arr) - $i - 1; $j++)
        {
            if($arr[$j] < $arr[$j+1])
            {
                $isSort = true;
                $temp = $arr[$j];
                $arr[$j] = $arr[$j+1];
                $arr[$j+1] = $temp ;
            }
        }
        if($isSort)
        {
            break;
        }
    }
    return $arr;
}

$arr = array(3,1,2);
var_dump(mysort($arr));

/*2、快速排序

基本思想:

在數組中挑出一個元素(多爲第一個)做爲標尺,掃描一遍數組將比標尺小的元素排在標尺以前,將全部比標尺大的元素排在標尺以後,經過遞歸將各子序列分別劃分爲更小的序列直到全部的序列順序一致。*/

//快速排序
function quick_sort($arr)
{
    //先判斷是否須要繼續進行
    $length = count($arr);
    if($length <= 1)
    {
        return $arr;
    }

    $base_num = $arr[0];//選擇一個標尺 選擇第一個元素

    //初始化兩個數組
    $left_array = array();//小於標尺的
    $right_array = array();//大於標尺的
    for($i=1; $i<$length; $i++)
    {      //遍歷 除了標尺外的全部元素,按照大小關係放入兩個數組內
        if($base_num > $arr[$i])
        {
            //放入左邊數組
            $left_array[] = $arr[$i];
        }
        else
        {
            //放入右邊
            $right_array[] = $arr[$i];
        }
    }
    //再分別對 左邊 和 右邊的數組進行相同的排序處理方式
    //遞歸調用這個函數,並記錄結果
    $left_array = quick_sort($left_array);
    $right_array = quick_sort($right_array);
    //合併左邊 標尺 右邊
    return array_merge($left_array, array($base_num), $right_array);
}

$arr = array(3,1,2);
var_dump(quick_sort($arr));

//快速排序第二種方法
//快速排序
function partition(&$arr,$low,$high){
    $pivotkey = $arr[$low];
    while($low<$high){
        while($low < $high && $arr[$high] >= $pivotkey){
            $high--;
        }
        $temp = $arr[$low];
        $arr[$low] = $arr[$high];
        $arr[$high] = $temp;
        while($low < $high && $arr[$low] <= $pivotkey){
            $low++;
        }
        $temp=$arr[$low];
        $arr[$low]=$arr[$high];
        $arr[$high]=$temp;
    }
    return$low;
}


function quick_sort2(&$arr,$low,$high){
    if($low < $high){
        $pivot = partition($arr,$low,$high);
        quick_sort2($arr,$low,$pivot-1);
        quick_sort2($arr,$pivot+1,$high);
    }
}
$arr = array(3,1,2);
var_dump(quick_sort2($arr,0,2));
//該算法是經過分治遞歸來實現的,其效率很大程度上取決於參考元素的選擇,能夠選擇數組的中間元素,也能夠隨機獲得三個元素,而後選擇中間的那個元素(三數中值法)。另外還有一點,就是當咱們在分割時,若是分割出來的子序列的長度很小的話(小於5到20),一般遞歸的排序的效率就沒有諸如插入排序或希爾排序那麼快了。所以能夠會去判斷數組的長度,若是小於10的話,直接用插入排序,而再也不遞歸調用這個快速排序。

/*
 * 3、二分查找

基本思想:

假設數據是按升序排序的,對於給定值x,從序列的中間位置開始比較,若是當前位置值等於x,則查找成功;若x小於當前位置值,則在數列的前半段中查找;若x大於當前位置值則在數列的後半段中繼續查找,直到找到爲止。(數據量大的時候使用)
 */
//二分查找
function bin_search($arr,$low,$high,$k)
{
    if($low <= $high)
    {
        $mid = intval(($low + $high)/2);
        if($arr[$mid] == $k)
        {
            return $mid;
        }
        else if($k < $arr[$mid])
        {
            return bin_search($arr,$low,$mid-1,$k);
        }
        else
        {
            return bin_search($arr,$mid+1,$high,$k);
        }
    }
    return -1;
}

$arr = array(1,2,3,4,5,6,7,8,9,10);

print(bin_search($arr,0,9,3));

/*
 * 4、順序查找

基本思想:

從數組的第一個元素開始一個一個向下查找,若是有和目標一致的元素,查找成功;若是到最後一個元素仍沒有目標元素,則查找失敗。
 */

//順序查找
function seq_search($arr,$n,$k)
{
    $array[$n] = $k;
    for($i = 0;$i < $n; $i++)
    {
        if($arr[$i] == $k)
        {
            break;
        }
    }

    if($i < $n)
    {
        return $i;
    }
    else
    {
        return -1;
    }
}

/*
 * 洗牌算法
 */
$card_num = 54;//牌數
function wash_card($card_num){
    $cards = $tmp = array();
    for($i = 0;$i < $card_num;$i++){
        $tmp[$i] = $i;
    }

    for($i = 0;$i < $card_num;$i++){
        $index = rand(0,$card_num-$i-1);
        $cards[$i] = $tmp[$index];
        unset($tmp[$index]);
        $tmp = array_values($tmp);
    }
    return $cards;
}
// 測試:
print_r(wash_card($card_num));

/*
 * 二維數組排序算法函數,可以具備通用性,能夠調用php內置函數。
 */
//二維數組排序,$arr是數據,$keys是排序的健值,$order是排序規則,1是降序,0是升序
function array_sort($arr,$keys,$order=0){
    if(!is_array($arr)){
        return false;
    }
    $keysvalue=array();
    foreach($arr as $key => $val){
        $keysvalue[$key] = $val[$keys];
    }
    if($order == 0){
        asort($keysvalue);
    }else{
        arsort($keysvalue);
    }
    reset($keysvalue);
    foreach($keysvalue as $key => $vals){
        $keysort[$key] = $key;
    }
    $new_array=array();
    foreach($keysort as $key=> $val){
        $new_array[$key]=$arr[$val];
    }
    return$new_array;
}
//測試
$person=array(
    array('id'=>2,'name'=>'zhangsan','age'=>23),
    array('id'=>5,'name'=>'lisi','age'=>28),
    array('id'=>3,'name'=>'apple','age'=>17)
);
$result = array_sort($person,'name',1);
print_r($result);

/*
 * 關於猴子的面試題
 * 一羣猴子排成一圈,按1,2,...,n依次編號。而後從第1只開始數,數到第m只,把它踢出圈,從它後面再開始數,再數到第m只,在把它踢出去...,
 如此不停的進行下去,直到最後只剩下一隻猴子爲止,那隻猴子就叫作大王。要求編程模擬此過程,輸入m、n,輸出最後那個大王的編號。(新浪)(小米)
 */
// 方案一,使用php來模擬這個過程
function king($n,$m){
    $mokey = range(1, $n);
    $i = 0;

    while (count($mokey) >1) {
        $i += 1;
        $head = array_shift($mokey);//一個個出列最前面的猴子
        if ($i % $m !=0) {
            #若是不是m的倍數,則把猴子返回尾部,不然就拋掉,也就是出列
            array_push($mokey,$head);
        }

        // 剩下的最後一個就是大王了
        return $mokey[0];
    }
}
// 測試
echo king(10,7);

// 方案二,使用數學方法解決
function josephus($n,$m){
    $r = 0;
    for ($i=2; $i <= $m ; $i++) {
        $r = ($r + $m) % $i;
    }

    return $r+1;
}
// 測試
print_r(josephus(10,7));

/*
 * 使對象能夠像數組同樣進行foreach循環,要求屬性必須是私有。(Iterator模式的PHP5實現,寫一類實現Iterator接口)(騰訊)
 */
class Test implements Iterator{
    private $item = array('id'=>1,'name'=>'php');

    public function rewind(){
        reset($this->item);
    }

    public function current(){
        return current($this->item);
    }

    public function key(){
        return key($this->item);
    }

    public function next(){
        return next($this->item);
    }

    public function valid(){
        return($this->current()!==false);
    }
}
//測試
$t=new Test;
foreach($t as $k=>$v){
    echo$k,'--->',$v,'<br/>';
}

/*
 * 用PHP實現一個雙向隊列(騰訊)
 */
class Deque{
    private $queue=array();
    public function addFirst($item){
        return array_unshift($this->queue,$item);
    }

    public function addLast($item){
        return array_push($this->queue,$item);
    }
    public function removeFirst(){
        return array_shift($this->queue);
    }

    public function removeLast(){
        return array_pop($this->queue);
    }
}



/*
 * 8.從0,1,2,3,4,5,6,7,8,9,這十個數字中任意選出三個不一樣的數字,「三個數字中不含0和5」的機率是(小米)
 */
function gailv(){
    $arr = array(0,1,2,3,4,5,6,7,8,9);
}

//9.一個三角形三個頂點有3只老鼠,一聲槍響,3只老鼠開始沿三角形的邊勻速運動,請問他們相遇的機率是(小米)
 function xiangyu(){
     /*
      * 75%,每隻老鼠都有順時針、逆時鐘兩種運動方向,3只老鼠共有8種運動狀況,只有當3只老鼠都爲順時針或者逆時鐘,它們纔不會相遇,剩餘的6中狀況都會相遇,故相遇的機率爲6/8=75%。
      */

 }

/*
 * 三、楊輝三角,用PHP寫。

思路:每一行的第一位和最後一位是1,沒有變化,中間是前排一位與左邊一排的和,這種算法是用一個二維數組保存,另外有種算法用一維數組也能夠實現,一行 一行的輸出,有興趣去寫着玩下。

1
1   1
1   2   1
1   3   3   1
1   4   6   4   1
1   5  10  10   5   1
 */
//每行的第一個和最後一個都爲1,寫了6行
for($i=0; $i<6; $i++) {
    $a[$i][0]=1;
    $a[$i][$i]=1;
}
//出除了第一位和最後一位的值,保存在數組中
for($i=2; $i<6; $i++) {
    for($j=1; $j<$i; $j++) {
        $a[$i][$j] = $a[$i-1][$j-1]+$a[$i-1][$j];
    }
}
//打印
for($i=0; $i<6; $i++){
    for($j=0; $j<=$i; $j++) {
        echo $a[$i][$j].' ';
    }
    echo '<br/>';
}

/*
 * 四、在一組數中,要求插入一個數,按其原來順序插入,維護原來排序方式。

思路:找到比要插入數大的那個位置,替換,而後把後面的數後移一位。
 */

$in = 2;
$arr = array(1,1,1,3,5,7);
$n = count($arr);
//若是要插入的數已經最大,直接打印
if($arr[$n-1] < $in) {
    $arr[$n+1] = $in; print_r($arr);
}
for($i=0; $i<$n; $i++) {
//找出要插入的位置
    if($arr[$i] >= $in){
        $t1= $arr[$i];
        $arr[$i] = $in;
//把後面的數據後移一位
        for($j=$i+1; $j<$n+1; $j++) {
            $t2 = $arr[$j];
            $arr[$j] = $t1;
            $t1 = $t2;
        }
//打印
        print_r($arr);
        die;
    }
}

/*
 * 八、牛年求牛:有一母牛,到4歲可生育,每一年一頭,所生均是同樣的母牛,到15歲絕育,再也不能生,20歲死亡,問n年後有多少頭牛。(來自論壇)
 */
function t($n) {
    static $num = 1;
    for($j=1; $j<=$n; $j++){
        if($j>=4 && $j<15) {$num++;t($n-$j);}
        if($j==20){$num--;}
    }
     return $num;
}
//test
echo t(8);

/*
 * 插入排序   (insertion sort)— O(n2)
 * 【基本思想】:每次將一個待排序的數據元素,插入到前面已經排好序的數列中的適當位置,使數列依然有序;直到待排序數據元素 所有插入完爲止。
 */
$data = array(6,13,21,99,18,2,25,33,19,84);
$nums = count($data)-1;
dump( $data );
InsertionSort($data,$nums);
dump( $data );
function InsertionSort(& $arr,$n )
{
    for( $i=1; $i<=$n; $i++ )
    {
        $tmp = $arr[$i];
        for( $j = $i; $j>0 && $arr[$j-1]>$tmp; $j-- )
        {
            $arr[$j] = $arr[$j-1];
        }
        $arr[$j] = $tmp;
    }
}
function dump( $d )
{
    echo '<pre>';print_r($d);echo '</pre>';
}

/*
 * 希 爾排序   (shell sort)— O(n log n)
 */
$data = array(6,13,21,99,18,2,25,33,19,84);
$nums = count($data);
dumps( $data );
ShellSort($data,$nums);
dumps( $data );
function ShellSort(& $arr,$n )
{
    for( $increment = intval($n/2); $increment > 0; $increment = intval($increment/2) )
    {
        for( $i=$increment; $i<$n; $i++ )
        {
            $tmp = $arr[$i];
            for( $j = $i; $j>= $increment; $j -= $increment )
                if( $tmp < $arr[ $j-$increment ] )
                    $arr[$j] = $arr[$j-$increment];
                else
                    break;
            $arr[$j] = $tmp;
        }
    }
}
function dumps( $d )
{
    echo '<pre>';print_r($d);echo '</pre>';
}

/**
 * 排列組合
 * 採用二進制方法進行組合的選擇,如表示5選3時,只需有3位爲1就能夠了,因此可獲得的組合是 01101 11100 00111 10011 01110等10種組合
 *
 * @param 須要排列的數組 $arr
 * @param 最小個數 $min_size
 * @return 知足條件的新數組組合
 */
function pl($arr,$size=5) {
    $len = count($arr);
    $max = pow(2,$len);
    $min = pow(2,$size)-1;
    $r_arr = array();
    for ($i=$min; $i<$max; $i++){
        $count = 0;
        $t_arr = array();
        for ($j=0; $j<$len; $j++){
            $a = pow(2, $j);
            $t = $i&$a;
            if($t == $a){
                $t_arr[] = $arr[$j];
                $count++;
            }
        }
        if($count == $size){
            $r_arr[] = $t_arr;
        }
    }
    return $r_arr;
}
$pl = pl(array(1,2,3,4,5,6,7),5);
var_dump($pl);
//遞歸算法
//階乘
function f($n){
    if($n == 1 || $n == 0){
        return 1;
    }else{
        return $n*f($n-1);
    }
}
echo f(5);
//遍歷目錄
function iteral($path){
    $filearr = array();
    foreach (glob($path.'\*') as $file){
        if(is_dir($file)){
            $filearr = array_merge($filearr,iteral($file));
        }else{
            $filearr[] = $file;
        }
    }
    return $filearr;
}
var_dump(iteral('d:\www\test'));


/*
【選擇排序(一維數組)】
【基 本思想】:每一趟從待排序的數據元素中選出最小(或最大)的一個元素,順序放在已排好序的數列的最後,直到所有待排序的數據元素排完。
【示例】:
[初 始關鍵字] [49 38 65 97 76 13 27 49]
第一趟排序後 13 [38 65 97 76 49 27 49]
第 二趟排序後 13 27 [65 97 76 49 38 49]
第三趟排序後 13 27 38 [97 76 49 65 49]
第 四趟排序後 13 27 38 49 [49 97 65 76]
第五趟排序後 13 27 38 49 49 [97 97 76]
第 六趟排序後 13 27 38 49 49 76 [76 97]
第七趟排序後 13 27 38 49 49 76 76 [ 97]
最 後排序結果 13 27 38 49 49 76 76 97
*/
function select_sort($arr){
    $count = count($arr);
    for($i=0; $i<$count; $i++){
        $k = $i;
        for($j=$i+1; $j<$count; $j++){
            if ($arr[$k] > $arr[$j])
                $k = $j;
        }
        if($k != $i){
            $tmp = $arr[$i];
            $arr[$i] = $arr[$k];
            $arr[$k] = $tmp;
        }
    }
    return $arr;
}
?>
相關文章
相關標籤/搜索