常見演算法
什麼是演算法
演算法是解決某個實際問題的過程和方法。
排序演算法
氣泡排序
每次都從陣列中找出最大值放到陣列的後面去。
虛擬碼(升序排序):
輸入:未排序的陣列arr,陣列長度length
輸出:無輸出,陣列arr原地實現排序
1 for (i = 0; i < length - 1; i++)
2 for (j = 0; j < length - i - 1; j++)
3 if (arr[i] > arr[j])
4 swap(arr[i], arr[i + 1])
5 end if
6 end for
7 end for
選擇排序
每輪選擇當前位置,來找出後面的較小值與該位置交換。
虛擬碼(升序排序):
輸入:未排序的陣列arr,陣列長度length
輸出:無輸出,陣列arr原地實現排序
1 for (i = 0; i < length - 1; i++)
2 for (j = i + 1; j < length - 1; j++)
3 if (arr[i] > arr[j])
4 swap(arr[i], arr[j])
5 end if
6 end for
7 end for
查詢演算法
基本查詢/順序查詢
遍歷陣列,依次比較。
在資料量特別大時,基本查詢效能很差。
二分查詢/折半查詢
- 將陣列排序。
- 二分法查詢。
虛擬碼:
輸入:帶查詢陣列arr,陣列長度length,待查詢值data
輸出:待查詢值的索引index,若陣列中沒有待查詢值,則輸出None
1 left = 0, right = length - 1
2 while (left <= right)
3 middle = floor((left + right) / 2)
4 if (data < arr[middle])
5 left = middle - 1
6 else if (data > arr[middle])
7 right = middle + 1
8 else
9 return middle
10 end if
11 end while
12 return None
正規表示式
正規表示式概述
正規表示式是什麼
正規表示式是由一些特定的字元組成的,代表的是一個規則。
正規表示式的作用
- 用來校驗資料格式是否合法。
- 在一段文字中查詢滿足要求的內容。
- 在一段文字中搜尋替換、分割內容。
String提供的與正規表示式相關的方法
方法名 | 說明 |
---|---|
public boolean matches(String regex) | 判斷字串是否匹配正規表示式,匹配返回true,不匹配返回false |
public String replaceAll(String regex , String newStr) | 按照正規表示式匹配的內容進行替換 |
public String[] split(String regex) | 按照正規表示式匹配的內容進行分割字串,反回一個字串陣列。 |
正規表示式的書寫規則
字元類(只匹配單個字元):
正規表示式 | 含義 |
---|---|
[abc] | 只能是a, b, 或c |
[^abc] | 除了a, b, c之外的任何字元 |
[a-zA-Z] | a到z A到Z,包括(範圍) |
[a-d[m-p]] | a到d,或m到p |
[a-z&&[def]] | d, e, 或f(交集) |
[a-z&&[^bc]] | a到z,除了b和c(等同於[ad-z]) |
[a-z&&[^m-p]] | a到z,除了m到p(等同於[a-lq-z]) |
預定義字元(只匹配單個字元):
正規表示式 | 含義 |
---|---|
. | 任何字元 |
\d | 一個數字: [0-9] |
\D | 非數字: [^0-9] |
\s | 一個空白字元:[ \t\n\x0B\f\r] |
\S | 非空白字元: [^\s] |
\w | [a-zA-Z_0-9] |
\W | 一個非單詞、非數字、非下劃線字元:[^\w] |
數量詞:
正規表示式 | 含義 |
---|---|
X? | 匹配X,一次或0次 |
X* | 匹配X,0次或多次 |
X+ | 匹配X,一次或多次 |
X | 匹配X,正好n次 |
X | 匹配X,至少n次 |
X | 匹配X,n次到m次,包括n次和m次 |
其他:
正規表示式 | 含義 |
---|---|
[] | 裡面的內容出現一次 |
^ | 取反 |
&& | 交集,不能寫單個的& |
() | 分組 |
| | 寫在方括號外面表示並集 |
(?i) | 忽略後面字元的大小寫 |
\ | 跳脫字元 |
注意:\\.代表對.的轉義
補充:(任意字元)\\1
代表分組編號,應用如下:
String str = "我我我喜歡編編編編編編編編程式設計程程";
String s = str.replaceAll("(.)\\1+", "$1");
System.out.println(s);
輸出為:
我喜歡程式設計
異常
認識異常
異常就是程式出現的問題。
異常的體系
- Error:代表的系統級別錯誤(屬於嚴重問題),也就是說系統一旦出現問題,sun公司會把這些問題封裝成Error物件給出來。開發過程中一般不會用到。
- Exception:異常,它代表的是我們程式可能出現的問題,所以,我們通常會用Exception以及它的子類來封裝程式出現的問題。
- 執行時異常:RuntimeException及其子類,編譯階段不會出現錯誤提醒,但執行時出現的異常。(如:陣列索引越界異常)
- 編譯時異常:編譯階段就會出現錯誤提醒的異常。(如:日期解析異常)
異常有什麼用
- 異常是用來查尋系統Bug的關鍵參考資訊。
- 異常可以作為方法內部的一種特殊返回值,以便通知上層呼叫者底層的執行情況。
自定義異常
Java無法為這個世界上全部的問題都提供異常類來代表, 如果開發者自己遇到了某種問題,想透過異常來表示,以便用異常來管理該問題,那就需要自己來定義異常類了。
自定義執行時異常
- 定義一個異常類繼承RuntimeException。
- 重寫構造器。
- 透過throw new 異常類(xxx)來建立異常物件並丟擲。
特點:編譯階段不報錯,提醒不強烈,執行時才可能出現。
自定義編譯時異常
- 定義一個異常類繼承Exception。
- 重寫構造器。
- 透過throw new 異常類(xxx)來建立異常物件並丟擲。
特點:編譯階段就報錯,提醒更加強烈。
throw和throws
- throw用在方法內,丟擲去這個異常物件。
- throws用在方法上,丟擲方法內部的異常。
異常的處理
程式碼層面的處理
丟擲異常(throws)
在方法上使用throws關鍵字,可以將方法內部出現的異常丟擲去給呼叫者處理。
方法 throws 異常1, 異常2, 異常3... {
...
}
// 推薦方式
方法 throws Exception {
...
}
// Exception代表可以捕獲一切異常
捕獲異常(try…catch)
直接捕獲程式出現的異常。
try{
// 監視可能出現異常的程式碼
} catch (異常型別1 變數) {
// 處理異常
} catch (異常型別2 變數) {
// 處理異常
}...
// 推薦方式
try{
// 可能出現異常的程式碼
} catch (Exception e) {
// 處理異常
}
// Exception代表可以捕獲一切異常
開發中對於異常的常見處理方法
下層方法將異常丟擲給呼叫者,逐層丟擲直到最外層方法,最外層方法有兩種處理方式:
- 捕獲異常,記錄異常並響應合適的資訊給使用者。
- 捕獲異常,嘗試重新修復。
- 丟擲異常時,都只丟擲Exception即可。
B D BCD C CD D C ABCD ABD