20162330 2017-2018-1《程序設計與數據結構》第三週學習總結


2017-2018-1 學習總結目錄: 1 2 3 5 6 7 9 10 11 12
html



目錄




教材學習內容總結

第13章 查找與排序

1.查找

  • 查找是在數據項中找到指定目標元素或是肯定目標不存在的過程。git

  • 查找池中找到目標須要的比較次數會隨着數據項的增長而增長;
    查找算法做用於 Comparable (多態)對象中的數組(compareTo 方法比較元素)。算法

  • 查找策略:
    • 窮舉法(線性查找)
    • 分治(二分查找)
  • 線性查找:依次比較,不要求有序,基於 Comparable 接口的實現,時間複雜度:O(n)
    二分查找:效率高,適用於有序數據項,迭代,分治,時間複雜度:O(nlog\(_2\)n)
public static Comparable binarySearch (Comparable[] data, Comparable target){
        Comparable result = null;
        int first = 0, last = data.length - 1,mid;  //查找範圍

        while(result == null && first <=last){
            mid = (first + last)/2;  //中間位置比較元素
            if (data[mid].compareTo(target) == 0)
                result = data[mid];  //查找成功
            else
                if(data[mid].compareTo(target) > 0)
                    last = mid - 1;  //範圍縮小到前半段
                else
                    first = mid + 1;  //範圍縮小到後半段
        }
        return result;
    }

【補充】二分查找算法主要步驟概括以下:(假設是有序列表)
(1)定義初值:first = 0, last = length - 1
(2)若是 first ≤ last,循環執行如下步驟:
  ① mid = (first + last)/2
  ② 若是 target 與 data[mid] 的關鍵字值相等,則查找成功,返回 mid 值,不然繼續執行;
  ③ 若是 target 小於 data[mid] 的關鍵字值,那麼 last = mid - 1,不然 first = mid + 1
(3)若是 first > last,查找失敗,返回 null。數組

---

2.排序

  • 排序:按照某種標準將一列數據項次序重排;
    依據:關鍵字(字母、數字等);
    順序:遞增、遞減、非遞增、非遞減。數據結構

  • 選擇排序:掃描整個表,找到最小值,交換。反覆將一個個具體的值放到它 最終 的有序位置。(整理無序撲克牌)
public static void selectionSort(Comparable[] data)
    {
        int min;

        for(int index = 0 ; index < data.length - 1; index++)  //  控制存儲位置
        {
            min = index;
            for(int scan = index + 1;scan < data.length; scan++)  //  查找餘下數據
                if (data[scan].compareTo(data[min]) < 0)  //  查找最小值
                    min = scan;

            swap(data,min,index);  //  交換賦值
        }
    }

交換方法:性能

private static void swap(Comparable[] data,int index1,int index2){
        Comparable temp = data[index1];  //引入一個臨時變量
        data[index1] = data[index2];
        data[index2] = temp;
    }
  • 示例:

    學習

  • 插入排序:反覆將一個個具體的值插入到有序的子序列中(合適位置)。(抓牌整理法)
    僞代碼及實現過程:
for(從第二個數據開始對全部數據循環處理)
{
    while (第i個數據小於它以前的第i-1個數據)
        {
        將第i個數據複製到一個空閒空間臨時存儲,這個空間爲「哨兵」
        在前i-1個數據中尋找合適的位置,將從該位置開始的元素所有後移
        將哨兵數據插入到合適位置
        }
}
public static void insertionSort (Comparable[] data)
    {
        for (int index = 1; index < data.length; index++)
        {
            Comparable key = data[index];
            int position = index;

            // 哨兵臨時存儲
            while (position > 0 && data[position-1].compareTo(key) > 0)
            {
                data[position] = data[position-1];  //位置所有後移
                position--;
            }

            data[position] = key;  //合適位置
        }
    }
  • 示例:
    測試

  • 希爾排序:把一個長序列分割爲若干個短序列,直接插入排序。
    示例:
    優化

  • 冒泡排序:反覆比較相鄰元素,若是必要就交換次序。
public static void bubbleSort (Comparable[] data)
    {
        int position, scan;

        for (position = data.length - 1; position >= 0; position--)
        {
            for (scan = 0; scan <= position - 1; scan++)
                if (data[scan].compareTo(data[scan+1]) > 0)
                    swap (data, scan, scan+1);  //逆序交換
        }
    }
  • 示例:

    ui

  • 快速排序:根據樞軸劃分序列,以後使用遞歸對子序列排序。
    樞軸:通常而言咱們選擇整個序列的第一個數爲樞軸。
public static void quickSort (Comparable[] data, int min, int max)
    {
        int pivot;

        if (min < max)
        {
            pivot = partition (data, min, max);  // make partitions(定義樞軸)
            quickSort(data, min, pivot-1);  // sort left partition
            quickSort(data, pivot+1, max);  // sort right partition
        }
    }

劃分並排序:

private static int partition (Comparable[] data, int min, int max)
    {
        // Use first element as the partition value
        Comparable partitionValue = data[min];

        int left = min;
        int right = max;

        while (left < right)
        {
            // Search for an element that is > the partition element
            while (data[left].compareTo(partitionValue) <= 0 && left < right)
                left++;

            // Search for an element that is < the partitionelement
            while (data[right].compareTo(partitionValue) > 0)
                right--;

            if (left < right)
                swap(data, left, right);
        }

        // Move the partition element to its final position
        swap (data, min, right);

        return right;
    }
  • 示例:


  • 歸併排序:遞歸平分,直到每一個序列只含一個元素,以後歸併爲有序表。
public static void mergeSort (Comparable[] data, int min, int max)
    {
        if (min < max)
        {
            int mid = (min + max) / 2;
            mergeSort (data, min, mid);
            mergeSort (data, mid+1, max);
            merge (data, min, mid, max);
        }
    }

歸併算法中關鍵代碼:

int first1 = first, last1 = mid;  // endpoints of first subarray
        int first2 = mid+1, last2 = last;  // endpoints of second subarray
        int index = first1;  // next index open in temp array

        //  Copy smaller item from each subarray into temp until one
        //  of the subarrays is exhausted
        while (first1 <= last1 && first2 <= last2)
        {
            if (data[first1].compareTo(data[first2]) < 0)
            {
                temp[index] = data[first1];
                first1++;
            }
            else
            {
                temp[index] = data[first2];
                first2++;
            }
            index++;
        }

以後檢查各個序列中的元素是否用盡,最後將有序數據複製回原數組。

  • 示例:

  • 分配排序:用額外空間節省時間。(桶排序、基數排序)
    示例:

  • 堆排序:堆積排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆是一個近似徹底二叉樹的結構,並同時知足堆性質:即子結點的鍵值或索引老是小於(或者大於)它的父結點。
    示例:

3.分析查找及排序算法

  • 考慮最差情形

  • 查找算法:二分查找高效(對數階)

  • 排序算法:性能比較

    排序方法 平均時間 最壞狀況 輔助存儲
     冒泡排序  O(\(n^2\))  O(\(n^2\))   O(1) 
     選擇排序  O(\(n^2\))   O(\(n^2\))   O(1) 
     希爾排序  O(nlogn)   O(nlogn)   O(1) 
     快速排序  O(nlogn)   O(\(n^2\))   O(logn) 
     堆排序  O(nlogn)   O(nlogn)   O(1) 
     歸併排序  O(nlogn)   O(nlogn)   O(n) 
     插入排序  O(\(n^2\))   O(\(n^2\))   O(1) 
     桶排序   O(n)   O(\(n^2\))   O(n) 
     基數排序  O(d(n+k))   O(d(n+k))   O(d(kd)) 

    【注】表中n是排序元素個數,d個關鍵字,關鍵碼的取值範圍爲k

【返回目錄】


教材學習中的問題和解決過程

  • 【問題1】:在看本章內容的PPT時,快速排序有一個示例沒看懂,只看圖的話,我以爲實線圈中的數和加粗的虛線圈中的數的位置變更沒有什麼規律,因此不太理解快速排序的執行順序。

  • 解決方案 :在仔細閱讀了相關內容以後,我發現實線圈中的數和加粗的虛線圈中的數的位置變更規律、比較順序並非受到同類線圈的影響,在選好樞軸之後,就開始首尾比較元素,以49爲樞軸,左右依次比較,順序就跳過一次,直到縮減到中間位置,便實現了劃分序列。我原來是被不一樣的線圈中的數迷惑了,才弄錯了執行次序。
    【注】樞軸是一個數。

  • 【問題2】:關於考試時的算法複雜度練習,求該算法的時間複雜度:
void fun3(int n)
{ int i=0,s=0;
while (s<=n)
{ i++;
s=s+i;
}
}
  • 解決方案 :之因此作錯是由於當時沒有仔細考慮while循環的執行次數,利用數學中的等差數列公式,能夠最後獲得 \(\frac{T(n)*[T(n) + 1]}{2}\),可簡化爲\(T^2\)(n),而這個值又小於等於n,因此T(n) ≤ \(\sqrt{n}\),即時間複雜度爲O(\(\sqrt{n}\))。

【返回目錄】


代碼調試中的問題和解決過程

  • 【問題】:在看教材代碼程序13.4時,不理解將姓氏和名字交換過來以後怎麼對數組中的字符串元素排序?

  • 解決方案 :在IDEA中使用debug單步調試,我發現這裏的關鍵字是按照字母的順序排列,從而返回一個正整數,負整數或者0。如圖所示:這裏的scan索引是D開頭的姓氏,而min索引是F開頭的姓氏,使用compareTo比較時(ASCII碼錶中),至關於將字母當成數字相減,因此這裏得出的是負整數-2,小於0,因此從新賦值,即最小索引對應的值。

【返回目錄】


代碼託管

  • 本週代碼上傳至 ch13 和 Practice 兩個文件夾裏:
    (statistics.sh腳本的運行結果截圖)


本週考試錯題總結

  • 本週課下測試還未給出錯題和解析:

  • 課上測試錯題以下:
    【錯題1】有如下用Java語言描述的算法,說明其功能並計算複雜度
double fun(double y,double x,int n)
{
 y=x;
while (n>1)
{ 
y=y*x;
n--;
}
return y;
}

【正解】計算\(x^n\);O(n)
【理解】當時由於循環前將x的值賦給了y,因此我有點糾結究竟是計算\(x^n\)仍是\(y^n\),最後寫成\(y^n\)。仔細一想,在循環前的y是否賦值與循環內的x沒有關係,即便循環以外y賦值爲x,循環內仍然是x,若是將循環內的y理解爲x那麼y則是無規律增加的,因此這裏是計算\(x^n\),至於O(n),我居然忘記了加大O符號(¬_¬)。

  • 【錯題2】求該算法的時間複雜度:
void fun3(int n)
{ int i=0,s=0;
while (s<=n)
{ i++;
s=s+i;
}
}

【正解】O(\(\sqrt{n}\))
【理解】之因此作錯是由於當時沒有仔細考慮while循環的執行次數,利用數學中的等差數列公式,能夠最後獲得 \(\frac{T(n)*[T(n) + 1]}{2}\),可簡化爲\(T^2\)(n),而這個值又小於等於n,因此T(n) ≤ \(\sqrt{n}\),即時間複雜度爲O(\(\sqrt{n}\))。

【返回目錄】


結對及互評

  • 本週個人結對夥伴莫禮鍾除了聽了課堂上的一些內容以外,課後就沒有其餘學習活動了,我建議他把書過一遍,可是仍然被「狼人殺」束縛着,監督幾回都沒有效果。星期一的時候翻了幾頁構建之法,以後又忙於老鄉會,保證過再也不通宵玩遊戲可是又通宵了一次。本學期只有第一週學習狀況良好,以後便一蹶不振。

本週結對學習狀況

  • 20162319
  • 結對學習內容
    • 構建之法第十六章(一小部分)


其餘(感悟、思考等,可選)

  本週狀態通常,比前兩週稍差一些,有點匆忙,可是每當空閒時有有些缺乏動力,本週課堂測試作得也很差,能作對的2分題沒有得分,說明前一章的掌握狀況有些死板。對於這周的學習內容,我明顯感受到難度在逐漸上升。這周的活動略多,老是忽然來一個通知,有時會影響一天的計劃,可是也不能由於事多就把主要精力大量分散。下週繼續保持狀態,求穩不求快。

  • 【附1】教材及考試題中涉及到的英語:

    Chinese English Chinese English
    泛型 generic 劃分元素 partition element
    線性查找 linear search 樞軸點 pivot point
    二分查找 binary search 優化 optimize
    插入排序 insertion sort 子表 sublist(s)
    歸併排序 merge sort 子集 subset
    排除 eliminate 指定的 designated
  • 【附2】本週小組博客:團隊學習:《構建之法》

【返回目錄】


學習進度條

  • 代碼行數(新增/累積) 博客量(新增/累積) 學習時間(新增/累積) 重要成長
    目標 5000行 30篇 400小時
    第一週 234/234 1/28 14/14 瞭解算法效率、大O符號等理論內容
    第二週 255/489 1/29 12/26 瞭解敏捷的團隊、泛型的使用
    第三週 436/925 2/31 10/36 瞭解一些查找和排序的算法
  • 計劃學習時間:14小時

  • 實際學習時間:10小時

  • 有效學習時間:4小時

  • 改進狀況:學習時間有些降低,本週建立小組博客反覆試驗模板花費了一些沒必要要的時間,在代碼上明顯感受有些亂,下週打算把課本上的內容再過一遍。


參考資料

【返回目錄】

相關文章
相關標籤/搜索