C++從入門開始講算法(1)

以下內容來自於洛谷網站

本文章僅是講一個目錄,細節會在之後的文章中出現

大家請拿起手中的紙和筆,認真做筆記!

1.順序結構

千里之行,始於足下。程序設計雖然花樣繁多,但還是要從最簡單的地方開始學習,由淺入深,直至掌握。畢竟任何複雜的工程代碼都是由一行行簡單的代碼組成的。

我們編寫計算機程序,將一個任務分解成一條一條的語句,計算機會按照順序一條一條的執行這些語句,這就是順序結構程序設計。

2.分支結構

人們在人生中需要做出許多選擇,小到考慮晚上吃什麼,大到決定高考志願填報的學校。只有一次次選擇後才能帶來無限可能,我們要根據自己掌握的情況,做出最佳的選擇。

程序的執行也不是一成不變的,往往會要求程序能夠在不同的場合下有不同的動作。這時就需要在代碼中使用條件語句來做出不同的選擇。比如說,登錄洛谷網時,網站後臺會將你提交的用戶名和密碼在後臺數據庫中看看是否匹配,如果能夠匹配就登陸成功,否則就登陸失敗。這一章就來介紹如何讓程序做出選擇。

3.循環結構

雖然計算機可以在短時間批量處理成千上萬條指令,但是不少問題中有許多規律性的重複操作,比如說計算幾百個學生的平均分,或者對上萬人的名單進行排序。僅使用順序或者分支結構,對每一步操作都寫出對應的語句是不可能的;但可以使用循環語句讓計算機反覆執行類似的任務。

本章將會介紹循環結構程序設計,同時前面的內容也會進一步的鞏固。學完這一章,讀者可以初步感受到計算機高效解決問題的能力。

4.數組

計算機運算速度很快,一秒鐘可以處理成千上萬的數據。之前的例子都是讀取一個數據後立刻對這些數據進行處理,然後再也不需要用到這些數據了;有時候,我們讀入數據後還需要將這些數據保存下來,便於以後再次使用。如果保存個別幾個數據,可以設立幾個變量存儲;但是如果要存儲成千上萬個數據,總不能定義成千上萬個變量吧。

既然可以通過循環語句來重複執行結構類似的語句,也有辦法一次定義一組成千上萬個的相同類型的變量——使用數組。這樣就可以把大量的數據存儲下來,隨時使用了。數組不僅可以存儲輸入的數據,還能存下運算過程中的“半成品”甚至答案,是 C++ 中非常重要的一部分。

5.字符串

計算機並不僅僅能夠處理數學問題,還可以用來處理文字,比如寫文章、處理代碼、記錄信息等等……如果需要將各種語句記錄在計算機中,就要用到字符串或者字符數組。

我們已經在最開始的地方嘗試輸出過"I love Luogu" 的字符串,也介紹過單個字符和數字對應的 ASCII 編碼。在這一章會介紹字符串的存儲和處理的方法。同時也初步接觸了 STL,這使得可以“站在前人的肩膀上”完成程序,簡化編程的難度。

6.函數與結構體

有時程序中會使用多次相同的語句,而且無法通過循環來減少重複編程。對於這樣的功能,如果能像使用 sqrt()、max() 這樣變成一個函數,那該多好啊!其實每個程序都用到了主函數——main()。除此之外,還可以自己定義其他函數,並將參數餵給這些函數,使其能夠根據這些參數完成要求的任務。不過這方面還有更復雜的一些知識點,比如參數傳遞與變量的作用域,接下來也需要學習。函數內還能調用自己,也就是遞歸函數,這是程序設計新手入門公認的第一道坎,但卻是非常重要的一部分。

最後介紹了結構體,可以建立並操作對象。存儲一些和對象有關的信息會變得相當便利。例如,可以設計結構體來存儲一位同學的各項信息——姓名、年齡、性別、考試成績等等,而一個確定的同學就是一個對象。可以很方便地操作一個對象,也可以用數組批量存儲對象。

7.排序

在生活中我們經常需要對一些東西排序。比如考試評卷後老師會要求你按照成績高低將試卷排序,玩撲克牌時要按點數排序手牌,在洛谷刷題將題庫按照難度排序然後簡單題刷起(友情提示:長期只刷簡單題不會有長進的)。多虧了排序過程,可以將無序的雜亂無章的東西整理清楚,便於查詢統計和利用。

8.高精度算法與模擬

各位讀者有聽說過“建模”一詞嗎?所謂“建模”,就是把事物進行抽象,根據實際問題來建立對應的數學模型。“抽象”並不意味着晦澀難懂;相反,它提供了大量的便利。計算機很難直接去解決實際問題,但是如果把實際問題建模成數學問題,就會大大地方便計算機來“理解”和“解決”。

舉個生活中常見的例子:我們拿到了某次數學考試的成績單,現在需要知道誰考得最好。當然不能把成績單對着電腦晃一晃,然後問“誰考得最好?”。需要通過一種途徑讓計算機來理解這個問題。這個問題可以建模成:“給定數組score[],問數組內元素的最大值”。這樣建模後,就能很方便的寫程序解決問題了。對於這個問題,採用之前討論過的“擂臺法”,就可以給出答案。

如何把實際問題建模成數學問題,主要依靠我們的經驗和直覺、當然還有你靈動的思維;而算法與數據結構,正是解決數學問題的兩把利劍。從這一章開始會介紹一些程序設計競賽中的一些常見套路算法,而下一部分會介紹基礎的數據結構。如果已經認真學習完了第一部分,相信這一部分也不在話下。

這一章是語言部分的延伸,會介紹一些競賽中會出現的“模擬題目”——這裏的“模擬”不是指模擬某場比賽的模擬題,而是指讓程序完整的按照題目敘述的方式執行運行得到最終答案。同時也會介紹可以計算很大整數的高精度運算方法。這一章對思維與算法設計的要求不高,但是會考驗編程的基本功是否紮實。

9暴力枚舉

設想一下,你覺得家門口的山非常礙事,下決心發揚“愚公移山”精神,憑藉一鎬一擔打算把山一點一點的移走。雖然精神值得褒獎,而且理論上是可行的,只要給予足夠多的時間遲早能做到。但是,實際上並不可能給你那麼多時間,所以使用這種辦法在有生之年是不可能將山移開的(也許你可以使用更好的辦法,比如使用魔法或者設法讓天神感動,讓他幫你移山)。然而,如果你只是把一個不到半人高的小沙堆給移走,那使用這種方法很快就可以完成了。

算法的世界高深莫測,但是很多問題的解決方法簡單而粗暴——就是枚舉出所有可能的情況,然後判斷或者統計,從而解決問題。在很多程序設計比賽中,有許多比較簡單的題目是可以通過枚舉暴力解決的;而有的更有具有挑戰性的題目雖然有更巧妙的解法,但依然可以使用枚舉暴力完成部分任務。

本章將介紹一些枚舉與暴力策略,這是非常基礎而且重要的,但是對初學者來說還是會有一些挑戰。請務必理解本章之前的所有章節後再開始本章的學習。

10 遞歸遞推

有些目標是宏大的,比如要在 IOI 賽場中得到滿分(俗稱 AK IOI)。如果你現在還是一個普通的學生,那麼想達成這個目標太難了。但把這樣宏大的目標分解爲很多個子任務,就沒覺得那麼複雜了。

要想 AK IOI,只需要入選國家隊,參加 IOI 即可。那怎麼成爲入選國家隊呢?參加中國隊選拔賽並通過面試答辯即可。使用同樣的思路往前倒推,直到最後只剩下最基礎的任務(比如認真的讀完這章內容並完成練習),做完這樣的小任務就很簡單了。

像這樣將一個很大的任務分解成規模小一些的子任務,子任務分成更小的子任務,直到遇到初始條件,最後整理歸納解決大任務的思想就是遞推與遞歸思想,不過這兩者還是有一些區別。

這一章涉及的內容是動態規劃思想與分治策略的基礎,大家也要認真學習啦,說不定目標就真的達到了。

11.貪心

如果你想在算法競賽中得獎,就要儘可能多讀書、多思考、多練習。去完成儘可能多數量與種類的算法題目積累知識和經驗,在考場上放平心態,就可以達到目標。但因爲花了太多時間在編程上而極度壓縮休息的時間,反而會效率低下,得不償失。很多時候太貪婪不是一件好事,因爲目光短淺,沒有考慮到後面的事情,結果沒有辦法保證最後的結果做到最好。

在算法競賽中求解某些問題時,只需要做出在當前看來是最好的選擇就能獲得最好的結果,而不需要考慮整體上的最優,即使目關短淺也是沒有關係的。本章就介紹這樣的貪心策略。

12.二分

大家還知道怎麼在一本很厚的詞典查找一個單詞嗎?字典中的單詞是按照“字典序”進行排序的,比如 code<pan<pancake 。如果我們要找一個單詞,就要將字典從中間翻開,然後將這面單詞跟想要找的單詞比較。如果這面單詞在需要尋找的單詞之前,就將字典往後翻,否則就往前翻,直到找到準確的單詞爲止。

大家可以發現,越接近需要查詢的單詞,翻動書面的頁數就越少。你肯定不會從第一頁開始一面一面翻,逐個查看每個單詞是否就是自己想要查的單詞,這樣做就太慢了。雖然實際情況不是那麼精確,但是基本上使用了“二分思想”。

如果序列是有序的,就可以通過二分查找快速定位所需要的數據。除此之外,二分思想還能求出可行解的最值問題,比如想知道某款手機最高能多少樓高度摔下來而不會摔壞,使用二分的方式可以用最小實驗次數就能得到結果(當然你需要準備好幾個樣品)。

13。搜索

我們在之前的章節介紹了暴力枚舉策略,將所有可能的情況都枚舉一遍以獲得最優解,但是枚舉全部元素的效率如同愚翁移山,無法應付數據範圍稍大的情形。本章在暴力枚舉的基礎上介紹了搜索算法,包括深度優先搜索和廣度優先搜索,從起點開始,逐漸擴大尋找範圍,直到找到需要的答案爲止。

嚴格來說,搜索算法也算是一種暴力枚舉策略,但是其算法特性決定了效率比直接的枚舉所有答案要高,因爲搜索可以跳過一些無效狀態,降低問題規模。在算法競賽中,如果選手無法找到一種高效求解的方法(比如貪心、遞推、動態規劃、公式推導等),使用搜索也可以解決一些規模較小的情況;而有的任務就是必須使用搜索來完成,因此這是相當重要的策略。

14.線性表

我們之前已經研究過很多算法了!比如,二分法可以用來“給定單調函數,求零點”;冒泡排序可以用來“給定一個數組,將其排序後輸出”……你已經知道算法很有用,接下來要學習的數據結構,也一樣很有用!初學數據結構,您可能會覺得無從下手;不過不用擔心,本書會用很多生活中實際存在的例子來解釋這些數據結構。

比如,在商場裏面排隊結賬,或者在網上“秒殺”商品,差別很大;但它們都遵循着相同的規則——講“先來後到”。早來的,就早買到商品;晚來的,就晚買到商品,甚至可能買不到商品。可以利用“先來後到”這一規則,把這兩種排隊模式統一起來——它們都是“隊列”,都可以用隊列這一數據結構來模擬。然後建模,編寫計算機程序解決這些問題。

這一章,先開始學習線性表。線性表是最簡單、最基本的一種數據結構,一個線性表示多個具有相同類型數據“串在一起”,每個元素有前驅(前一個元素)後繼(後一個元素)。根據不同的特性,線性表也分爲棧、隊列、鏈表等等。因爲這些特性,數據結構可以解決不同種類的問題。

15.二叉樹

我們之前介紹了線性表這一類數據結構,並且學習瞭如何使用線性表解決一類特定的問題(數據具有明顯的前後關係,可以進行線性連接)。本章將介紹一類新的數據結構——二叉樹。

看看窗外的橡樹吧。一般來說,樹有一個粗壯的樹幹,再往上面樹幹就會分成兩叉或者多叉,接着樹枝會繼續一直分下去,一直分到末端的葉子爲止(不過也有可能是花或者果子)。

如想統計一棵蘋果樹上面有多少蘋果,只需要知道樹杈左邊的蘋果數量和樹杈右邊的蘋果數量,然後計算它們的和就行了。至於樹杈左邊有多少個蘋果?可以使用一樣的方法來統計,把這個分枝當作樹幹,然後統計這個樹幹的左分杈和右分杈的蘋果數量和……直到統計到樹枝末端每一個蘋果,然後依次彙總就可以得到蘋果的數量 。

很明顯,樹形結構不僅能表示數據間的指向關係,還能表示出數據的層次關係,而有很明顯的遞歸性質。因此,我們可以利用樹的性質解決更多種類的問題。

16.集合

有時候,我們並不關心數據之間的前後關係,也不關心數據的層次關係。一些確定元素只是單純的聚集在一起,這樣的元素聚集體被稱爲集合。

當希望知道某個數據是否存在一個集合中,或者兩個元素是否在同一個集合中時,就需要使用一些集合數據結構來維護集合元素之間的關係。

17.圖的基本應用

我們已經學過一些簡單的數據結構,例如線性表和二叉樹。現在,需要學習一種新的數據結構——圖。雖然相比於前面講過的數據結構,圖會複雜一些,但是依然能用很多生活中存在的例子來解釋圖這種數據結構。

比如,現在新同學站在校園的正門口,手裏拿着校園地圖。可以從地圖上看到有很多建築物。複雜的路網四通八達,連接着這些建築物。如果希望偷個懶,走最近的道路到達目的地,或者是希望制定一種方案,參觀完學校內的每一種建築物,都可以使用“圖”這一數據結構來模擬。通過建模,編寫計算機程序,就可以解決這類問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章