搜尋與排序 search and sort - csie.ntu.edu.twr95116/ca200/slide/c9_sortsearch.pdf ·...

30
講師:洪安 搜尋與排序 Search and Sort 1

Upload: others

Post on 17-Oct-2019

7 views

Category:

Documents


0 download

TRANSCRIPT

講師:洪安

搜尋與排序Search and Sort

1

排序與搜尋 搜尋

循序(線性)搜尋法(Linear Search)

二分搜尋法(Binary Search)

排序

氣泡排序法(Bubble Sort)

選擇排序法(Selection Sort)

插入排序法(Insertion Sort)

快速排序法(Quick Sort)

2

排序 簡介

將一群資料按照某一規則排列,使其具有遞增(減)的線性關係

分類與比較

執行效率

記憶體空間

穩定性

用途

資料搜尋

進階的分析與處理

5 1 4 2 3

sort

1 2 3 4 5

3

選擇排序法 Selection Sort 在一段資料中找出最大(小)值後,才做交換

範例程式碼(將資料由小排到大)

4

int i, j, tmp, min; int n[5] = {7,1,3,9,5}; // 欲排序的資料

for( i=0; i<4; i++) {min = i;for( j=i+1; j<=4; j++) // 找出最小值

if(n[ j] < n[min]) min = j;

// 把最小值跟第 i 個做交換if (min != i) {

tmp = n[i];n[i] = n[min];n[min] = tmp;

} }

7 1 3 9 5

i=0, j=2, min是1, n[1]=1

7 1 3 9 5

i=0, j=3 , min是1, n[1]=1

7 1 3 9 5

i=0, j=4 , min是1, n[1]=1

1 7 3 9 5

i=0, j=4 , 把min換到最前面

7 1 3 9 5

i=0, j=1, min是1, n[1]=1

1 7 3 9 5

i=1, j=2

1

1

1

1

1

7

min

已排好的 目前的

……

i=0, min是0, n[0]=7

操作範例

選擇排序法 Selection Sort

特點

當資料紀錄很大 (欄位數多) ,比較之鍵值是少量的,則適合Selection Sort 因為每個回合至多一次

交換動作

5

7 1 3 9 5

1 7 3 9 5

1 3 7 9 5

1 3 5 9 7

1 3 5 7 9

課堂練習 以下為一個動態的”選擇排序法”程式,請用迴圈

讓使用者輸入6次數字,然後將每次排序的結果輸出:

輸出輸入範例如下:

第一次輸入:9;輸出:9

第二次輸入:3;輸出:3 9

第三次輸入:7;輸出:3 7 9

第四次輸入:5;輸出:3 5 7 9

第五次輸入:9;輸出:3 5 7 9 9

第六次輸入:2;輸出:2 3 5 7 9 9

程式結束

6

Ans: 9_SelectionSort.cpp

插入排序法 Insertion Sort 將一段資料中最右(左)邊的資料當作key,然後往左(右)

塞入此資料中作排序 範例程式碼(將資料由小排到大)

7

int i, j, key; int n[5] = {7,1,3,9,5}; // 欲排序的資料

for( i=1; i<=4; i++) {key=n[i];for( j=i-1; j>=0 && n[ j]>key; j--)

n[ j+1] = n[ j];

n[ j+1] = key;}

1 7 3 9 5

i=2, j=1

1 3 7 9 5

i=2, j=0

1 3 7 9 5

i=3, j=2, 9比7大,不必排

1 3 7 9 5

i=4, j=3

7 1 3 9 5

i=1, j=0

1 3 5 7 9

i=4, j=1

已排好的 目前的

……

課堂練習 以下為一個動態的”插入排序法”程式,請用迴圈

讓使用者輸入6次數字,然後將每次排序的結果輸出:

輸出輸入範例如下:

第一次輸入:9;輸出:9

第二次輸入:3;輸出:3 9

第三次輸入:7;輸出:3 7 9

第四次輸入:5;輸出:3 5 7 9

第五次輸入:9;輸出:3 5 7 9 9

第六次輸入:2;輸出:2 3 5 7 9 9

程式結束

8

Ans: 9_InsertionSort.cpp

氣泡排序法 Bubble Sort

排序時,最大的元素會如同氣泡一樣移至右端

利用比較相鄰元素的方法,將大的元素交換至右端

口訣:小在前,大在後!

9

操作範例 (1/2)

10 7 13 5 1

比較10> 7 ,10和7對調

7 10 13 5 1

比較10<= 13 ,不做任何事

7 10 13 5 1

比較13>5 , 13和5對調

10

比較13> 1 ,13和1對掉

7 10 5 13 1

最後結果: 最大的數跑到最右邊了

7 10 5 1

比較7<=10 ,不做任何事

13

剩下4個數還未排序,重複剛才的動作,這次讓10跑到右邊

操作範例 (2/2)

7 10 5 1 13

11

完整操作範例• 10,7,13,5,1 由小到大排列

• Step1.1 10>7,於是兩者交換,陣列變成7,10,13,5,1

• Step1.2 10<13,於是沒有動作

• Step1.3 13>5,於是兩者交換,陣列變成7,10,5,13,1

• Step1.4 13>1,於是兩者交換,陣列變成7,10,5,1,13

• 到此為止,我們已經把最大的元素13移至最右端了,下一次只需檢查到陣列倒數第二個元素即可。

• Step2.1 7<10,於是沒有動作

• Step2.2 10>5,於是兩者交換,陣列變成7,5,10,1,13

• Step2.3 10>1,於是兩者交換,陣列變成7,5,1,10,13

• 第二大的元素10也就定位了。

• Step3.1 7>5,於是兩者交換,陣列變成5,7,1,10,13

• Step3.2 7>1,於是兩者交換,陣列變成5,1,7,10,13

• 第三大的元素7也就定位了。

• Step4.1 5>1,於是兩者交換,陣列變成1,5,7,10,13

• 完成。

12

課堂練習 請利用氣泡排序法程式片段,撰寫一個程式可以讓

使用者任意輸入5個數字,程式會輸出排序結果

13

課堂練習 請參考 9_bubblesort.cpp ,將其修改為使用樣板

(Template)的版本

14

Ans: 9_bubblesort_template.cpp

快速排序法 Quick Sort (1/4)

平均情況下執行時間最快的方法

採取 Divide and Conquer 策略

觀念1

每回合處理之後,pk會被放置正確位子

15

1 2 3 … n

Pivot Key

1 2 3 … n

Pivot Key比Pivot Key小 比Pivot Key大

Divide!

快速排序法 Quick Sort (2/4)

觀念2

分為左右半部後 各自做遞迴 quick sort

如何決定 pk 之正確位置?

作法

16

Conquer!

1 2 3 4 5 6 7 8 9 10

26 5 37 1 61 11 59 48 39 65

i : 找>=pk j : 找<=pk

i jj: 找到 11 <= 26i:找到37>=26

swap

快速排序法 Quick Sort (3/4)

資料結構與C++程式設計進階班17

1 2 3 4 5 6 7 8 9 10

26 5 11 1 61 37 59 48 39 65

j: 找到 1 <= 26

i:找到61>=26 i 和 j 擦身而過,所以pk正確位置應該是4

1 2 3 4 5 6 7 8 9 10

1 5 11 26 61 37 59 48 39 65

swap

快速排序法 Quick Sort (4/4)

演算法:

最好與平均情況

nlogn

最差情況

n2

發生在資料由小到大或由大到小的情況

資料結構與C++程式設計進階班18

i : 找>=pk

j : 找<=pk

sort左半邊

sort右半邊

排序法的比較 執行效率(Computational Complexity) 速度:排序一群資料所需的”比較”次數

例如:氣泡排序法排序 N 筆資料需比較次數為為 (N-1)x(N-2)/2

記憶體空間(Memory Usage) 排序一群資料所需要的記憶體空間

例如:快速排序法排序N筆資料通常需 logN 的額外記憶體空間

穩定性(Stability) 對於鍵值相同的資料其”原始順序”排序後能否被保留? If Yes:穩定

If No:不穩定

19

分類與比較一覽表 同樣排序 n 筆資料

Bubble Selection Insertion Quick

平均情形 O(n2) O(n2) O(n+d) O(nlogn)

最糟情形 O(n2) O(n2) O(n2) O(n2)

記憶體使用 O(1) O(1) O(1) O(logn)~O(n)

穩定性 Y Y Y N

備註d是相反資料(需交換)的

個數

20

排序與搜尋 搜尋

循序搜尋法(Linear Search)

二分搜尋法(Binary Search)

排序

氣泡排序法(Bubble Sort)

選擇排序法(Selection Sort)

插入排序法(Insertion Sort)

快速排序法(Quick Sort)

21

循序(線性)搜尋法 Linear Search 在一群資料中,從頭搜尋到尾直到找到資料為止

又稱 Sequential Search

範例程式碼int linearSearch(int key) {

int n[10] = {-2,0,1,2,3,4,6,7,9,14}, key=3; int found = -1;

for( i=0; i< 10; i++)if(n[i] == key) {

found=i; break;

}return found;

}22

• 實施之前,紀錄不需事先排序過• 可用隨機存取 (Array) 或循序存取 (Linked List) 方式支援

輸出1. 大 於 等 於 0

表示找到第i筆符合key值

2. 等於-1表示沒找到

二元搜尋法 Binary Search

在已排序的資料數列中尋找某一筆資料

須藉助隨機存取 (Array) 機制支援

在執行二元搜尋時的比較,可以分成三種情況,如下所示:

搜尋鍵值小於陣列的中間元素 鍵值在資料陣列的前半部

搜尋鍵值大於陣列的中間元素 鍵值在資料陣列的後半部

搜尋鍵值等於陣列的中間元素 找到搜尋的鍵值

23

小 → 大

中間元素

1 5 9 12 16Num

Num[0] Num[1] Num[2] Num[3] Num[4]

Up

Low

int SearchKey=7; //數字7在陣列裡的哪個位置 (0~4)

int Low=0,Up=4;

int Middle=(Up+Low)/2; // (0+4)/2 = 2

Middle

操作範例 (1/4)

24

1 5 9 12 16Num

Num[0] Num[1] Num[2] Num[3] Num[4]

Up

Low

//因為: 7不在Num[middle], 且7<9

//所以: 我們知道7如果在陣列裡的話,應該會在middle 的左邊

// => 把up移到middle-1的位置 Up=Middle-1;

//把Up移到新的位置後,計算新的middle

middle=(Up+Low)/2; // middle = (0+1)/2 =0

Middle

操作範例 (2/4)

25

1 5 9 12 16Num

Num[0] Num[1] Num[2] Num[3] Num[4]

Up

Low

//因為: 7 不在Num[middle], 且7>1

//所以: 我們知道7如果在陣列裡的話,應該會在middle 的右邊

// => 把Low移到middle+1的位置 Low=Middle+1;

//把Low移到新的位置後,計算新的middle

middle=(Up+Low)/2; // middle = (1+1)/2 =1

Middle

操作範例 (3/4)

26

1 5 9 12 16Num

Num[0] Num[1] Num[2] Num[3] Num[4]

Up

Low

//因為: 7 不在Num[middle], 且7>5

//所以: 我們知道7如果在陣列裡的話,應該會在middle 的右邊

// => 把Low移到middle+1的位置 Low=Middle+1;

//把Low移到新的位置後,發現Low > Up

//告知使用者7不在陣列裡

Middle

操作範例 (4/4)

27

程式範例// bool done;

// bool 這個資料型態只能有兩個值 true, false

// !false==true

//!true==false

28

課堂練習 請改寫上面所給的二元搜尋法 C 程式片段,撰寫

一個 C++ 程式可以讓使用者任意輸入5個數字並指定一個任意的搜尋數字,程式會輸出搜尋結果

29

搜尋法比較 循序搜尋法

資料不需排序

易實作、但效率較低

二元搜尋法

容易實作、效率高

必須確保資料有經過排序

30