① C語言作業:結構體編程練習 在屏幕上模擬顯示一個數字式時鍾 源代碼能給我的話+50,感謝
#include <stdio.h>
struct clock {
int hour;
int minute;
int second;
};
typedef struct clock CLOCK;
/*
函數功能:時、分、秒時間的更新
函數參數:無
函數返回值:無
*/
void Update(CLOCK *myclock) {
myclock->second++;
if (myclock->second == 60) { /*若second值為60,表示已過1分鍾,則 minute值加1*/
myclock->second = 0;
myclock->minute++;
}
if (myclock->minute == 60){ /*若minute值為60,表示已過1小時,則 hour值加1*/
myclock->minute = 0;
myclock->hour++;
}
if (myclock->hour == 24) { /*若hour值為24,則hour的值從0開始計時*/
myclock->hour = 0;
}
}
/*
函數功能:時、分、秒時間的顯示
函數參數:無
函數返回值:無
*/
void Display(CLOCK *myclock) { /*用回車符'\r'控制時、分、秒顯示的位置*/
printf("%2d:%2d:%2d\r", myclock->hour, myclock->minute, myclock->second);
}
/*
函數功能:模擬延遲1秒的時間
函數參數:無
函數返回值:無
*/
void Delay(void) {
long t;
for (t = 0; t < 290000000; t++) {
/*循環體為空語句的循環,起延時作用*/
}
}
int main(){
CLOCK myclock;
long i;
myclock.hour = myclock.minute = myclock.second = 0; /*hour,minute,second賦初值0*/
for (i = 0; i < 100000; i++) { /*利用循環結構,控制時鍾運行的時間*/
Update(&myclock); /*時鍾更新*/
Display(&myclock); /*時間顯示*/
Delay(); /*模擬延時1秒*/
}
return 0;
}
② 誰能告訴我如何用計算機編程的語言比如1和0表示出1到10的數字
本文字數:4894 字
閱讀本文大概需要:13 分鍾
寫在之前
我們都知道,對於同一個問題來說,可以有多種解決問題的演算法。盡管演算法不是唯一的,但是對於問題本身來說相對好的演算法還是存在的,這里可能有人會問區分好壞的標準是什麼?這個要從「時效」和「存儲」兩方面來看。
人總是貪婪的,在做一件事的時候,我們總是期望著可以付出最少的時間、精力或者金錢來獲得最大的回報,這個類比到演算法上也同樣適用,那就是花最少的時間和最少的存儲做成最棒的解決辦法,所以好的演算法應該具備時效高和存儲低的特點。這里的「時效」是指時間效率,也就是演算法的執行時間,對於同一個問題的多種不同解決演算法,執行時間越短的演算法效率越高,越長的效率越低;「存儲」是指演算法在執行的時候需要的存儲空間,主要是指演算法程序運行的時候所佔用的內存空間。
時間復雜度
首先我們先來說時間效率的這個問題,這里的時間效率就是指的演算法的執行時間,時間的快慢本來就是一個相對的概念,那麼到了演算法上,我們該用怎樣的度量指標去度量一個演算法的時間效率(執行時間)呢?
剛開始我們想出了一種事後統計方法,我稱它為「馬後炮式」,顧名思義,就是對於要解決的某個問題,費盡心思想了 n 種解法,提前寫好演算法程序,然後攢了一堆數據,讓它們分別在電腦上跑,跑完瞭然後比較程序的運行時間,根據這個來判斷演算法時效的高低。這種的判斷技術計算的是我們日常所用的時間,但這並不是一個對我們來說有用的度量指標,因為它還依賴於運行的機器、所用的編程語言、編譯器等等等等。相反,我們需要的是一個不依賴於所用機器或者編程語言的度量指標,這種度量指標可以幫助我們判斷演算法的優劣,並且可以用來比較演算法的具體實現。
我們的科學家前輩們發現當我們試圖去用執行時間作為獨立於具體程序或計算機的度量指標去描述一個演算法的時候,確定這個演算法所需要的步驟數目非常重要。如果我們把演算法程序中的每一步看作是一個基本的計量單位,那麼一個演算法的執行時間就可以看作是解決一個問題所需要的總步驟數。但是由於演算法的執行過程又各不相同,所以這個每一步,即這個基本的計量單位怎麼去選擇又是一個令人頭禿的問題。
下面我們來看一個簡單的求和的函數:
defget_sum(n): sum = 0for i in range(1,n+1): sum += i return sumprint(get_sum(10))
我們仔細去分析一下上述代碼,其實可以發現統計執行求和的賦值語句的次數可能是一個好的基本計數單位,在上面 get_sum 函數中,賦值語句的數量是 1 (sum = 0)加上 n (執行 sum += i 的次數)。
我們一般用一個叫 T 的函數來表示賦值語句的總數量,比如上面的例子可以表示成 T(n) = n + 1。這里的 n 一般指的是「數據的規模大小」,所以前面的等式可以理解為「解決一個規模大小為 n,對應 n+1 步操作步數的問題,所需的時間為 T(n)」。
對於 n 來說,它可以取 10,100,1000 或者其它更大的數,我們都知道求解大規模的問題所需的時間比求解小規模要多一些,那麼我們接下來的目標就很明確了,那就是「尋找程序的運行時間是如何隨著問題規模的變化而變化」。
我們的科學家前輩們又對這種分析方法進行了更為深遠的思考,他們發現有限的操作次數對於 T(n) 的影響,並不如某些占據主要地位的操作部分重要,換句話說就是「當數據的規模越來越大時,T(n) 函數中的某一部分掩蓋了其它部分對函數的影響」。最終,這個起主導作用的部分用來對函數進行比較,所以接下來就是我們所熟知的大 O閃亮登場的時間了。
大 O 表示法
「數量級」函數用來描述當規模 n 增加時,T(n) 函數中增長最快的部分,這個數量級函數我們一般用「大 O」表示,記做 O(f(n))。它提供了計算過程中實際步數的近似值,函數 f(n) 是原始函數 T(n) 中主導部分的簡化表示。
在上面的求和函數的那個例子中,T(n) = n + 1,當 n 增大時,常數 1 對於最後的結果來說越來不越沒存在感,如果我們需要 T(n) 的近似值的話,我們要做的就是把 1 給忽略掉,直接認為 T(n) 的運行時間就是 O(n)。這里你一定要搞明白,這里不是說 1 對 T(n) 不重要,而是當 n 增到很大時,丟掉 1 所得到的近似值同樣很精確。
再舉個例子,比如有一個演算法的 T(n) = 2n^2+ 2n + 1000,當 n 為 10 或者 20 的時候,常數 1000 看起來對 T(n) 起著決定性的作用。但是當 n 為 1000 或者 10000 或者更大呢?n^2 起到了主要的作用。實際上,當 n 非常大時,後面兩項對於最終的結果來說已經是無足輕重了。與上面求和函數的例子很相似,當 n 越來越大的時候,我們就可以忽略其它項,只關注用 2n^2 來代表 T(n) 的近似值。同樣的是,系數 2 的作用也會隨著 n 的增大,作用變得越來越小,從而也可以忽略。我們這時候就會說 T(n) 的數量級 f(n) = n^2,即 O(n^2)。
最好情況、最壞情況和平均情況
盡管前面的兩個例子中沒有體現,但是我們還是應該注意到有時候演算法的運行時間還取決於「具體數據」而不僅僅是「問題的規模大小」。對於這樣的演算法,我們把它們的執行情況分為「最優情況」、「最壞情況」和「平均情況」。
某個特定的數據集能讓演算法的執行情況極好,這就是最「最好情況」,而另一個不同的數據會讓演算法的執行情況變得極差,這就是「最壞情況」。不過在大多數情況下,演算法的執行情況都介於這兩種極端情況之間,也就是「平均情況」。因此一定要理解好不同情況之間的差別,不要被極端情況給帶了節奏。
對於「最優情況」,沒有什麼大的價值,因為它沒有提供什麼有用信息,反應的只是最樂觀最理想的情況,沒有參考價值。「平均情況」是對演算法的一個全面評價,因為它完整全面的反映了這個演算法的性質,但從另一方面來說,這種衡量並沒有什麼保證,並不是每個運算都能在這種情況內完成。而對於「最壞情況」,它提供了一種保證,這個保證運行時間將不會再壞了,**所以一般我們所算的時間復雜度是最壞情況下的時間復雜度**,這和我們平時做事要考慮到最壞的情況是一個道理。
在我們之後的演算法學習過程中,會遇到各種各樣的數量級函數,下面我給大家列舉幾種常見的數量級函數:
為了確定這些函數哪些在 T(n) 中佔主導地位,就要在 n 增大時對它們進行比較,請看下圖(圖片來自於 Google 圖片):
在上圖中,我們可以看到當 n 很小時,函數之間不易區分,很難說誰處於主導地位,但是當 n 增大時,我們就能看到很明顯的區別,誰是老大一目瞭然:
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n)
我們下面就來分析幾個上述所說的「數量級函數」:
1.常數函數
n = 100 # 1 次sum = (1 + n) *n / 2 # 1 次print(sum) # 1 次
上述演算法程序的 f(n) = 3,可能有人看到這會說那麼時間復雜度就是 O(f(n)) = O(3),其實這個是錯的,這個函數的時間復雜度其實是 O(1)。這個對於初學者來說是很難理解的一種結果,其實你可以把 sum = (1 + n) * n / 2 多復制幾次再來看:
a = 100 # 1 次sum = (1 + n) * n / 2 # 1 次sum = (1 + n) * n / 2 # 1 次sum = (1 + n) * n / 2 # 1 次sum = (1 + n) * n / 2 # 1 次sum = (1 + n) * n / 2 # 1 次sum = (1 + n) * n / 2 # 1 次print(sum) # 1 次
上述演算法的 f(n) = 8,事實上你可以發現無論 n 為多少,上述兩段代碼就是 運行 3 次和運行 8 次的區別。這種與數據的規模大小 n 無關,執行時間恆定的演算法我們就叫它具有 O(1) 的時間復雜度。不管這個常數是多少,我們都記作是 O(1),而不是 O(3) 或者是 O(8)。
2.對數函數
cnt = 1while cnt < n: cnt *= 2 # O(1)
上面的演算法程序的時間復雜度就是 O(logn),這個是怎麼算出來的呢?其實很簡單:上述的代碼可以解釋成 cnt 乘以多少個 2 以後才能大於等於 n,我們假設個數是 x,也就是求 2^x = n,即 x = log2n,所以這個循環的時間復雜度就是 O(logn)。
最後呢,我們來看看下面的這個例子,藉助這段代碼來詳細的說一下我們如何對其時間復雜度進行詳細的分析:
a = 1b = 2c = 3for i inrange(n):for j inrange(n): x = i * i y = j * j z = i * jfor k inrange(n): u = a * k + b v = c * cd = 4
上面的代碼沒有任何意義,甚至不是一個可運行的代碼,我只是用來說明你在以後如何對代碼進行執行分析,關於代碼本身可不可以運行,就不需要你在這關心了。
上面的代碼其實我們要分的話可以分成 4 部分:第 1 部分是 a,b,c 這 3 個賦值語句,執行次數也就是 3 次;第二部分是 3n^2,因為是循環結構,裡面有 x,y,z 這 3 個賦值語句,每個語句執行了 n^2 次;第 3 部分是 2n,因為裡面是 2 個賦值語句,每條語句被執行了 n 次;最後第 4 部分是常數 1,只有 d 這么 1 條賦值語句。所以我們得到的 T(n
) = 3+3n^2 +2n+1 = 3n^2+2n+4,看到指數項,我們自然的發現是 n^2 做主導,當 n 增大時,後面兩項可以忽略掉,所以這個代碼片段的數量級就是 O(n^2)。
空間復雜度
類比於時間復雜度的討論,一個演算法的空間復雜度是指該演算法所耗費的存儲空間,計算公式計作:S(n) = O(f(n))。其中 n 也為數據的規模,f(n) 在這里指的是 n 所佔存儲空間的函數。
一般情況下,我們的程序在機器上運行時,刨去需要存儲程序本身的輸入數據等之外,還需要存儲對數據操作的「存儲單元」。如果輸入數據所佔空間和演算法無關,只取決於問題本身,那麼只需要分析演算法在實現過程中所佔的「輔助單元」即可。如果所需的輔助單元是個常數,那麼空間復雜度就是 O(1)。
空間復雜度其實在這里更多的是說一下這個概念,因為當今硬體的存儲量級比較大,一般不會為了稍微減少一點兒空間復雜度而大動干戈,更多的是去想怎麼優化演算法的時間復雜度。所以我們在日常寫代碼的時候就衍生出了用「空間換時間」的做法,並且成為常態。比如我們在求解斐波那契數列數列的時候我們可以直接用公式去遞歸求,用哪個求哪個,同樣也可以先把很多結果都算出來保存起來,然後用到哪個直接調用,這就是典型的用空間換時間的做法,但是你說這兩種具體哪個好,偉大的馬克思告訴我們「具體問題具體分析」。
寫在之後
如果上面的文章你仔細看了的話,你會發現我不是直接上來就告訴你怎麼去求時間復雜度,而是從問題的產生,到思考解決的辦法,到「馬後炮」,再到 T(n),最後到 O(n)一步一步來的。這樣做的原因呢有兩個:一是為了讓你了解大 O 到底是怎麼來的,有時候搞明白了由來,對於你接下來的學習和理解有很大的幫助;二是為了讓這個文章看起來不是那麼枯燥,我覺得很多時候上來扔給你一堆概念術語,很容易就讓人在剛看到它的時候就打起了退堂鼓,循序漸進的來,慢慢引導著更容易接受一些。
很多人從大學到工作,代碼寫了不少依然不會估算時間復雜度,我感覺倒不是學不會,而是內心沒有重視起來。你可能覺得計算機的更新換代很快,CPU 處理速度的能力越來越棒,沒必要在一些小的方面斤斤計較,其實我覺得你是 too young too naive。我們隨便來算一個簡單的例子:有兩台電腦,你的電腦的運算速度是我的電腦的 100 倍,同樣一道問題,明明稍微想一想用 O(n) 可以做出來,你偏偏要懶,直接暴力 O(n^2),那麼當 n 的數據稍微增大一些,比如上萬上十萬,到底誰的運算速度快還用我再告訴你嗎?
所以今後在寫演算法的時候,請好好學會用時間復雜度估算一下自己的代碼,然後想想有沒有更有效率的方法去改進它,你只要這樣做了,相信慢慢的你的代碼會寫的越來越好,頭會越來越禿。(逃
最後說一點的是,估算演算法的復雜度這件事你不要指望一下子看了一篇文章就想弄懂,這個還是要有意識的多練,比如看到一個程序的時候有意識的估算一下它的復雜度,准備動手寫代碼的時候也想想有沒有更好的優化方法,有意識的練習慢慢就會來了感覺。這篇文章我就用了幾個小例子,大概的估算方式就是這樣。之後我還會繼續寫一些關於「數據結構與演算法」相關的文章和一些具體的實戰題目,都會帶大家繼續分析它們的時間復雜度,敬請期待。
③ 數學編程是什麼意思啊
「數學編程」指數學領域的編程,或者為解決實際的數學問題而進行的編程。另外,數學是基礎學科,有豐富的數學基礎可以對理解編程中的邏輯有幫助。
編程是編定程序的中文簡稱,就是讓計算機代碼解決某個問題,對某個計算體系規定一定的運算方式,使計算體系按照該計算方式運行,並最終得到相應結果的過程。
為了使計算機能夠理解人的意圖,人類就必須將需解決的問題的思路、方法和手段通過計算機能夠理解的形式告訴計算機,使得計算機能夠根據人的指令一步一步去工作,完成某種特定的任務。這種人和計算體系之間交流的過程就是編程。
執行原理:
將高級程序設計語言編寫的源程序轉換到機器目標程序的方式有兩種:解釋方式和編譯方式。
1、解釋方式下,計算機對高級語言書寫的源程序一邊解釋一邊執行,不能形成目標文件和執行文件。
2、編譯方式下,首先通過一個對應於所用程序設計語言的編譯程序對源程序進行處理,經過對源程序的詞法分析、語法分析、語意分析、代碼生成和代碼優化等階段將所處理的源程序轉換為用二進制代碼表示的目標程序。
然後通過連接程序處理將程序中所用的函數調用、系統功能調用等嵌入到目標程序中,構成一個可以連續執行的二進制執行文件。調用這個執行文件就可以實現程序員在對應源程序文件中所指定的相應功能。
以上內容參考:網路-編程
④ 何為數字編程
估計你說的是fpga或者是cpld吧
FPGA是英文Field Programmable Gate Array的縮寫,即現場可編程門陣列,它是在PAL、GAL、EPLD等可編程器件的基礎上進一步發展的產物。它是作為專用集成電路(ASIC)領域中的一種半定製電路而出現的,既解決了定製電路的不足,又克服了原有可編程器件門電路數有限的缺點。
FPGA採用了邏輯單元陣列LCA(Logic Cell Array)這樣一個新概念,內部包括可配置邏輯模塊CLB(Configurable Logic Block)、輸出輸入模塊IOB(Input Output Block)和內部連線(Interconnect)三個部分。FPGA的基本特點主要有:
1)採用FPGA設計ASIC電路,用戶不需要投片生產,就能得到合用的晶元。 ——2)FPGA可做其它全定製或半定製ASIC電路的中試樣片。
3)FPGA內部有豐富的觸發器和I/O引腳。
4)FPGA是ASIC電路中設計周期最短、開發費用最低、風險最小的器件之一。
5)FPGA採用高速CHMOS工藝,功耗低,可以與CMOS、TTL電平兼容。
可以說,FPGA晶元是小批量系統提高系統集成度、可靠性的最佳選擇之一。
目前FPGA的品種很多,有XILINX的XC系列、TI公司的TPC系列、ALTERA公司的FIEX系列等。
FPGA是由存放在片內RAM中的程序來設置其工作狀態的,因此,工作時需要對片內的RAM進行編程。用戶可以根據不同的配置模式,採用不同的編程方式。
加電時,FPGA晶元將EPROM中數據讀入片內編程RAM中,配置完成後,FPGA進入工作狀態。掉電後,FPGA恢復成白片,內部邏輯關系消失,因此,FPGA能夠反復使用。FPGA的編程無須專用的FPGA編程器,只須用通用的EPROM、PROM編程器即可。當需要修改FPGA功能時,只需換一片EPROM即可。這樣,同一片FPGA,不同的編程數據,可以產生不同的電路功能。因此,FPGA的使用非常靈活。
FPGA有多種配置模式:並行主模式為一片FPGA加一片EPROM的方式;主從模式可以支持一片PROM編程多片FPGA;串列模式可以採用串列PROM編程FPGA;外設模式可以將FPGA作為微處理器的外設,由微處理器對其編程。