20172319 《程序設計與數據結構》 第五週學習總結

20172319 2018.10.10-10.18

《程序設計與數據結構》第5周學習總結

目錄


教材學習內容總結

第九章 排序和查找:

  • 9.1 查找:
  • 查找(Searching) : 肯定目標元素是否存在於項目組中。
  • 查找池(Search pool) : 進行查找的項目組。
  • 高效地完成查找是咱們所須要追求的目標;所以,在算法上儘量地減小比較這一操做的次數。
  • 9.1.1 靜態方法:
  • 靜態方法(Static method) : 又稱類方法(Class method),能夠經過類名來激活,無需爲了調用一個靜態方法而去實例化該類的一個對象。
  • 靜態方法不能引用實例變量,由於其並不是做用於具體的對象中;但其能夠引用靜態變量,由於其存在與具體的對象無關。
  • 9.1.2 泛型方法:
  • 建立泛型方法的方法:在方法頭的返回類型前插入一個泛型聲明便可,泛型聲明必須位於返回類型以前,這樣泛型才能做爲返回類型的一部分。
public static <T extends Comparable<T>> boolean
        linearSearch(T[] data, int min, int max, T target)

  • 9.1.3 線性查找法
  • 線性查找,又稱其爲順序查找,是一種最簡單的查找方法,其基本思想:從查找池的第一個記錄開始,逐個比較記錄的關鍵字,直到和給定的關鍵字相等,則查找成功;若比較結果與查找池中n個記錄的關鍵字都不等,則查找失敗。
  • 時間複雜度爲 : O(n);
  • 平均查找長度 :ASL = (n + ······ + 2 + 1)/ n = (n + 1 ) / 2
  • 優缺點:
    • 優勢: 算法簡單,適應面廣,對錶的結構無任何要求,不管記錄是否按關鍵字有序都可應用。
    • 缺點: ASL較大,當n較大時,查找效率低。
  • 代碼實現:
public static <T>   boolean linearSearch(T[] data, int min, int max, T target)
    {
        int index = min;
        boolean found = false;

        while (!found && index <= max) 
        {
            found = data[index].equals(target);
            index++;
        }

        return found;
    }
  • 9.1.4 二分查找法
  • 二分查找 :也稱折半查找,效率較高,但要求線性表必須採用順序存儲結構,且表中元素按關鍵字有序排列。
  • 基本原理 : 首先先肯定在該存儲結構的中點位置;以後將待查找的值與中值進行比較;若兩者相等,則查找成功並返回此位置,不然肯定新的查找區間,再繼續進行二分查找:
    • 1.若待查找值大於中值,則新的查找區間爲前一查找區間的中值及區間後半部分元素。
    • 2.若待查找值小於中值,則新的查找區間爲前一查找區間的中值及區間前半部分元素。
  • 從初始的查找區間開始,每通過一次與當前查找區間的中點位置上的結點值的比較,便可判斷查找是否成功,不成功則當前的查找區間便縮小一半。這一過程一直重複,直至找到待查找值的位置,或者直至當前的查找區間爲空(即查找失敗)爲止。html

  • 時間複雜度 :O(log₂n);
    • 第n次查詢 剩餘待查詢元素的數量
      1 N/2
      2 N/(2^2)
      3 N/(2^3)
      4 N/(2^4)
      5 N/(2^5)
      6 N/(2^6)
      ······ ······
      ······ ······
      K N/(2^K)
  • 不管如何,只要還在查找的過程當中,N/(2^K)>=1,而咱們所考慮的最壞狀況 無非是N/(2^K)=1,因此有K = log₂n。
  • 平均查找長度: ASL = log₂(n+1)-1。(現有知識儲備不足,沒法作出相應推導)
  • 優缺點:
    • 優勢: 查找的效率較高。
    • 缺點: 只適用於有序表,且限於順序存儲結構,對線性鏈表沒法有效的進行查找,在一些特殊狀況 下查找效率很低:所查找的元素是表中的第一個元素和最後一個元素。
  • 代碼實現:java

public static <T extends Comparable<T>>  boolean binarySearch(T[] data, int min, int max, T target)
    {  
        boolean found = false;
        int midpoint = (min + max) / 2;  // determine the midpoint

        if (data[midpoint].compareTo(target) == 0) {
            found = true;
        } else if (data[midpoint].compareTo(target) > 0)
        {
            if (min <= midpoint - 1) {
                found = binarySearch(data, min, midpoint - 1, target);
            }
        }
        
        else if (midpoint + 1 <= max) {
            found = binarySearch(data, midpoint + 1, max, target);
        }

        return found;
    }
  • 9.2 排序
  • 排序(Sorting): 基於某一標準,以升序或降序的形式將項目池中的元素按某個規定好的序列進行排列。
  • 9.2.1 選擇排序法:
  • 選擇排序(Selection Sort): 在要排序的一組數中,選出最小的一個數與第一個位置的數交換;而後在剩下的數當中再找最小的與第二個位置的數交換,如此循環到倒數第二個數和最後一個數比較爲止。
    node

  • 代碼實現:git

public static <T extends Comparable<T>> void selectionSort(T[] data)
    {
        long startTime=System.nanoTime();   //獲取開始時間
        int Total_number_of_comparisons = 0;
        int min;
        T temp;

        for (int index = 0; index < data.length-1; index++)
        {
            min = index;

            for (int scan = index+1; scan < data.length; scan++) {
                Total_number_of_comparisons++;
                if (data[scan].compareTo(data[min])<0) {
                    min = scan;

                }
            }
            swap(data, min, index);
        }
        long endTime=System.nanoTime(); //獲取結束時間
        System.out.println("程序運行時間: "+(endTime-startTime)+"ns");
        System.out.println("總比較次數: " + Total_number_of_comparisons);
    }
  • 外層循環: 控制下一個最小值在數組中的存儲位置。
  • 內層循環: 掃描全部大於或等於外層循環指定索引的位置來找出剩餘列表的最小值。
  • 在肯定最小值後,將其和存儲在索引位置處的值交換。算法

  • 9.2.2 插入排序法:
  • 插入排序(Insertion Sort): 每步將一個待排序的記錄,按其順序碼大小插入到前面已經排序的字序列的合適位置(從後向前找到合適位置後),直到所有插入排序完爲止。
  • 代碼實現:數組

public static <T extends Comparable<T>> void insertionSort(T[] data)
    {
        long startTime=System.nanoTime();   //獲取開始時間
        int Total_number_of_comparisons = 0;
        for (int index = 1; index < data.length; index++)
        {
            T key = data[index];
            int position = index;
            
            // shift larger values to the right 
            while (position > 0 && data[position-1].compareTo(key) > 0)
            {
                data[position] = data[position-1];
                position--;
                Total_number_of_comparisons++;
            }

            data[position] = key;
        }
        long endTime=System.nanoTime(); //獲取結束時間
        System.out.println("程序運行時間: "+(endTime-startTime)+"ns");
        System.out.println("總比較次數: " + Total_number_of_comparisons);
    }
  • 外層循環: 控制下一個插入值在數組中的索引。
  • 內層循環: 將當前的插入值和存儲在更小的索引處的值進行比較。
  • 若當前插入值小於position的值,則將該值移位至右邊。數據結構

  • 9.2.3 冒泡排序法:
  • 冒泡排序(Bubble Sort): 重複地走訪過要排序的數列,一次比較兩個元素,若是他們的順序錯誤就把他們交換過來。走訪數列的工做是重複地進行直到沒有再須要交換,也就是說該數列已經排序完成,越小的元素會經由交換慢慢「浮」到數列的頂端。
    學習

  • 代碼實現:
    • 數組形式:
public static <T extends Comparable<T>> void bubbleSort(T[] data)
    {
        long startTime=System.nanoTime();   //獲取開始時間
        int Total_number_of_comparisons = 0;
        int position, scan;
        T temp;
        
        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);

                }
                Total_number_of_comparisons++;
            }
        }
        long endTime=System.nanoTime(); //獲取結束時間
        System.out.println("程序運行時間: "+(endTime-startTime)+"ns");
        System.out.println("總比較次數: " + Total_number_of_comparisons);
    }
  • 外層循環: 對數據進行n-1輪遍歷
  • 內層循環: 從頭到尾掃描數據,對相鄰數據進行成對比較,若符合條件則進行交換。
    • 鏈表形式(Exp1):
public void Bubble_sort(Linked_list_node Head,Linked_list linked_list){

        Linked_list_node temp = null, tail = null;
        temp = head;

        int count=1;
        while(temp.next != tail){
            while(temp.next != tail){
                if(temp.number > temp.next.number){
                    int temp_number = temp.number;
                    temp.number = temp.next.number;
                    temp.next.number = temp_number;
                    System.out.print("The list sorted by the "+ count + " truly bubbling sort is :  ");
                    System.out.println(linked_list);
                    System.out.print("The number of linked elements is :  " + linked_list.getCount() + "\n" );

                    count++;
                }
                temp = temp.next;

            }
            tail = temp;
            temp = head;
        }
    }
  • 9.2.4 快速排序法:
  • 快速排序(Quick Sort): 經過一趟排序將待排序記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另外一部分關鍵字小,則分別對這兩部分繼續進行排序,直到整個序列有序。

    ui

  • 代碼實現:.net

private static <T extends Comparable<T>> 
        int partition(T[] data, int min, int max)
    {

        T partitionelement;
        int left, right;
        int middle = (min + max) / 2;
        
        // use the middle data value as the partition element
        partitionelement = data[middle];
        // move it out of the way for now
        swap(data, middle, min);
        
        left = min;
        right = max;
        
        while (left < right)
        {
            // search for an element that is > the partition element
            while (left < right && data[left].compareTo(partitionelement) <= 0) {
                left++;
            }
            
            // search for an element that is < the partition element
            while (data[right].compareTo(partitionelement) > 0) {
                right--;
            }
            
            // swap the elements
            if (left < right) {
                swap(data, left, right);
            }
        }
        
        // move the partition element into place
        swap(data, min, right);
        
        return right;
    }
  • 先調用partition方法(返回分區元素值的索引)來將排序區域分割成兩個分區。
  • 而後兩次遞歸調用quicksort方法來對兩個分區元素進行排序。
private static <T extends Comparable<T>> void quickSort(T[] data, int min, int max)
    {
        if (min < max)
        {
            // create partitions
            int indexofpartition = partition(data, min, max);
            
            // sort the left partition (lower values)
            quickSort(data, min, indexofpartition - 1);
            
            // sort the right partition (higher values)
            quickSort(data, indexofpartition + 1, max);

        }
    }
  • 9.2.5 歸併排序法:
  • 歸併排序(Merge Sort): 將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分爲若干個子序列,每一個子序列是有序的。而後再把有序子序列合併爲總體有序序列。

  • 9.3 基數排序法


返回目錄


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

  • 問題1:在二分查找中,若查找的項目組裏元素個數是偶數個,中間項如何肯定?
  • 解決:
  • 解釋1:對於查找條件爲等式的狀況,mid指針能夠指向中間偏左,也能夠指向中間偏右,對於查找條件爲不等式時,要根據具體狀況選擇,查找大於某數的第一個數值時選擇指向中間偏左,查找小於某數的第一個數值時選擇之下是那個中間偏右。
  • 解釋2:二分查找通常都是左除右加1,意思是若是如今你的查找區間是(k,m),那麼中間點 mid = (k + m) / 2;若是你查找的節點在左邊就查找 (k, mid),在右邊就查找(mid+1,m)。
  • 解釋3:通常來講向下取整,好比8個數:1,2,3,4,5,6,7,8,mid=(1+8)/2=4 。

返回目錄


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

  • 問題1:PP9.2的題意吃得不是很透徹。

  • 解決:
  • 間隔排序法是冒泡排序法的一種變異,則其大致上的代碼結構不會發生變化
  • 仿照冒泡排序法,個人初始代碼是這樣的,這裏間隔爲2

  • 運行結果以下:
  • 能夠看到,通過遍歷比較後,相應間隔的元素都發生了對應的置換,而彼此相鄰的元素卻沒有通過比較,所以致使排序並不完整;
  • 而要想相鄰的元素也參與到比較之中,那以後的遍歷所取的間隔就要相應地發生必定的變化;
  • 做出相應更改以後的代碼:
  • 相應的運行結果:

返回目錄


代碼託管

返回目錄


上週考試錯題總結

  • 錯題1:無任何錯題。

  • 解決:

  • 錯題2:

  • 解決:

  • 錯題3:

  • 解決:

返回目錄


結對及互評

點評過的同窗博客和代碼

  • 本週結對學習狀況
    • 20172316趙乾宸
    • 博客中值得學習的或存在問題:
    • 20172329王文彬
    • 博客中值得學習的或存在問題:
    • 博客內容充實、排版整齊、對教材內容有通過一番認真思考、繼續保持。
    • 代碼截圖作標註時應儘可能避免遮擋代碼。
    • Markdown的部分縮進有誤。
    • 教材問題2提出得很好,能夠看出近斷時間來反覆使用鏈表、數組去實現同一類型的數據結構起得了必定的成效。

返回目錄


學習進度條

代碼行數(新增/累積) 博客量(新增/累積) 學習時間(新增/累積)
目標 3000行 15篇 300小時
第一週 0/0 1/1 12/12
第二週 935/935 1/2 24/36
第三週 849/1784 1/3 34/70
第四周 3600/5384 1/5 50/120
第五週 2254/7638 1/7 50/170

返回目錄


參考資料

二分查找過程、比較次數分析、java實現
折半查找的平均查找次數分析
二分查找的平均查找長度詳解

返回目錄

相關文章
相關標籤/搜索