20172301 《程序設計與數據結構》第一周學習總結
20172301 《程序設計與數據結構》第一周學習總結
教材學習總結
第一章
- 軟件的質量特征
- 正確性:軟件能否有效處理問題
- 可靠性:軟件發生故障的頻率
- 健壯性:軟件修復錯誤以及bug出現的頻率
- 可用性:軟件處理問題效率
- 可維護性:代碼的整潔規範是否有利於維護
- 可重用性:使用已有的組件來減少開發工作量
- 可移植性:能在不同開發環境下能順利運行
- 運行效率:提高軟件運行效率,優化CPU時間和內存
數據結構
數據結構是計算機存儲、組織數據的方式。算法效率
算法效率是指算法執行的時間,算法執行時間需通過依據該 算法編制的程序在計算機上運行時所消耗的時間來度量。
第二章
- 增長函數:表示問題(n)大小與我們希望最優化的值之間的關系。
- 算法復雜度: 時間復雜度是指執行算法所需要的計算工作量;
而空間復雜度是指執行這個算法所需要的內存空間。
(算法的復雜性體現在運行該算法時的計算機所需資源的多少上,計算機資源最重要的是時間和空間(即寄存器)資源,因此復雜度分為時間和空間復雜度) - 漸進復雜度稱為算法的階次。
- 大O記法:常用大O表示法表示時間復雜性,註意它是某一個算法的時間復雜性。大O表示只是說有上界,由定義如果f(n)=O(n),那顯然成立f(n)=O(n^2),它給你一個上界,但並不是上確界,但人們在表示的時候一般都習慣表示前者。此外,一個問題本身也有它的復雜性,如果某個算法的復雜性到達了這個問題復雜性的下界,那就稱這樣的算法是最佳算法。
教材學習中的問題和解決過程
- 問題1:散列表是何?
- 問題解決:
哈希表(Hash table,也叫散列表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表。
記錄的存儲位置=f(關鍵字)
這裏的對應關系f稱為散列函數,又稱為哈希(Hash函數),采用散列技術將記錄存儲在一塊連續的存儲空間中,這塊連續存儲空間稱為散列表或哈希表(Hash table)。- 哈希表hashtable(key,value) 就是把Key通過一個固定的算法函數既所謂的哈希函數轉換成一個整型數字,然後就將該數字對數組長度進行取余,取余結果就當作數組的下標,將value存儲在以該數字為下標的數組空間裏。(或者:把任意長度的輸入(又叫做預映射,pre-image),通過散列算法,變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間通常遠小於輸入的空間,不同的輸入可能會散列成相同的輸出,而不可能從散列值來唯一的確定輸入值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數。)
數組的特點是:尋址容易,插入和刪除困難;
而鏈表的特點是:尋址困難,插入和刪除容易。
那麽我們能不能綜合兩者的特性,做出一種尋址容易,插入刪除也容易的數據結構?答案是肯定的,這就是我們要提起的哈希表,哈希表有多種不同的實現方法,我接下來解釋的是最常用的一種方法——拉鏈法,我們可以理解為“鏈表的數組”,如圖:
左邊很明顯是個數組,數組的每個成員包括一個指針,指向一個鏈表的頭,當然這個鏈表可能為空,也可能元素很多。我們根據元素的一些特征把元素分配到不同的鏈表中去,也是根據這些特征,找到正確的鏈表,再從鏈表中找出這個元素。
- Hash Table的查詢速度非常的快,幾乎是O(1)的時間復雜度。
- hash就是找到一種數據內容和數據存放地址之間的映射關系。
- 散列法:元素特征轉變為數組下標的方法。
散列表的查找步驟
當存儲記錄時,通過散列函數計算出記錄的散列地址
當查找記錄時,我們通過同樣的是散列函數計算記錄的散列地址,並按此散列地址訪問該記錄- 散列沖突:不同的關鍵字經過散列函數的計算得到了相同的散列地址。
好的散列函數=計算簡單+分布均勻(計算得到的散列地址分布均勻)
哈希表是種數據結構,它可以提供快速的插入操作和查找操作。 優缺點
優點:不論哈希表中有多少數據,查找、插入、刪除(有時包括刪除)只需要接近常量的時間即0(1)的時間級。實際上,這只需要幾條機器指令。
哈希表運算得非常快,在計算機程序中,如果需要在一秒種內查找上千條記錄通常使用哈希表(例如拼寫檢查器)哈希表的速度明顯比樹快,樹的操作通常需要O(N)的時間級。哈希表不僅速度快,編程實現也相對容易。
如果不需要有序遍歷數據,並且可以提前預測數據量的大小。那麽哈希表在速度和易用性方面是無與倫比的。
缺點:它是基於數組的,數組創建後難於擴展,某些哈希表被基本填滿時,性能下降得非常嚴重,所以程序員必須要清楚表中將要存儲多少數據(或者準備好定期地把數據轉移到更大的哈希表中,這是個費時的過程)。
- 問題2:軟件工程和程序設計關系?
問題解決:軟件工程包含程序設計,已經不單單是局限於編寫代碼,而是應該考慮程序的簡潔性,實用性。簡單來說,軟件工程考慮的要更加全面具體。
- 問題3:漸進復雜度與時間復雜度異同?
問題解決:一個是時間復雜度,一個是漸近時間復雜度。前者是某個算法的時間耗費,它是該算法所求解問題規模n的函數,而後者是指當問題規模趨向無窮大時,該算法時間復雜度的數量級。
當我們評價一個算法的時間性能時,主要標準就是算法的漸近時間復雜度,因此,在算法分析時,往往對兩者不予區分,經常是將漸近時間復雜度T(n)=O(f(n))簡稱為時間復雜度
其中的f(n)一般是算法中頻度最大的語句頻度。語句頻度是一個算法中的語句執行次數。
沒有循環的一段程序的復雜度是常數,一層循環的復雜度是O(n),兩層循環的復雜度是O(n^2)- 問題4:問題3中的語句頻度是什麽?
問題解決:
語句頻度和數據結構中時間復雜度的區別。
1)時間頻度一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個算法都上機測試,只需知道哪個算法花費的時間多,哪個算法花費的時間少就可以了。並且一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱為語句頻度或時間頻度。記為T(n)。
(2)時間復雜度在剛才提到的時間頻度中,n稱為問題的規模,當n不斷變化時,時間頻度T(n)也會不斷變化。但有時我們想知道它變化時呈現什麽規律。為此,我們引入時間復雜度概念。一般情況下,算法中基本操作重復執行的次數是問題規模n的某個函數,用T(n)表示,若有某個輔助函數f(n),使得當n趨近於無窮大時,T(n)/f(n)的極限值為不等於零的常數,則稱f(n)是T(n)的同數量級函數。記作T(n)=O(f(n)),稱O(f(n)) 為算法的漸進時間復雜度,簡稱時間復雜度。在各種不同算法中,若算法中語句執行次數為一個常數,則時間復雜度為O(1),另外,在時間頻度不相同時,時間復雜度有可能相同,如T(n)=n^2+3n+4與T(n)=4n^2+2n-1它們的頻度不同,但時間復雜度相同,都為O(n2)。
按數量級遞增排列,常見的時間復雜度有:常數階O(1),對數階O(log2n),線性階O(n),線性對數階O(nlog2n),平方階O(n2),立方階O(n3),...,k次方階O(nk),指數階O(2n)。隨著問題規模n的不斷增大,上述時間復雜度不斷增大,算法的執行效率越低。
復雜度關系
c < log2N < n < n * Log2N < n^2 < n^3 < 2^n < 3^n < n!- 問題5:在一個長度為n的順序表的表尾插入一個新元素的漸進時間復雜度為?
問題解決:答案是0(1),
因為是在表尾插入的,順序表讀取表尾元素是個常量級操作,插入操作無需移動因此也是個常量級操作。
課後習題
- EX2.1 下列增長函數的階次是多少?
a.10n^2+100n+1000
n^2
b.10n^3-7
n^3
c.2^n+100n^3
2^n
d.n^2 ·log(n)
n^2 ·log(n) - EX2.4 請確定下面代碼段的增長函數和階次
for(int count = 0 ; count < n ; count++)
for(int count2 = 0 ; count2 < n ; count2 = count2 + 2)
{
System.out.println(count,count2);
}
}
由題,內層循環是n/2,外層循環是n,所以增長函數f(n) = n^2 /2,所以階次是O(n^2)。
- EX 2.5 請確定下面代碼段的增長函數和階次
for(int count = 0 ; count < n ; count++)
for(int count2 = 0 ; count2 < n ; count2 = count2 * 2)
{
System.out.println(count,count2);
}
}
由題,內層循環是log2n,外層循環是n,所以增長函數是nlog2n,所以階次是O(nlog2n)。
參考資料
- 何謂語句的頻度?
- 數據結構頻度
- 哈希表(散列表)原理詳解
20172301 《程序設計與數據結構》第一周學習總結