feat: Add PHP Codes for chapter_computational_complexity

This commit is contained in:
DoWake 2024-05-19 22:42:06 +08:00
parent e1e0668e0f
commit 422694cf2c
5 changed files with 499 additions and 0 deletions

View File

@ -0,0 +1,76 @@
<?php
/**
* File: iteration.php
* Created Time: 2024-05-19
* Author: DoWake (admin@mengxing.cc)
*/
/* for 循环 */
function forLoop($n)
{
$res = 0;
// 循环求和 1, 2, ..., n-1, n
for ($i = 1; $i <= $n; $i++) {
$res += $i;
}
return $res;
}
/* while 循环 */
function whileLoop($n)
{
$res = 0;
$i = 1; // 初始化条件变量
// 循环求和 1, 2, ..., n-1, n
while ($i <= $n) {
$res += $i;
$i++; // 更新条件变量
}
return $res;
}
/* while 循环(两次更新) */
function whileLoopII($n)
{
$res = 0;
$i = 1; // 初始化条件变量
// 循环求和 1, 4, 10, ...
while ($i <= $n) {
$res += $i;
// 更新条件变量
$i++;
$i *= 2;
}
return $res;
}
/* 双层 for 循环 */
function nestedForLoop($n)
{
$res = '';
// 循环 i = 1, 2, ..., n-1, n
for ($i = 1; $i <= $n; $i++) {
// 循环 j = 1, 2, ..., n-1, n
for ($j = 1; $j <= $n; $j++) {
$res .= '(' . $i . ', ' . $j . '), ';
}
}
return $res;
}
/* Driver Code */
$n = 5;
$res = 0;
$res = forLoop($n);
echo "\nfor 循环的求和结果 res = {$res}" . PHP_EOL;
$res = whileLoop($n);
echo "\nwhile 循环的求和结果 res = {$res}" . PHP_EOL;
$res = whileLoopII($n);
echo "\nwhile 循环(两次更新)求和结果 res = {$res}" . PHP_EOL;
$resStr = nestedForLoop($n);
echo "\n双层 for 循环的遍历结果 {$resStr}" . PHP_EOL;

View File

@ -0,0 +1,80 @@
<?php
/**
* File: recursion.php
* Created Time: 2024-05-19
* Author: DoWake (admin@mengxing.cc)
*/
/* 递归 */
function recur($n)
{
// 终止条件
if ($n === 1) {
return 1;
}
// 递:递归调用
$res = recur($n - 1);
// 归:返回结果
return $n + $res;
}
/* 使用迭代模拟递归 */
function forLoopRecur($n)
{
// 使用一个显式的栈来模拟系统调用栈
$stack = [];
$res = 0;
// 递:递归调用
for ($i = $n; $i > 0; $i--) {
// 通过“入栈操作”模拟“递”
array_push($stack, $i);
}
// 归:返回结果
while (!empty($stack)) {
// 通过“出栈操作”模拟“归”
$res += array_pop($stack);
}
// res = 1+2+3+...+n
return $res;
}
/* 尾递归 */
function tailRecur($n, $res)
{
// 终止条件
if ($n === 0) {
return $res;
}
// 尾递归调用
return tailRecur($n - 1, $res + $n);
}
/* 斐波那契数列:递归 */
function fib($n)
{
// 终止条件 f(1) = 0, f(2) = 1
if ($n === 1 || $n === 2) {
return $n - 1;
}
// 递归调用 f(n) = f(n-1) + f(n-2)
$res = fib($n - 1) + fib($n - 2);
// 返回结果 f(n)
return $res;
}
/* Driver Code */
$n = 5;
$res = 0;
$res = recur($n);
echo "\n递归函数的求和结果 res = {$res}" . PHP_EOL;
$res = forLoopRecur($n);
echo "\n使用迭代模拟递归求和结果 res = {$res}" . PHP_EOL;
$res = tailRecur($n, 0);
echo "\n尾递归函数的求和结果 res = {$res}" . PHP_EOL;
$res = fib($n);
echo "\n斐波那契数列的第 {$n} 项为 {$res}" . PHP_EOL;

View File

@ -0,0 +1,117 @@
<?php
/**
* File: space_complexity.php
* Created Time: 2024-05-19
* Author: DoWake (admin@mengxing.cc)
*/
require_once '../utils/ListNode.php';
require_once '../utils/TreeNode.php';
require_once '../utils/PrintUtil.php';
/* 函数 */
function func()
{
// 执行某些操作
return 0;
}
/* 常数阶 */
function spaceConstant($n)
{
// 常量、变量、对象占用 O(1) 空间
define('A', 0);
$b = 0;
$nums = array_fill(0, 10000, 0);
$node = new ListNode(0);
// 循环中的变量占用 O(1) 空间
for ($i = 0; $i < $n; $i++) {
$c = 0;
}
// 循环中的函数占用 O(1) 空间
for ($i = 0; $i < $n; $i++) {
func();
}
}
/* 线性阶 */
function linear($n)
{
// 长度为 n 的数组占用 O(n) 空间
$nums = array_fill(0, $n, 0);
// 长度为 n 的列表占用 O(n) 空间
$nodes = [];
for ($i = 0; $i < $n; $i++) {
$nodes[] = new ListNode($i);
}
// 长度为 n 的哈希表占用 O(n) 空间
$map = [];
for ($i = 0; $i < $n; $i++) {
$map[$i] = strval($i);
}
}
/* 线性阶(递归实现) */
function linearRecur($n)
{
echo "递归 n = {$n}" . PHP_EOL;
if ($n === 1) {
return;
}
linearRecur($n - 1);
}
/* 平方阶 */
function quadratic($n)
{
// 矩阵占用 O(n^2) 空间
$numMatrix = array_fill(0, $n, array_fill(0, $n, 0));
// 二维列表占用 O(n^2) 空间
$numList = [];
for ($i = 0; $i < $n; $i++) {
$tmp = [];
for ($j = 0; $j < $n; $j++) {
$tmp[] = 0;
}
$numList[] = $tmp;
}
}
/* 平方阶(递归实现) */
function quadraticRecur($n)
{
if ($n <= 0) {
return 0;
}
// 数组 nums 长度为 n, n-1, ..., 2, 1
$nums = array_fill(0, $n, 0);
echo "递归 n = {$n} 中的 nums 长度 = " . count($nums) . PHP_EOL;
return quadraticRecur($n - 1);
}
/* 指数阶(建立满二叉树) */
function buildTree($n)
{
if ($n === 0) {
return null;
}
$root = new TreeNode(0);
$root->left = buildTree($n - 1);
$root->right = buildTree($n - 1);
return $root;
}
/* Driver Code */
$n = 5;
// 常数阶
spaceConstant($n);
// 线性阶
linear($n);
linearRecur($n);
// 平方阶
quadratic($n);
quadraticRecur($n);
// 指数阶
$root = buildTree($n);
PrintUtil::printTree($root);

View File

@ -0,0 +1,184 @@
<?php
/**
* File: time_complexity.php
* Created Time: 2024-05-19
* Author: DoWake (admin@mengxing.cc)
*/
/* 常数阶 */
function timeConstant($n)
{
$count = 0;
$size = 100000;
for ($i = 0; $i < $size; $i++) {
$count++;
}
return $count;
}
/* 线性阶 */
function linear($n)
{
$count = 0;
for ($i = 0; $i < $n; $i++) {
$count++;
}
return $count;
}
/* 线性阶(遍历数组) */
function arrayTraversal($nums)
{
$count = 0;
// 循环次数与数组长度成正比
foreach ($nums as $num) {
$count++;
}
return $count;
}
/* 平方阶 */
function quadratic($n)
{
$count = 0;
// 循环次数与数据大小 n 成平方关系
for ($i = 0; $i < $n; $i++) {
for ($j = 0; $j < $n; $j++) {
$count++;
}
}
return $count;
}
/* 平方阶(冒泡排序) */
function bubbleSort($nums)
{
$count = 0; // 计数器
// 外循环:未排序区间为 [0, i]
for ($i = count($nums) - 1; $i > 0; $i--) {
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for ($j = 0; $j < $i; $j++) {
if ($nums[$j] > $nums[$j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
$tmp = $nums[$j];
$nums[$j] = $nums[$j + 1];
$nums[$j + 1] = $tmp;
$count += 3; // 元素交换包含 3 个单元操作
}
}
}
return $count;
}
/* 指数阶(循环实现) */
function exponential($n)
{
$count = 0;
$base = 1;
// 细胞每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1)
for ($i = 0; $i < $n; $i++) {
for ($j = 0; $j < $base; $j++) {
$count++;
}
$base *= 2;
}
// count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1
return $count;
}
/* 指数阶(递归实现) */
function expRecur($n)
{
if ($n === 1) {
return 1;
}
return expRecur($n - 1) + expRecur($n - 1) + 1;
}
/* 对数阶(循环实现) */
function logarithmic($n)
{
$count = 0;
while ($n > 1) {
$n = $n / 2;
$count++;
}
return $count;
}
/* 对数阶(递归实现) */
function logRecur($n)
{
if ($n <= 1) {
return 0;
}
return logRecur($n / 2) + 1;
}
/* 线性对数阶 */
function linearLogRecur($n)
{
if ($n <= 1) {
return 1;
}
$count = linearLogRecur($n / 2) + linearLogRecur($n / 2);
for ($i = 0; $i < $n; $i++) {
$count++;
}
return $count;
}
/* 阶乘阶(递归实现) */
function factorialRecur($n)
{
if ($n === 0) {
return 1;
}
$count = 0;
// 从 1 个分裂出 n 个
for ($i = 0; $i < $n; $i++) {
$count += factorialRecur($n - 1);
}
return $count;
}
/* Driver Code */
// 可以修改 n 运行,体会一下各种复杂度的操作数量变化趋势
$n = 8;
echo "输入数据大小 n = {$n}" . PHP_EOL;
$count = timeConstant($n);
echo "常数阶的操作数量 = {$count}" . PHP_EOL;
$count = linear($n);
echo "线性阶的操作数量 = {$count}" . PHP_EOL;
$count = arrayTraversal(array_fill(0, $n, 0));
echo "线性阶(遍历数组)的操作数量 = {$count}" . PHP_EOL;
$count = quadratic($n);
echo "平方阶的操作数量 = {$count}" . PHP_EOL;
$nums = [];
for ($i = 0; $i < $n; $i++) {
$nums[$i] = $n - $i; // [n,n-1,...,2,1]
}
$count = bubbleSort($nums);
echo "平方阶(冒泡排序)的操作数量 = {$count}" . PHP_EOL;
$count = exponential($n);
echo "指数阶(循环实现)的操作数量 = {$count}" . PHP_EOL;
$count = expRecur($n);
echo "指数阶(递归实现)的操作数量 = {$count}" . PHP_EOL;
$count = logarithmic($n);
echo "对数阶(循环实现)的操作数量 = {$count}" . PHP_EOL;
$count = logRecur($n);
echo "对数阶(递归实现)的操作数量 = {$count}" . PHP_EOL;
$count = linearLogRecur($n);
echo "线性对数阶(递归实现)的操作数量 = {$count}" . PHP_EOL;
$count = factorialRecur($n);
echo "阶乘阶(递归实现)的操作数量 = {$count}" . PHP_EOL;

View File

@ -0,0 +1,42 @@
<?php
/**
* File: worst_best_time_complexity.php
* Created Time: 2024-05-19
* Author: DoWake (admin@mengxing.cc)
*/
/* 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 */
function randomNumbers($n)
{
$nums = [];
// 生成数组 nums = { 1, 2, 3, ..., n }
for ($i = 0; $i < $n; $i++) {
$nums[$i] = $i + 1;
}
// 随机打乱数组元素
shuffle($nums);
return $nums;
}
/* 查找数组 nums 中数字 1 所在索引 */
function findOne($nums)
{
foreach ($nums as $key => $value) {
// 当元素 1 在数组头部时,达到最佳时间复杂度 O(1)
// 当元素 1 在数组尾部时,达到最差时间复杂度 O(n)
if ($value === 1) {
return $key;
}
}
return -1;
}
/* Driver Code */
for ($i = 0; $i < 10; $i++) {
$n = 100;
$nums = randomNumbers($n);
$index = findOne($nums);
echo "\n数组 [ 1, 2, ..., n ] 被打乱后 = [" . join(', ', $nums) . "]" . PHP_EOL;
echo "数字 1 的索引为 {$index}" . PHP_EOL;
}