【算法】學習筆記(0):算法初探(邏輯抽象 + 示例 + 代碼實現)

什么是算法?

人生皆算法,算法的本質,是解決問題的方法,遇到問題,尋找答案,解決問題,是作為一個人,一生都在做的事情。

算法是人類思維的產物,是解決問題的方案,并且,它能夠映射到計算機世界去實現,完成一些人類不擅長的事情,比如大量重復的計算。

算法很有魅力,它很特別,但是并不神秘,我們時時刻刻都在運用著算法背后的“解決問題”的思想去生活,去過著每一天。

用計算機思維去思考問題

算法是普通的,也是特別的,它是人類使用計算機思維思考的產物,能夠讓人類更加充分地利用計算機這個人類發明的工具,這也是信息時代特有的產物。

既然是計算機思維,當然有其特點:
在這里插入圖片描述概念不重要,理解即可,不必記憶,不必急于掌握,直接看實例體會。

“玩具”問題

計數:判斷一個byte(無符號整數)里面有多少個bit的值是1

算法一

很簡單的想法,將十進制數轉換為一位一位的二進制,然后看看是不是1就好了,就是簡單的數數

// method 1
int cal_1(unsigned char number) {unsigned char count = 0;while (number != 0){int div = number % 2;if (div == 1) {count++;}number /= 2;}return count;
}

算法二

上面是我們解決問題的第一種想法。

下面我們加一種假設,假如內存空間足夠大,且使用函數次數足夠多,我們是不是可以提高算法的效率?

要知道,1字節大小的無符號整數,一共28 = 256種,如果我們連續10000次調用函數,每一次都使用除二取余法(算法1),就大量重復計算了,這個時候不妨提前算好把結果存起來,然后直接訪問結果(就像緩存、cache那樣的思想)。

也就是所謂的打表查表

// 計數:判斷一個byte(無符號整數)里面有多少個bit的值是1
#include <iostream>
using namespace std;int num_table[256] = { 0 };// method 1
int cal_1(unsigned char number) {unsigned char count = 0;while (number != 0){int div = number % 2;if (div == 1) {count++;}number /= 2;}return count;
}// method 2
int cal_2(unsigned char number) {return num_table[number];
}int main(){// 存儲答案for (unsigned char i = 0; i < 255; i++) {num_table[(int)i] = cal_1(i);}// 直接訪問cout << cal_2(15);return 0;
}

我們開始使用算法1,存儲了一張,之后再需要使用的時候,就能夠直接查表得結果,而不需要再重復計算了,如果調用100000萬次,效率將會比算法1顯著提高。

當然……由于數據量對計算機來說太小了還是,測試不出很大的差異其實。

如果規模更大,會有顯著效果。

算法三

對于算法一

  • 省空間,因為沒占用多少數據段
    對于算法二
  • 省時間,因為提前儲存好了答案,只需要訪問數組就可以

對于前面兩種算法,是根據不同需求不同情況取使用的,但是涉及到了算法設計考慮的兩個維度:時間和空間

算法一省空間,費時間,算法二省時間廢空間,那么能不能兼得?

其實這種

不走極端取中間的兼得思想

在計算機中經常需要用到。

我們需要既省時間又省空間的算法。

與cache類似的設計思想

我們可以使用哈希表,采取如下策略

  • 如果表中有值,那就直接取
  • 如果沒有,就去計算,并且存表中

這樣一來,做到了拿走需要的,保存需要的,同時考慮了時間和空間兩方面的因素。

我們使用unordered_map完成這件事:

// 計數:判斷一個byte(無符號整數)里面有多少個bit的值是1
#include <iostream>
#include <unordered_map>
using namespace std;typedef std::unordered_map<unsigned char, int> result_map;// method three
int cal_3(unsigned char number, result_map &map) {result_map::iterator count = map.find(number);if (count != map.end()) // 在無序映射表中{cout << "在表中  ";return	count->second;}else  // 不在表中{cout << "不在表中  ";int result = cal_1(number);map.insert(result_map::value_type(number,result));	// 插入鍵值對return result;}}int main(){result_map map;cout << cal_3(15, map) << endl;	// 不在表中  4cout << cal_3(15, map) << endl; // 在表中    4cout << cal_3(10, map) << endl; // 不在表中  2cout << cal_3(10, map) << endl; // 在表中    2return 0;
}

這樣,通過無序映射表,我們就完成了既節省時間,又節省空間的目的。

小結

我們來回顧一下。

對于這個問題

  1. 我們看到了問題,理解了問題
  2. 拆解問題,變成自己熟悉的
  3. 解決問題,創建解決問題的過程方案
  4. 設計解決流程,將其代碼實現
  5. 根據實際情況,優化解決方案
  6. 綜合考慮算法的時間空間兩個維度的指標

我們通過這個超級簡單的例子,初步了解了算法的基本情況,我們繼續往下進行。

連續子序列和

在這里插入圖片描述
讓我們體會一下不同的算法,不同的解決方案,感受一下它們之間的時間和空間上的性能差異。

一件事情,往往都是很多種解決方案,并且都能到達彼岸,但是過程不一樣,走過的路不同,花的時間也不同,算法的時空性能也是一樣的。

充分體會: 計算機世界是人類世界的二進制映射,與人類生活息息相關。

算法1:三層循環

  1. 取某個首位置i
  2. i后的某個位置j
  3. 計算[i,j]數值的和,與最大值比較,更新最大值

這是一種最樸素的思想了,我們看圖。
在這里插入圖片描述因此,我們需要

for(int i = 0; i < char_size; i++){for(int j = i; j < char_size; j++){1. 求和2. 更新maxValue}
}

代碼如下:

#include <iostream>
#include <vector>
using namespace std;int max_subsequence_sum(const vector<int> &a) {int max_sum = 0;for (int i = 0; i < a.size(); i++) {for (int j = i; j < a.size(); j++) {int current_sum = 0;for (int k = i; k <= j; k++)current_sum += a[k];if (current_sum > max_sum)max_sum = current_sum;}}return max_sum;
}int main()
{vector<int> a = { 1,3,-1,2 };cout << max_subsequence_sum(a);return 0;
}

但是,毫無疑問,三重循環,時間消耗過多了,我們得看看能不能優化。
在這里插入圖片描述將三重循環轉換為遞歸。

代碼暫不寫

算法2:兩層循環

在這里插入圖片描述

算法3:一層循環

在這里插入圖片描述

算法4:遞歸

在這里插入圖片描述

算法比較

在這里插入圖片描述

小結

之所以沒有談及后面的代碼,因為對于初學者來說比較復雜,看看就行了,充分體會的是同一個問題,達成同一個目的的情況下,不同算法的差異巨大,這也是算法魅力所在。

致謝

感謝北交大算法MOOC!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384649.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384649.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384649.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Verilog】數據流建模傳輸問題:賦值傳輸有方向

這次&#xff0c;我們說明的是&#xff0c;assign語句實現的數據流建模&#xff0c;包含的是兩個層面 建立聯系傳輸方向 assign A B的本質含義是 A與B建立關聯B的值傳給A 這個傳輸方向至關重要&#xff0c;實際情況是什么&#xff0c;就必須按照順序進行&#xff0c;不是單…

【計算機系統設計】實踐筆記(2)數據通路構建:第一類R型指令分析(2)

待辦事項 時鐘頻率高&#xff0c;取指周期長&#xff0c;遠大于執行周期&#xff0c;如何處理&#xff1f; 不可綜合邏輯的處理 接上一篇 【計算機系統設計】實踐筆記&#xff08;2&#xff09;數據通路構建&#xff1a;第一類R型指令分析&#xff08;1&#xff09; 8.2 ALU運…

【計算機系統設計】實踐筆記(2)插敘:綜合與實現

接上一篇文章的第10節 之前完成了功能仿真&#xff0c;下面我們進行綜合實現。 10.1.1 綜合 綜合成功。 實現試試 這真是令人悲傷……找Bug吧。 我們看看綜合后的門級網表。 發現綜合后的并不是我們想要的……看了看可能是綜合的目錄錯誤&#xff0c;我們再試試。 不是這…

【電路原理】學習筆記(1):電路模型的基本變量

上一講說到了電路模型&#xff0c;這一電路的抽象&#xff0c;現在我們看看它的基本組成。 1 電流 1.1 概念 對于一根管道&#xff0c;它能夠流通電荷&#xff0c;定向移動就形成了電流。 單位時間t內&#xff0c;&#xff0c;某一橫截面&#xff0c;穿過電荷量是q&#xf…

【電路原理】學習筆記(0):電路與電路模型

東北大學電路原理MOOC 電路原理的核心點&#xff1a;研究電路模型 我們實際看見的&#xff0c;是真實電路 我們高中學的&#xff0c;是電原理圖 現在&#xff0c;我們要研究的是電路模型&#xff0c;它是實際電路的抽象模型&#xff0c;并且是理想化的。 對于電路模型&#…

【計算機系統設計】實踐筆記(3)改進數據通路:移位R型指令分析

0 回顧 前面的內容中&#xff0c;第一類R型指令分析&#xff0c;我們完成了一類R型指令的設計&#xff0c;完成了其數據通路&#xff0c;構建了相應的部件&#xff0c;并且完成了從ROM中取指&#xff0c;成功進行了基本的功能仿真&#xff0c;進行了綜合和實現&#xff0c;但是…

【計算機系統設計】實踐筆記(3)改進數據通路:jr指令分析與實現

1 jr指令分析 instructionoprsrtrdshamtfuncjr000000rs000000000000000001000 舉例&#xff1a;jr $31 功能&#xff1a;PC <- &#xff08;$31&#xff09; 這是個跳轉指令&#xff0c;將指定寄存器的值&#xff0c;放入PC中&#xff0c;是無條件跳轉。 我們需要 更新P…

【計算機系統設計】實踐筆記(4)改進數據通路:第一類I型指令分析與實現

0 回顧 之前&#xff0c;我們完成了17條R型指令的設計&#xff0c;接下來&#xff0c;我們逐步完成I型指令的設計。 1 核心思想&#xff1a;增量思維 & 復用思維 & 學會選擇 & 分治思想 增量思維 我們從無到有&#xff0c;構建了支持R型指令的CPU&#xff0c;接…

【算法】學習筆記(1):算法就是人類去教會計算機的方法

人生處處皆算法&#xff0c;算法是解決問題之道。 對于計算機科學中的算法&#xff0c;我更喜歡將其理解為利用人類思維之一&#xff1a;計算機思維&#xff0c;去解決一些人類不擅長的問題&#xff0c;比如大量重復運算&#xff0c;然后&#xff0c;人類使用計算機編程語言去…

【算法】學習筆記(2):遞歸思想

0 回顧 之前的筆記&#xff08;0&#xff09;和筆記&#xff08;1&#xff09;&#xff0c;我們介紹了算法的基本含義&#xff0c;并且舉了一些實例&#xff0c;同時理解了&#xff0c;算法就是人類在教計算機做事情&#xff01; 我們知道&#xff0c;算法就是解決問題的方案…

【計算機系統設計】實踐筆記(5)插敘:內外有別之CPU和Memory

區分CPU的內外 首先明確&#xff0c;內存&#xff0c;不在CPU內&#xff0c;我們的CPU是會有數據和指令端口的&#xff0c;然后去訪問內存和外設。 而CPU設計&#xff0c;我們所說的單周期&#xff0c;多周期和流水線&#xff0c;描述的都是CPU&#xff0c;而不是Memory&…

【計算機系統設計】實踐筆記(5)改進數據通路:beq和bne指令分析與實現

接下來的分析和實踐非常粗糙&#xff0c;因為跟之前一樣的分析流程&#xff0c;不再多說了&#xff0c;如果前面真的掌握&#xff0c;這里不看也罷。 分析 先看beq指令。 ALU輸入的是rs和rt&#xff0c;不輸入imm&#xff0c;進行subu操作&#xff0c;判斷是否為zero&#x…

【算法】學習筆記(4):分治思想 歸并排序

分治思想&#xff0c;分治策略&#xff0c;自古有之&#xff0c;與人類生活息息相關&#xff0c;其本質是將大問題拆解為小問題&#xff0c;小問題轉換為已知解的問題&#xff0c;進而求解。 軍隊管理&#xff0c;國家分級治理…… 大規模數據排序&#xff0c;例如10000000000…

【算法】學習筆記(5):快速排序

注意一個C的坑 sizeof()這個函數靜態數組可以求長度&#xff0c;動態new出來的數組不行&#xff0c;因為針對的是指針……&#xff0c;不過既然的動態數組了&#xff0c;其長度本身必然是一個變量了&#xff0c;你沒有必要這么求長度。 下面看快速排序的代碼。 #include <…

【計算機系統設計】實踐筆記(6)改進數據通路:lw和sw指令

不想多說了……前面的鋪墊足夠了&#xff0c;剩下的自己做做應該也會了&#xff0c;如果遇到問題&#xff0c;就搜一下自己查閱就好。 這篇水過&#xff0c;沒有太多技術點。 唯一注意的是&#xff0c;引入的RAM和ROM的clk觸發問題&#xff0c;可能引起時序問題&#xff0c;等…

html css 核心設計理念

分開看&#xff01; 從不同視角&#xff0c;獨立地去看某一部分內容&#xff0c;使用聚焦視角&#xff0c;進行獨立操作和批量操作。

html css 學習筆記(1)背景相關

背景顏色 圖片 插入圖片img背景圖片 背景圖片 3. logo 4. 大圖 5. 裝飾性小圖 便于控制位置&#xff01; 插入后會執行自動平鋪&#xff0c;這與插入圖片是不同的&#xff01; div{width: 600px;height: 300px;background-image: url(img/登錄用戶頭像.png); }小結 盒子的第…

html css a標簽的應用

作為普通鏈接轉換為行內塊元素 轉換為行內塊元素之后&#xff0c;就可以給其各種塊行為&#xff0c;加背景&#xff0c;加背景圖片&#xff0c;設置寬高&#xff0c;內外邊距…… 塊行為可以的&#xff0c;它都行&#xff0c;唯一的區別&#xff0c;它這個盒子是個鏈接&#…

GitHub回滾

不要直接退回到很久前的歷史版本&#xff0c;這很可能引起文件沖突&#xff0c;可以一步步回滾&#xff0c;先回滾最近的&#xff0c;從近到遠一步步滾到目標。

2020-12-15 CPU設計復盤

SOC修改 將之前完成的31條指令單周期CPU進行了重構&#xff0c;將其分開&#xff0c;實現了內外有別&#xff0c;將CPU、指令ROM和數據RAM。 這樣&#xff0c;以后為其增加接口外設&#xff0c;總線控制&#xff0c;才更加清晰&#xff0c;這是進一步封裝和抽象。 MARS大坑 …