使用堆疊和佇列的正確姿勢(附案例)
透過堆疊和佇列的學習,我們似乎會感覺到其實資料結構還是很簡單的嘛。當然,這只是一個開始,我們從順序表、鍊錶開始,到現在的堆疊和佇列,其實都是為了將來在鋪路。在樹和圖的遍歷演算法中,都可以見到棧和佇列的身影。在這裡,我們先簡單的看看堆疊和佇列的一些實際應用。
回文題
假設有一段文字,我們要判斷它是不是「回文」(不是回族兄弟的文字)。就可以應用堆疊來解決這個問題。
回文指的就是將這段文字一分為二之後,前面一段內容和後面一段內容是完全相同的,但是順序是相反的。例如非常出名的:上海自來水來自海上。上海自來,來自海上,這樣的兩段結構在一句話裡就構成了一段回文。又例如雙數長度的一段字元:abcddcba,這也是一段回文。
類似的這種題目其實很容易出現在一些簡單的演算法面試題中,相信也有不少小夥伴已經看出端倪了,我們可以將前半段入棧,然後再一個一個的出棧與後半段進行比對就可以判斷目前的字串是否是回文了。別光說不練,我們就上程式碼來實現。
$string1 = 'abcdedcba'; $string2 = 'abcdeedcba'; $string3 = 'abcdefcba'; function getIsPlalindrome($string) { if (gettype($string) != 'string') { return false; } $strlen = strlen($string); $mid = floor($strlen / 2); $arr = []; if ($strlen < 2) { return false; } // 入栈 for ($i = 0; $i < $mid; $i++) { array_push($arr, $string[$i]); } $j = $mid; $i = $strlen % 2 == 0 ? $mid : $mid + 1; // $i 从中位数开始 for (; $i < $strlen; $i++) { $v = $arr[$j - 1]; // 获得栈顶元素 if ($v != $string[$i]) { return false; } array_pop($arr); // 弹出栈顶元素 $j--; } if ($arr) { return false; } return true; } var_dump(getIsPlalindrome($string1)); // bool(true) var_dump(getIsPlalindrome($string2)); // bool(true) var_dump(getIsPlalindrome($string3)); // bool(false)
很簡單吧,就是使用 array_push() 和 array_pop() 來進行的順序堆疊的操作而已。唯一要注意的就是對於字元長度奇偶數的不同,我們要取的中位數也會對應的要改變。
回文演算法還是比較簡單的,另外還常會出現的像是簡單的括號匹配、算式運算、中綴轉後綴表達式這類的題目都是棧的典型演算法面試題。大家可以自行尋找相關的內容來嘗試嘗試。
遞迴
在講遞歸前,我們要弄清楚一件事情,那就是:程式語言中的函數呼叫本質上就是堆疊的呼叫。
怎麼理解這句話呢?當我們執行程式碼時,如果遇到一個函數,總是會先進入到這個函數中,運行完這個函數中的程式碼之後才會再回到原來的程式碼執行線中繼續執行呼叫目前這個函數的程式碼。比如下面這段程式碼。
function testA() { echo 'A start.', PHP_EOL; testB(); echo 'A end.', PHP_EOL; } function testB() { echo 'B start.', PHP_EOL; echo 'B end.', PHP_EOL; } echo 'P start.', PHP_EOL; testA(); echo 'P end.', PHP_EOL; // P start. // A start. // B start. // B end. // A end. // P end.
目前頁面 P ,在執行到 testA() 函數時,就進入了 testA() 函數內部執行其內部的程式碼,也就是 P -> A 。然後 testA() 函數又呼叫了 testB() 函數,那麼現在就進入了 testB() 中並執行該函數體內的程式碼,也就是 P -> A -> B 。當 testB() 的程式碼運行完成後,回到 testA() 繼續執行 testA() 函數體裡面的內容,最後回到頁面 P 繼續往下執行,也就是 B -> A -> P 。
上面這段描述如果一次沒看明白的話,請再多看幾次,細細品。這不就是一個棧的呼叫過程嘛! !
這麼一看,在程式語言中,堆疊還真是深入骨髓般的存在。因為你只要是在開發程式碼,那你一定就是在運用棧這個東西了。而“遞歸”,則是棧的更典型的實現。
function recursion($n) { if ($n == 0 || $n == 1) { return 1; } $result = recursion($n - 1) * $n; return $result; } echo recursion(10), PHP_EOL;
這是一段簡單的階乘演算法的遞歸實現,由於遞歸會建立一個棧,所以我們這段程式碼最先計算出來的是的棧底的n 是1,出棧返回1 之後,再出棧時就是用1 乘以2 ,再繼續出棧就是2 乘以3 ,依次類推,直到計算出從1 到10 的階乘結果。
遞迴相關的面試題也是我們在面試中非常常見的內容,所以我們一定要把握好遞歸其實就是堆疊的一種表現形式,然後運用堆疊的思想來解構整個遞歸的呼叫過程。
隊列應用程式
最後,我們再講講隊列的一些實際應用。隊列在程式碼層面其實並沒有太多很好的範例,比較常見的可能有兩個隊列合併出隊(舞伴問題)或者兩組隊列一起出隊,一邊出兩個另一個才能出一個之類的這種問題。大家可以自行找相關的題目。相對來說,隊列的演算法題在面試題中還是比較少的,包括在考研的時候也多是以選擇判斷之類的題目出現的。不過,在實際應用中,隊列現在卻是解決高並發問題的超級法寶,也是面試官判斷你經驗的重要內容。
在實際的專案開發中,佇列最典型的功能就是秒殺問題。就像搶火車票或搶小米手機一樣,在整點的時候,大量的請求湧入,如果僅依靠伺服器來處理,超高的並發量不僅會帶給伺服器巨大壓力,而且還有可能出現各種高並發場景下才會出現的問題,例如超賣、事務異常等。 (多個執行緒同時更新資料)
而队列,正是解决这个问题的一把好手。通常我们会使用的队列系统(redis、rabbitmq)都是以内存为主的队列系统,它们的特点就是存储非常快。由前端(生产者)生成的大量请求都存入队列中(入队),然后在后台脚本(消费者)中进行处理(出队)。前端只需要返回一个正在处理中,或者正在排队的提示即可,然后后台处理完成后,通知前台显示结果。这样,在一个秒杀场景中基本上就算是解决了高并发的问题了。当然,现实环境可能还需要考虑更多因素,但核心都是以队列的方式来解决这种瞬间高并发的业务功能。
另外,队列还有一个重要的业务场景,那就是通知、消息、邮件、短信之类的这种信息发送。因为队列的所能解决的一些问题的最大特点就是需要生产者/消费者的业务解耦。通常我们在群发消息时都会批量进行大规模的发送,这时就只需要准备好消息内容和对应的手机号、设备id,就可以让系统在后台队列中慢慢进行消息发送了,而不需要我们的前端一直等待消息全部发送完成。
这时,不少小伙伴又看出了一点点门道了。队列这货在实际应用中,就是多线程的感觉呀,JS 中的事件回调,CPU 的碎片时间轮询可不就是一种队列的真实应用嘛。还有设计模式中的“观察者模式”,本身就是事件回调这种机制的一种编程范式,所以,用它来实现的很多功能中,我们都能看到队列的影子。
总结
看看,一个栈,一个队列,竟然都是我们在开发过程中天天要接触的东西。是不是感觉自己的脑容量不够用了?仔细再想想,还有哪些东西和我们的栈、队列有关呢?其实只要把握住它们的两个本质就可以了:栈是后进先出(LIFO)或者说是先进后出(FILO),而队列是先进先出(FIFO)。
测试代码:
https://github.com/zhangyue0503/Data-structure-and-algorithm/blob/master/3.栈和队列/source/3.3栈和队列的应用.php
推荐学习:php视频教程
以上是使用堆疊和佇列的正確姿勢(附案例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。
