Sorting and Binary Search

基礎排序與二分搜

Laurice

時間複雜度

  • 回想一下找最大值的時候我們怎麼做
int max = 0, i;
for(i=0;i<size_arr;i++){
    if(max< arr[i])
        max = arr[i];
}

// max is the answer

最多跑幾次?

常數 * size_arr

時間複雜度

T(n) = O(n)

Big O notation

                      的意思是,當n夠大時,我們可以找到一個常數c,

使得

T(n) < cn

例如:

n = O(n)
100n = O(n)
10n^2 = O(n^2)
50n-100 = O(n)

如果把n當成輸入的個數,Big O代表的其實就是跑的時間的上界

時間複雜度

  • 我們學過的東西的時間複雜度?
    • 找n個數裡的最大值?
      • 掃過所有數字選出最大的 ->
    • 判斷一個數字n是不是質數(這裡的n是數字大小)
      • 掃過 2~n ->
      • 掃過 2~       ->
    • ​給定平面上n個點,找最近點對
      • 枚舉所有點對並找出最小值 ->

 

O(n)
  • 為什麼需要知道時間複雜度?
    • 因為我們在意當問題規模變大時,演算法花的時間會增加多少
    • 常數會隨著語言、機器而變,所以Big O中省略常數
O(n)
O(\sqrt n)
\sqrt n
O(n^2)

時間複雜度

  • 今天要講的排序是最基本的方法:時間複雜度
    • Selection Sort 選擇排序法
    • Insertion Sort 插入排序法
    • Bubble Sort 泡沫排序法

 

 

O(n^2)

Sorting

基礎排序

選擇排序法 Selection Sort

          核心觀念:

          假設現在要由小排到大

  • 把資料分成排好序跟未排序兩邊
  • 每次都從未排序的那邊拿最小值放到排序好的那邊
  • 全部都變已排序就排完了

已排序

未排序

最小的元素

選擇排序法 Selection Sort

未排序

 20 15 -23 60 -80    由小排到大

已排序部分

未排序部分

20 15 -23 60 -80 

20 15 -23 60

-80 

20 15 60

-80 -23

20 60

-80 -23 15

60

-80 -23 15 20

-80 -23 15 20 60

選擇排序法 Selection Sort

未排序

  • 時間複雜度
    • 有n個元素
    • n次之後才會把所有的元素排好
    • 每次裡面都要看n個元素(找最小值)
O(n^2)
  • Code怎麼寫?
    • 一個大的for loop一個一個丟東西到已排序那邊
    • 一個小的for loop找最小值

選擇排序法 Selection Sort

就直接照著剛剛的方法,開一個新陣列放排序好的吧~

#include<iostream>

int main(){

    int unsorted[10] = {7, 4, 8, 2, 6, 3, 100, 9, 22, -20};
    int sorted[10];
    int i, j, min_index = 0;

    for(i=0;i<10;i++){
        
        for(j=0;j<10;j++){
            if(unsorted[j]<unsorted[min_index])
                min_index = j;
        }
        
        sorted[i] = unsorted[min_index];
        unsorted[min_index] = 1000;
    }

    for(i=0;i<10;i++)
        std::cout << sorted[i] << " ";
    return 0;
}
    

選擇排序法 Selection Sort

記憶體雖然不用錢,但是能省則省啊

#include<iostream>

int main(){

    int unsorted[10] = {7, 4, 8, 2, 6, 3, 100, 9, 22, -20};
    int i, j, min_index;

    for(i=0;i<10;i++){
        
        min_index = i;
        for(j=i;j<10;j++){
            if(unsorted[j]<unsorted[min_index])
                min_index = j;
        }

        //swap
        int tmp = unsorted[i];
        unsorted[i] = unsorted[min_index];
        unsorted[min_index] = tmp;
    }

    for(i=0;i<10;i++)
        std::cout << unsorted[i] << " ";
    return 0;
}
    

插入排序法 Insertion Sort

  1. 一樣分成排好跟未排好
  2. 一直向左邊比,如果順序不對就交換
  3. 直到相對順序是對的

左邊的圖接下來怎麼跑?

插入排序法 Insertion Sort

#include<iostream>


int main(){
    int array[10] = {293, 422, 12, 31, 41, 21, 33, 55, 2, 10};
    int n, i, j, length = 10;
    for (i = 1; i < length; ++i)
    {
        n = array[i];
        for (j = i - 1; j >= 0 && array[j] > n; --j)
            array[j + 1] = array[j];
        array[j + 1] = n;
    }
    for(i=0;i<length;i++)
        std::cout << array[i] << " ";
    return 0;
}

泡沫排序法 Bubble Sort

顧名思義,

他就是個像泡沫一樣的排序法?

 

像泡泡一樣,密度小的一直往上跑

                       數值大的一直往後跑

泡沫排序法 Bubble Sort

  1. 比較相鄰的元素,如果前者比後者大,就交換他們兩個。
  2. 再換下一對相鄰的元素做一樣的事
  3. 針對所有的元素重複以上的步驟,除了最後一個。
  4. 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字的順序是錯的。

由小排到大

泡沫排序法 Bubble Sort

  • Code 怎麼寫呢?
    • 雙層for loop
#include <iostream>
void bubble_sort(int arr[], int len) {
    int i, j, temp;
    for (i = 0; i < len - 1; i++){
	for (j = 0; j < len - 1 - i; j++){    //最後i個是已經浮(?)好的
	    if (arr[j] > arr[j + 1]) {
                temp = arr[j];      //swap
		arr[j] = arr[j + 1];
		arr[j + 1] = temp;
	    }
        }
    }
}
int main() {
    int arr[] = { 22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70 };
    int len = 14;
    bubble_sort(arr, len);
    int i;
    for (i = 0; i < len; i++)
        std::cout << arr[i] << " ";
    return 0;
}

注意:j的index上界是len - 1 - i,Why??

練習:#369 書瑾與他的泡泡們

Binary Search

二分搜尋法

如何搜尋 

假設現在給你一個已經由小到大排好的陣列

  1. 找出最大值
  2. 找出最小值 
  3. 找出第二大的值
  4. 找出第K大的值
  5. 找出裡面有沒有36

難道我真的要整個陣列走一次嗎.....

要整個陣列走一次嗎.....

走一次嗎.....

嗎.....

如何搜尋 

假設現在給你一個已經由小到大排好的陣列

1 4 100 232 2111 20321

Max

Min

但要找特定數字,像是36? 30000?

二分搜 Binary Search

顧名思義,就是一次切兩份搜

ex. 找20321

1 4 100 232 2111 20321

round1 

round2

二分搜 Binary Search

-122 4 24 34 47 48 55 65 80 80

return the index of 48

0 1 2 3 4 5 6 7 8 9

二分搜 Binary Search

Code 怎麼寫?

1. 每一輪都有左index: left 跟右index: right

2. leftright )  -> 含左不含右

3. mid = (left + right)/2

4. arr[mid] > num   :在mid左邊,right = mid

    arr[mid] < num   :在mid右邊,left = mid + 1

    arr[mid] == num :找到了!!

給定一個由小排到大的陣列

二分搜 Binary Search

#include<iostream>


int binary_search(int arr[], int size, int goal){
    
    int left = 0, right = size, mid;  //含左不含右
    
    while(left < right){              //如果左界與右界相等,是發生什麼事了呢?
        
        mid = (left + right)/2;
        
        if(arr[mid] == goal)
            return mid;
        else if(arr[mid] > goal)
            right = mid;
        else if(arr[mid] < goal)
            left = mid + 1;
    }
    
    return -1;   //while loop跑完還沒找到,回傳-1表示要找的東西不在裡面
}
        

二分搜 Binary Search

如果給你的資料是由大排到小呢?

判斷新的left, right的方法不一樣

二分搜真的有比較快嗎?

  • 一個個看:O(n)
  • 二分搜    :O(log n)

y = x

y = log x

以上講的都是對數字做比較跟搜尋,

還有什麼可以排序跟搜尋呢?

字串!!

strcmp(str1, str2) 回傳值的意義:

等於0: 兩個字串一樣

大於0: 前面的字串字典序比較大 (ex. apple > abuse)

大於0: 前面的字串字典序比較小 (ex. apple < banana)

 

 

Any Questions?

再說一次,我叫LauriceXD

Sorting and Binary Search

By austinlaurice

Sorting and Binary Search

for CSIE sprout

  • 1,390