20172302 《Java軟件結構與數據結構》實驗三:查找與排序實驗報告

課程:《Java軟件結構與數據結構》

班級: 1723

姓名: 侯澤洋

學號:20172302

實驗教師:王志強老師

實驗日期:2018年11月19日

必修/選修: 必修

實驗內容

  • (1)定義一個Searching和Sorting類,並在類中實現linearSearch(教材P162 ),SelectionSort方法(P169),最後完成測試。要求很多於10個測試用例,提交測試用例設計狀況(正常,異常,邊界,正序,逆序),用例數據中要包含本身學號的後四位提交運行結果圖。php

  • (2)重構你的代碼,把Sorting.java Searching.java放入 cn.edu.besti.cs1723.(姓名首字母+四位學號) 包中(例如:cn.edu.besti.cs1723.G2301),把測試代碼放test包中,從新編譯,運行代碼,提交編譯,運行的截圖(IDEA,命令行兩種)html

  • (3)參考http://www.cnblogs.com/maybe2030/p/4715035.html 在Searching中補充查找算法並測試,提交運行結果截圖java

  • (4)補充實現課上講過的排序方法:希爾排序,堆排序,二叉樹排序等(至少3個)測試實現的算法(正常,異常,邊界)提交運行結果截圖git

  • (5)編寫Android程序對各類查找與排序算法進行測試,提交運行結果截圖,推送代碼到碼雲web

實驗過程及結果

(1)實驗一

定義一個Searching和Sorting類,並在類中實現linearSearch(教材P162 ),SelectionSort方法(P169)
SelectionSort方法測試:
測試正常狀況:算法

@Test
    public void testNormal() throws Exception
    {
        Integer[] integers1 = {2,7,12,13,14,23,29,32,46,56};
        Integer[] integers2 = {7,32,12,46,14,56,29,13,23,2};
        Sorting.selectionSort(integers2);
        for (int i=0;i<integers2.length;i++)
             assertEquals(integers1[i],integers2[i]);
    }

測試異常狀況:數組

@Test
    public void testAbnormal() throws Exception
    {
        Integer[] integers1 = {2,7,12,13,14,23,29,32,46,56};
        Integer[] integers2 = {7,32,12,46,14,56,29,14,23,2};
        Sorting.selectionSort(integers2);
        boolean result1 = true;
        for (int i =0 ;i<integers2.length;i++)
        {
            if (integers1[i]!=integers2[i])
            {
                result1 = false;
                break;
            }
        }
        assertEquals(false,result1);
    }

測試邊界狀況:數據結構

@Test
    public void testBoundary () throws Exception{
        Integer[] integers1 = {2,7,12,13,14,23,29,32,46,8961};
        Integer[] integers2 = {7,32,12,46,14,8961,29,14,23,2};
        Sorting.selectionSort(integers2);
        boolean result1 = true;
        for (int i =0 ;i<integers2.length;i++)
        {
            if (integers1[i]!=integers2[i])
            {
                result1 = false;
                break;
            }
        }
        assertEquals(false,result1);
    }

測試逆序:性能

@Test
    public void testReversed() throws Exception
    {
        Integer[] integers1 = {56,46,32,29,23,14,13,12,7,2};
        Integer[] integers2 = {7,32,12,46,14,56,29,13,23,2};
        Sorting.selectionSort(integers2);
        for (int i=0;i<integers2.length;i++)
            assertEquals(integers1[integers1.length-1-i],integers2[i]);
    }

測試結果:

測試

[測試用例代碼]https://gitee.com/CS-IMIS-23/Java-pro/commit/6fff44510202eac172b3cbd26756c6554797802d

(2)實驗二

  • 重構代碼,把Sorting.java Searching.java放入 cn.edu.besti.cs1723.(姓名首字母+四位學號) 包中(例如:cn.edu.besti.cs1723.G2301),把測試代碼放test包中,從新編譯,運行代碼,提交編譯,運行的截圖(IDEA,命令行兩種)
    時間不夠沒有完成命令行,虛擬機也卸載掉了,只完成了第一種IDEA,對代碼重構,放入指定包中。

(3)實驗三

參考http://www.cnblogs.com/maybe2030/p/4715035.html 在Searching中補充查找算法並測試,提交運行結果截圖
七種查找算法:線性查找、二分查找、插值查找、斐波那契查找、樹表查找、分塊查找、哈希查找
七種裏面,斐波那契查找分塊查找是兩個新學的,也比較有意思
斐波那契查找的原理是利用斐波那契數列的特性來進行查找的,不是以二分的比列來查找,而是按照黃金比列0.618來進行分割查找,這樣作的好處是:

關於斐波那契查找, 若是要查找的記錄在右側,則左側的數據都不用再判斷了,不斷反覆進行下去,對處於當衆的大部分數據,其工做效率要高一些。因此儘管斐波那契查找的時間複雜度也爲O(logn),但就平均性能來講,斐波那契查找要優於折半查找。惋惜若是是最壞的狀況,好比這裏key=1,那麼始終都處於左側在查找,則查找效率低於折半查找。
還有關鍵一點,折半查找是進行加法與除法運算的(mid=(low+high)/2),插值查找則進行更復雜的四則運算(mid = low + (high - low) * ((key - a[low]) / (a[high] - a[low]))),而斐波那契查找只進行最簡單的加減法運算(mid = low + F[k-1] - 1),在海量數據的查找過程當中,這種細微的差異可能會影響最終的效率。

代碼實現:

/*構造一個斐波那契數組*/
    public static void Fibonacci(int[] F)
    {
        F[0]=0;
        F[1]=1;
        for(int i=2;i<max_size;++i)
            F[i]=F[i-1]+F[i-2];
    }

    //斐波那契查找
    public static <T extends Comparable<? super T>>
       boolean FibonacciSearch(T[] data, int min, int max, T target)
    {
        int length = max - min +1;

        int[] F = new int[max_size];
        Fibonacci(F);

        int k=0;
        while (length>(F[k]-1))
        {
            k++;
        }
        Object[] temp = new Object[max_size];
        System.arraycopy(data,0,temp,0,data.length-1);
        for (int i=length;i<F[k]-1;i++)
        {
            temp[i] = data[length-1];
        }
        while(min<=max)
        {
            int mid=min+F[k-1]-1;
            if(target.compareTo((T) temp[mid])<0)
            {
                max=mid-1;
                k-=1;
            }
            else if(target.compareTo((T)temp[mid])>0)
            {
                min=mid+1;
                k-=2;
            }
            else
            {
               return true;
            }
        }
        return false;
    }

分塊查找給個人第一感受是快速排序算法,這進行劃分,就用了原快速排序算法中的partition方法,我將整個數組分紅了四塊,進行了三次劃分,而後根據比較結果肯定元素所在區域,而後進行線性查找。

public static <T extends Comparable<? super T>>
    boolean partitionSearch(T[] data, int min, int max, T target)
    {
        boolean result = false;
        int partition1 = partition(data,min,max);

        int partition2 = partition(data,min,partition1-1);
        int partition3 = partition(data,partition1+1,max);

        if (target.compareTo(data[partition1])==0)
            return true;
        else
            {
                if (target.compareTo(data[partition1])<0)
                {
                    if (target.compareTo(data[partition2])==0)
                        return true;
                    else
                    {
                        if (target.compareTo(data[partition2])<0)
                            result =  linearSearch(data,min,partition2-1,target);
                        else
                            result =  linearSearch(data,partition2+1,partition1-1,target);
                    }
                }
                else
                    {
                        if (target.compareTo(data[partition3])==0)
                            return true;
                        else
                        {
                            if (target.compareTo(data[partition3])<0)
                              result = linearSearch(data,partition1+1,partition3-1,target);
                            else
                                result = linearSearch(data,partition3+1,max,target);
                        }
                    }
            }
            return result;
    }

(4)實驗四

補充實現課上講過的排序方法:希爾排序,堆排序,二叉樹排序等
希爾排序是新學的部分,一開始我對這裏的希爾排序和以前作過的一個冒泡排序的升級的間隔排序法分辨不清,怎麼也弄不明白這兩個有什麼區別,問題會記錄這裏。
將無序數組分割爲若干個子序列,子序列不是逐段分割的,而是相隔特定的增量的子序列,對各個子序列進行插入排序;而後再選擇一個更小的增量,再將數組分割爲多個子序列進行排序......最後選擇增量爲1,即便用直接插入排序,使最終數組成爲有序。
增量的選擇:在每趟的排序過程都有一個增量,至少知足一個規則 增量關係 d[1] > d[2] > d[3] >..> d[t] = 1 (t趟排序);根據增量序列的選取其時間複雜度也會有變化,這個很多論文進行了研究,在此處就再也不深究;本文采用首選增量爲n/2,以此遞推,每次增量爲原先的1/2,直到增量爲1;


實現代碼:

public static <T extends Comparable<T>>void heapSort(T[] data)
    {
        LinkedHeap<T> linkedHeap = new LinkedHeap<>();
        for (int i=0;i<data.length;i++)
            linkedHeap.addElement(data[i]);
        for (int i=0;i<data.length;i++)
            data[i] = linkedHeap.removeMin();
    }

實驗代碼很是簡單。

(5)實驗五

編寫Android程序對各類查找與排序算法進行測試,提交運行結果截圖,推送代碼到碼雲
在Android上把這些算法都進行了測試,錄了一個短的視頻。
[連接]:https://www.mosoteach.cn/web/index.php?c=interaction_homework&m=homework_result_list&clazz_course_id=8CE1B708-B1CE-11E8-AA22-7CD30AD36C02&id=45E962C9-D25E-E6A1-697E-5820A8FAC84E
[代碼連接]:https://gitee.com/CS-IMIS-23/Java-pro/commit/5b4d837f976592fbed90a14a3e7e194bc63997fd

實驗過程當中遇到的問題和解決過程

  • 問題1:關於泛型數組如何實例化?直接這樣T[] temp = new T[];出現錯誤。

  • 問題1解決方案:參照書上以前的代碼進行實例化
T[] array;
array = (T[]) new Object[10];

還找到一種方法是數組就是Object類型,使用再將Object類型強制轉化爲T類型也是能夠。

  • 問題2:希爾排序和間隔排序法的一個區別?

  • 問題2解決方案:
    希爾排序是對間隔爲必定距離的這些元素,所有進行排序,也就是說,通過這麼一次排序以後,那麼間隔爲該距離的元素構成的一個集合必定是已排序好的。
    而間隔排序作的是從最開始元素開始,對這些元素,把大的放在後面,一次排序後,間隔爲該距離的元素構成的集合不必定有序。但最後面的那個必定是最大的。
    舉個簡單的例子:
    對 {9 7 6 4 3}進行排序
    希爾排序第一輪
    間隔爲2進行,獲得 3 4 6 7 9 即 三、六、9是有序的,四、7是有序的。
    間隔排序第一輪
    獲得 6 4 3 7 9,即9放到了後面,7也被放到了後面。
    這就產生了差異,二者在實現的代碼上也有較大區別。

其餘(感悟、思考等)

  • 本次實驗主要的是排序和查找的算法的一些設計,幫助咱們複習了以前的內容,同時也爲接下來的Android開發提供了一個方向。

參考資料

相關文章
相關標籤/搜索