php之經常使用算法實現

<?php
$arr = array(35,66,2,15,6,81,6,9,0,-2,9); 
    /* 堆排序: 利用大(小)頂堆的特性,不斷調整堆,依次選出待排序列中最大、次大值。 
    代碼參考自:http://www.cnblogs.com/zemliu/archive/2012/08/18/2645941.html 
    */ 
     function heapSort(&$arr) { 
         #初始化大頂堆 爲何要初始化,實際上是爲了找出待排序列中最大的值 
         initHeap($arr, 0, count($arr) - 1); 
         //print_r($arr);exit; 
         #開始交換首尾節點,並每次減小一個末尾節點再調整堆,直到剩下一個元素 
         for($end = count($arr) - 1; $end > 0; $end--) {  // 依次取出大頂堆中第一個根節點即最大值,並從新調整,即 
         //依次選出次大的元素 
             $temp = $arr[0]; 
             $arr[0] = $arr[$end]; 
             $arr[$end] = $temp; 
             ajustNodes($arr, 0, $end - 1); 
         } 
     } 
      
     #初始化最大堆,從最後一個非葉子節點開始,最後一個非葉子節點編號爲 數組長度/2 向下取整 
     function initHeap(&$arr) { 
         $len = count($arr); 
         for($start = floor($len / 2) - 1; $start >= 0; $start--) { 
             ajustNodes($arr, $start, $len - 1); 
         } 
     } 
      
     #調整節點 
     #@param $arr    待調整數組 
     #@param $start    調整的父節點座標 
     #@param $end    待調整數組結束節點座標 
     function ajustNodes(&$arr, $start, $end) { 
         $maxInx = $start; // 根節點 
         $len = $end + 1;    #待調整部分長度 
         $leftChildInx = ($start + 1) * 2 - 1;    #左孩子座標 
         $rightChildInx = ($start + 1) * 2;    #右孩子座標 
          
         #若是待調整部分有左孩子,調換左孩子與根節點,看哪一個做爲根節點 
         if($leftChildInx + 1 <= $len) { 
             #獲取最小節點座標 
             if($arr[$maxInx] < $arr[$leftChildInx]) { 
                 $maxInx = $leftChildInx; 
             } 
         } 
         #若是待調整部分有右子節點 , 接上面的調整, 繼續調換右孩子與根節點,看哪一個做爲根節點 
         if($rightChildInx + 1 <= $len) { 
             if($arr[$maxInx] < $arr[$rightChildInx]) { 
                 $maxInx = $rightChildInx; 
             } 
         } 
         // 上面調整結束後,根、左、右三個節點中,根節點必定是最大值 即maxInx是最大值的索引。 
         #交換父節點和最大節點 
         if($start != $maxInx) { 
             // 將最大值的節點調整爲根節點 
             $temp = $arr[$start]; 
             $arr[$start] = $arr[$maxInx]; 
             $arr[$maxInx] = $temp; 
              
             #若是交換後的子節點還有子節點,繼續調整 
             if(($maxInx + 1) * 2 <= $len) {// 依次反覆 
                 ajustNodes($arr, $maxInx, $end); 
             } 
         } 
     } 
      
     $arr = array(35,66,2,15,6,81,6,9); 
     heapSort($arr); 
     print_r($arr); 
/* 
計數排序:依次計算出待排序列中每一個元素比他大(小)的元素個數。而後根據這個個數依次輸出便可 
得出有序的序列。缺點是:須要的空間巨大,特別是待排序列元素個數小,可是最大值卻巨大的狀況下, 
性能極差。 
*/ 
function count_sort($ary) { 
    $tmp = array(); 
    for($i = 0;$i< count($ary);$i++) { //第一步,須要找出最大值 
        if($max < $ary[$i]) { 
            $max = $ary[$i]; 
        } 
    } 
    for($i = 0;$i < $max;$i++) { 
        $tmp[$i] = 0; 
    } 
    for($i = 0;$i < count($ary);$i++) { 
        $tmp[$ary[$i]]++; 
    } 
     
    for ($i = 1; $i < count($tmp); $i++) { 
        $tmp[$i] += $tmp[$i-1]; 
    } 
    //print_r($tmp); 
    for ($i = 0; $i < count($ary); $i++) { 
        $tmp_ary[$tmp[$ary[$i]]] = $ary[$i]; 
        $tmp[$ary[$i]]--; 
    } 
     
    for ($i = 0; $i < count($tmp_ary); $i++) { 
        $ret[] = $tmp_ary[$i]; 
    } 
    return $ret; 
} 
$arr = array(35,66,2,15,6,81,6,44); 
print_r(count_sort($arr)); 

/* 
快速排序:通過一趟遍歷,根據某一基數[通常是第一個元素]將待排序列調整爲大值在右邊, 
小值在左邊的一個序列。按照這種方式不斷遞歸的調整直到待排序列只剩下一個元素。 
利用分治的思想,將待排序列每次分爲左邊小、右邊大的兩個序列,並依次對各子序列進行排序。
和歸併排序異同:都使用的分治的思想,先分後合。可是,快速排序經排序的過程集中在分的過程當中了,
而歸併排序則是將排序的過程集中在合的過程當中。
*/ 
function quick_sort($ary) { 
    if(count($ary) > 1) { 
        $left = array(); 
        $right = array(); 
        $pivot = $ary[0]; 
        for($i = 1;$i< count($ary);$i++) { 
            if($ary[$i] >= $pivot) $right[] = $ary[$i]; 
            else $left[] = $ary[$i]; 
        } 
         
        $left = quick_sort($left); 
        $right = quick_sort($right); 
        return array_merge($left,array($pivot),$right); 
    } else { 
        return $ary; 
    } 
} 
$arr = array(35,66,2,15,6,81,6,9); 
$sort_ary = quick_sort($ary); 
print_r($sort_ary); 
/* 
快速排序第二個版本。*/ 
function partition(&$ary,$low,$high) { 
    $tmp = $ary[$low]; 
    while($low < $high) { 
        while($low < $high && $ary[$high] >= $tmp) {  
            $high--; 
        } 
        $ary[$low] = $ary[$high];// 巧妙之處: 這裏只要一發生交換,下面的low就必須往前走一步
        while($low < $high && $ary[$low] <= $tmp) { 
            $low++; 
        } 
        $ary[$high] = $ary[$low];// 這裏只要一發生交換,上面的high就必須往前走一步,這樣一來,其實左右 
        // 調換過來的元素並無相互覆蓋掉。 
    } 
    $ary[$low] = $tmp;// 最後,須要把基數賦值給low下標,此時的low下面就是調整後次序列的分水嶺,右邊值大,左邊值小 
    return $low; 
} 


function quick_sort2(&$ary,$low,$high) { 
    if($low < $high) { 
        $p = partition($ary,$low,$high); 
        quick_sort($ary,$low,$p - 1); 
        quick_sort($ary,$p+1,$high); 
    } 
    return $ary; 
} 
$arr = array(35,66,2,15,6,81,6,9); 
$sort_ary = quick_sort2($ary,0,count($ary)); 
print_r($sort_ary); 

/* 
/* 直接插入排序*/ 
function cr_sort1($ary) { 
    for($i = 1;$i < count($ary);$i++) { 
        $tmp = $ary[$i]; 
        $j = $i - 1;     
        while($j>=0 && $ary[$j] > $tmp) { 
            $ary[$j + 1] = $ary[$j]; 
            $j--; 
        } 
        $ary[$j+1] = $tmp; 
    } 
    return $ary; 
} 

// 插入排序另外一種寫法 
function cr_sort2($ary) { 
    for($i=1;$i < count($ary);$i++) { 
        $tmp = $ary[$i]; 
        $j = $i; 
        while($j >= 0 && $tmp < $ary[$j-1]) { 
            $ary[$j] = $ary[$j-1];// 日後移 
            $j--; 
        } 
        $ary[$j] = $tmp;// 插入 
    } 
    return $ary; 
} 
/*折半插入:因爲普通的插入算法是依次將待排序的元素與已經完成排序的序列每個元素作比較, 
而後插入到合適位置。二分插入的出現是爲了減小元素的比較次數,本質是對插入排序的優化。 
具體思想是:利用二分查找,直接將待排序的那個元素定位到有序序列中須要插入的位置。這是優化的關鍵點。 
*/ 
function cr_sort3($ary) { 
    for($i = 1;$i < count($ary);$i++) { 
        $tmp = $ary[$i]; 
        $j = $i - 1; 
        $low = 0; 
        $high = $i - 1; 
        while($low <= $high) { 
            $mid = floor(($low + $high) / 2); 
            if($tmp > $ary[$mid]) $low = $mid + 1; 
            else  $high = $mid - 1; 
        } 
         
        while($j >= $low) { 
            $ary[$j + 1] = $ary[$j]; 
            $j--; 
        } 
        $ary[$low] = $tmp; 
    } 
    return $ary; 
} 
/* 
希爾排序:對插入排序的改進版。 基本算法是創建在直接插入排序算法之上的。 
基本思想是:按照某遞增量,「間隔」的將待排序列調整爲有序的序列。跳躍性的插入排序。 

*/ 
function shell_sort($ary) { 
    $d = count($ary); 
    while($d  > 1) { 
        $d  = intval($d / 2); //遞增 
        for($i = $d;$i < count($ary);$i+=$d) { 
            $tmp = $ary[$i]; 
            $j = $i - $d;     
            while($j >= 0 && $ary[$j] > $tmp) { 
                $ary[$j + $d] = $ary[$j]; 
                $j -= $d; 
            } 
            $ary[$j+$d] = $tmp; 
        } 
    } 
    return $ary; 
} 

// 選擇排序: 每次從待排序列中選出最大、次大的元素 
function xz_sort(&$ary) { 
    for($i = 0;$i < count($ary);$i++) { 
        $tmp = $ary[$i]; 
        for($j = $i+1;$j < count($ary);$j++) { 
            if($ary[$i] > $ary[$j]) { 
                $sit = $j; 
                $ary[$i] = $ary[$j]; 
            } 
        } 
        if($tmp != $ary[$i]) { 
            $ary[$sit] = $tmp; 
        } 
        //$ary[$i] = $flag; 
    } 
    return $ary; 
} 




$ary = array(23,-2,9,0,89,100,-23); 
$ary = cr_sort1($ary); 
print_r($ary); 
// 冒泡: 依次比較相鄰的元素,兩兩比較,就能夠最終將最大(小)的元素調整到最頂端、次頂端、、、 
// 下面的兩種寫法: 一是從前向後冒泡,第一次將對打元素冒到最上面、第二次冒到次下面。 
// 第二種:從後向前冒泡。 

function mp_sort2(&$ary) { 
    for($i = 0;$i < count($ary);$i++) { 
        for($j = 0;$j < count($ary) - $i - 1;$j++) { 
            if($ary[$j] > $ary[$j+1]) { 
                $tmp = $ary[$j]; 
                $ary[$j] = $ary[$j+1]; 
                $ary[$j+1] = $tmp; 
            } 
             
        } 
    } 
    return $ary; 
} 

function mp_sort(&$ary) { 
    for($i = 0;$i < count($ary);$i++) { 
        for($j = count($ary)-2;$j >= $i;$j--) { 
            if($ary[$j] > $ary[$j+1]) { 
                $tmp = $ary[$j]; 
                $ary[$j] = $ary[$j+1]; 
                $ary[$j+1] = $tmp; 
            } 
        } 
    } 
    return $ary; 
} 

// 二分查找 非遞歸算法 
function div_search($ary,$key) { 
    $low = 0; 
    $high = count($ary) - 1; 
    $i = 0; 
    while($low <= $high) { 
        $mid = floor(($high+$low)/2); 
        if($key == $ary[$mid]) return $key; 
        elseif($key < $ary[$mid]) $high = $mid -1;// 惟有這樣,範圍纔會不斷縮小啊 
        else $low = $mid + 1; 
    } 
} 
// 二分查找 遞歸算法 
function re_div_search($ary,$key,$low,$high) { 
    $mid = floor(($high+$low)/2); 
    if($key == $ary[$mid]) return $key; 
    elseif($key < $ary[$mid]) return re_div_search($ary,$key,$low,$mid -1); 
    else return re_div_search($ary,$key,$mid + 1,$high); 
} 
// 回溯法找子串 
function find_str($str,$substr) { 
    $i = 0; 
    $j =0 ; 
    while($i<strlen($str) && $j<strlen($substr)) { 
        if($str[$i]==$substr[$j]) { 
            $i++; 
            $j++; 
        } else { 
            $i = $i - $j +1; // 不相等的狀況下,i是要向前走的哦! 
            $j = 0; 
        } 
    } 
    if($j == strlen($substr)) return true; 
    return false; 
} 

$str = 'XXXhello world'; 
$substr = 'ld'; 
echo find_str($str,$substr); 
exit; 

// 斐波那契數列 
function findN($n) { 
    if($n <= 2) return 1; 
    return findN($n-2)+findN($n-1); 
} 
// 斐波那契數列的非遞歸形式 
function findN1($n) { 
    $arr = array(1,1); 
    if($arr <= 2) return $arr; 
    for($i = 2;$i < $n;$i++) { 
        $arr[] = $arr[$i-1] + $arr[$i-2] ; 
    } 
    return implode(',',$arr); 
} 
print_r(findN1(7));exit; 
for($i = 1;$i<=20;$i++) { 
    echo findN($i); 
    echo '<br>'; 
} 
exit; 


//$ary = array(100,1,10,10,2,8,890,4,-98,39,89,12,-2); 

//$ary = mp_sort($ary); 

//print_r($ary);
相關文章
相關標籤/搜索