20172304 實驗三報告

20172304 實驗二報告

  • 課程:《軟件結構與數據結構》
  • 班級: 1723
  • 姓名: 段志軒
  • 學號:20172304
  • 實驗教師:王志強
  • 助教:張師瑜&張之睿
  • 實驗日期:2018年11月5日-2018年11月12日
  • 必修選修: 必修

    實驗要求

    實驗三-查找與排序-1
    定義一個Searching和Sorting類,並在類中實現linearSearch(教材P162 ),SelectionSort方法(P169),最後完成測試。要求不少於10個測試用例,提交測試用例設計情況(正常,異常,邊界,正序,逆序),用例數據中要包含自己學號的後四位提交運行結果圖。
    實驗三-查找與排序-2
    重構你的代碼
    把Sorting.java Searching.java放入 cn.edu.besti.cs1723.(姓名首字母+四位學號) 包中(例如:cn.edu.besti.cs1723.G2301)把測試代碼放test包中重新編譯,運行代碼,提交編譯,運行的截圖(IDEA,命令行兩種)

實驗三-查找與排序-3
參考http://www.cnblogs.com/maybe2030/p/4715035.html 在Searching中補充查找算法並測試提交運行結果截圖
實驗三-查找與排序-4
補充實現課上講過的排序方法:希爾排序,堆排序,二叉樹排序等(至少3個)
測試實現的算法(正常,異常,邊界)
提交運行結果截圖
實驗三-查找與排序-5(選做,加分)
編寫Android程序對各種查找與排序算法進行測試
提交運行結果截圖

實驗過程及實驗結果

實驗一過程及結果:
本次實驗主要內容是對之前已經學習過的順序查找和選擇排序進行測試,實際上就是讓我們再次熟悉一下junit測試的相關內容以及複習一下有關順序查找和選擇排序的相關內容。但是由於後續實驗的內容都是在Sorting類以及Searching類的基礎上繼續改進的,所以在此我就不講相關的碼雲鏈接給出,而只給出順序查找以及選擇排序的相關代碼。
順序查找

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;
    }

選擇排序

public static <T extends Comparable<T>> T[] selectionSort(T[] data)
    {
        int min;
        T temp;

        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);
        }
        return data;
        }
private static <T extends Comparable<? super T>> void swap(T[] data, int index1, int index2)
        {
            T temp = data[index1];
            data[index1] = data[index2];
            data[index2] = temp;
        }

然後將相關的junit測試截圖發過來
這是順序查找的圖片


這是選擇排序的圖片

說明:由於要求至少十個測試用例,所以我將兩個方法的測試的每種情況(正常,異常,邊界,正序,逆序)在查找的測試中,雖然我不知道測試邊界究竟有什麼用,但是我還是查找了兩個位於給定數組邊界的兩個元素,在設置異常的時候,考慮到實現的順序查找的是需要給定的查找範圍的,於是就給定了一個超過給定數組範圍的範圍,並且爲他大度劃分出了一個測試的空間,最後不出意外的出現了異常,拋出了ArrayIndexOutOfBoundsException,也就是我們認知意義上的數組越界異常。
在處理選擇排序的時候,雖然還是不理解測試一個正序數組道德排序究竟有何意義,但是還是做了,並且爲了滿足10個用例的要求,最終也是每個情況做了多組數據的測試,但是考慮到排序算法似乎並沒有所謂的什麼邊界,所以最終就沒有做這方面的測試,在進行設置異常的時候。首先聲明瞭一個Comparable數組,這個數組有個很神奇的地方就是它能夠同時容納不同類型的數據,所以我就在這個數組中儲存了整數型的數據和文本型也就是String類型的數據。然後在進行排序的時候理所當然的就會出現異常。最終拋出的異常是ClassCastException: java.lang.Integer cannot be cast to java.lang.String,也就是類型轉換異常:整數型變量不能轉換爲文本型變量。

實驗二過程與結果
重構你的代碼
把Sorting.java Searching.java放入 cn.edu.besti.cs1723.(姓名首字母+四位學號) 包中(例如:cn.edu.besti.cs1723.G2301)把測試代碼放test包中重新編譯,運行代碼,提交編譯,運行的截圖(IDEA,命令行兩種)
實驗二的idea部分實際上並沒有什麼難度,只是換了一個位置,然後重新進行測試就是了。最後的結果和實驗一雷同,於是就不在此放出圖片了。然後就是命令行部分的實現了,出於嚴謹的態度,我請示了一下王老師,命令行模式是否也要在junit中進行測試,在得到肯定回答後就是噩夢的開始。首先上網上查資料。查到了首先應該是導入一個插件,也就是所謂的後綴爲.jar的東西,下載之後就是導入的過程了。首先是找到導入位置,可能是太久沒有人有勇氣嘗試在命令行中進行junit測試了,網上給定的教程的版本不知落後了我的虛擬機版本不知道多少輩子子孫孫。終於在費盡九牛二虎之力後,終於找到疑似目標之後,卻又被權限困住了。還曾記得老師曾經教過我們,我們所學的是面向對象的設計是頂層設計,但是沒想到自己最後卻敗在底層結構上了。圖形界面沒權限,命令行一般的移動命令mv似乎也不能識.jar這個東西。系統給我的提示是系統並不認爲這是個文件,當時我就崩了,內心中猶如滔滔江水,氾濫而過,一發不可收拾。最終在掙扎與無奈中,伴隨着12點鐘聲的響起,只能與我的實驗二的另一半分數作別。別了,實驗二的另一半。曾經有一份分數擺在我面前,我沒有珍惜,如果上天能再給我一次機會,我會對他說:“junit還是idea的好。”
實驗三過程與結果
決策樹,這個的實現是基於書上的代碼,這個實際上也沒有也沒有太大的難度
DecisionTree碼雲鏈接
CharacterAnalyzer
這是我設計的決策樹

測試結果

實驗三
這個實驗主要就是要求我們閱讀老師給定的博客,然後將相關算法補充完整,實際上,這更加類似於,將C++翻譯成java的過程。除了實驗一中已經使用過的順序查找,這篇博客中還給出了二分查找,插值查找,斐波那契查找,平衡查找樹,分塊查找,哈希查找。處於治學嚴謹的態度,首先我要介紹着幾種算法的原理。。
首先是順序查找。
順序查找顧名思義,就是按照順序查找,就是從頭開始依次向下進行。
然後二分查找是建立在已經排序好的數組的基礎上的。首先由首尾兩個數據算出將要作爲標準的中間值,然後將查找目標與中間值進行比較。如果相等就返回true。如果小於中間值。則取中間值左面的數組,如果大於則反之。最後如果找到元素返回true,否則返回false。
下面是有關兩個查找算法的動圖

然後是插值查找,
其實插值查找時類似於二分查找的下面的公式中的第一行就是二分查找的公式,第二行是插值查找的公式。其中mid就是每次所確定的要與目標進行比較的值。而low和high就是每次重新劃分完區域之後重新確定的最大值和最小值。可以看出插值查找通過改進算法,使得改進後的算法在面對分佈較爲均勻的數據時,有較好的效率。
mid=(low+high)/2, 即mid=low+1/2(high-low);
mid=low+(key-a[low])/(a[high]-a[low])
(high-low),
插值查找示意圖

然後是斐波那契查找
相對於折半查找,一般將待比較的key值與第mid=(low+high)/2位置的元素比較,比較結果分三種情況:
1)相等,mid位置的元素即爲所求
2)>,low=mid+1;
3)<,high=mid-1。 斐波那契查找與折半查找很相似,他是根據斐波那契序列的特點對有序表進行分割的。他要求開始表中記錄的個數爲某個斐波那契數小1,及n=F(k)-1;
開始將k值與第F(k-1)位置的記錄進行比較(及mid=low+F(k-1)-1),比較結果也分爲三種
1)相等,mid位置的元素即爲所求
2)>,low=mid+1,k-=2;
說明:low=mid+1說明待查找的元素在[mid+1,high]範圍內,k-=2 說明範圍[mid+1,high]內的元素個數爲n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1個,所以可以遞歸的應用斐波那契查找。
3)<,high=mid-1,k-=1。
說明:low=mid+1說明待查找的元素在[low,mid-1]範圍內,k-=1 說明範圍[low,mid-1]內的元素個數爲F(k-1)-1個,所以可以遞歸 的應用斐波那契查找。
斐波那契查找動態圖

平衡查找樹
這個實際上就是利用構建好的平衡查找樹的性質來進行查找元素。平衡查找樹構建要求右子樹大於左子樹。左子樹小於右子樹。且左右兩子樹高度差絕對值不超過一。
平衡查找樹動態圖展示。

分塊查找
要求將數據分成塊,並且前一塊的任一元素都不能大於後面塊中的元素。所以這個算法應該是建立在數據已經排好序的的基礎上道德。然後將每一塊的最大元素取出然後建立一個索引列表。在將目標元素與索引列表中的元素進行比較,最後找到目標元素所在的分塊,最後再次使用順序或者二分查找進行查找,然後根據查找結果分別返回true或false。
分塊查找圖片展示

哈希查找
首先得將代查數據按照哈希規則存入哈希表中。所謂哈希規則就是將數據通過某種函數,來確定他在表中的位置。例如數據b=a%11,其中a表示數據,b表示數據在表中的位置,但是有時數據之間會產生衝突。例如。1%11=1,12%11=1,這時兩個不同的數據卻通過函數產生了相同的地址,這就是所謂的衝突。解決哈希衝突的辦法有很多,但是其中最常用的就是鏈地址法。就是在數組中儲存的並不是一個個具體的數據,而是鏈表,一旦發生衝突,就將數據插入到鏈表的末尾。在查找的時候也是遵循同樣的規則的,首先將待查元素通過函數求得其目標位置,然後,在遍歷鏈表,如果找到就返回true,如果沒有找到就返回false。
實現代碼。由於代碼太多所以就將其置於下面鏈接之中。
Searching
測試類代碼

package cn.edu.besti.cs1723.DZX2304;



public class Searchingtest {
    public static void main(String[] args) {
    Integer[] a={10,2,8,19,16,18,20,51,};//被查找的數組
       Integer []a1={2,8,10,16,18,19,20,51};
        Searching b=new Searching();


        System.out.println("線性查找查找50的結果:" + Searching.linearSearch(a,0,7,50));
        System.out.println("線性查找查找2的結果:"+Searching.linearSearch(a,0,7,2));
        System.out.println("二分查找50的結果:" + b.BinarySearch1(a1,50,7));
        System.out.println("二分查找2的結果:" + b.BinarySearch1(a1,2,7));
       System.out.println("插值查找能否找到50:" + b.InterpolationSearch(a1, 50));
        System.out.println("插值查找能否找到2:" + b.InterpolationSearch(a1,2));
        System.out.println("斐波那契查找能否找到50:" + Searching.FibonacciSearch(a1,0,11, 50));
        System.out.println("斐波那契查找能否找到2:" + Searching.FibonacciSearch(a1,0,11, 2));
        System.out.println("二叉查找樹查找能否找到50:" + b.BinarySearchTreeSearch(a,0,7,50));
        System.out.println("二叉查找樹查找能否找到2:" + b.BinarySearchTreeSearch(a,0,7,2));
        System.out.println("分塊查找能否找到50:" + Searching.partitionSearch(a,0,7,50));
        System.out.println("分塊查找能否找到2:" + Searching.partitionSearch(a,0,7,2));
        System.out.println("哈希表查找50的結果" +b.Hashsearching(a,50));
        System.out.println("哈希表查找2的結果"+b.Hashsearching(a,2));
    }}

測試結果截圖

實驗四
這個實驗主要是補充老師曾經講過的排序算法,什麼希爾排序堆排序以及二叉樹排序,自己也可以實現排序算法。除了這兩個排序算法之外,我還實現了插入排序和快速排序。
首先向大家介紹一下這幾種算法。
首先是希爾排序,希爾排序的具體算法應用就是首先確定一個步長,從第一個元素開始,比較間隔步長-1個元素的元素,如果不符合與其的排序規則就交換兩個元素。然後逐漸減少步長直至最後步長小於1爲之。
希爾排序動態示意圖

堆排序講解
堆排序是一種比較複雜的排序,它是在二叉平衡樹的基礎上實現的。對分爲兩種,一種是大頂堆,大頂堆的所有子樹的父結點都不小於其孩子結點。而小頂堆的所有子樹的父結點都不大於他的孩子結點。我就簡單介紹一下使用對進行排序的部分,而具體生成堆的部分我就不再贅言了。主要說一下使用堆進行排序的部分。以大頂堆爲例。由於大頂堆的性質,導致最大的元素就是根節點,於是將根節點取出,然後將第一個非葉子結點取出,置爲根節點。然後再次生成堆。依此類推。
堆排序動態展示

二叉樹排序講解
實際上二叉樹排序實際上就是生成二叉查找樹然後通過中序遍歷就會得到排好序的數據。
二叉查找樹生成動態示意圖

插入排序講解
實際上插入排序就是從頭開始遍歷,將未排序的元素與已排序的元素逐個進行比較然後,直接將其插入到適合的位置。

插入排序示意圖

快速排序
從數列中挑出一個元素,稱爲 “基準”(pivot);
重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分區退出之後,該基準就處於數列的中間位置。這個稱爲分區(partition)操作;
遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。
快速排序動態展示

實現代碼。由於代碼太多所以就將其置於下面鏈接之中。
Sorting.java
測試類代碼

package cn.edu.besti.cs1723.DZX2304;

public class SortingTest {
    public static void main(String[] args) {
        Comparable a[] = {10, 25, 2304,  44, 56, 11, 9, 8};
        Sorting b = new Sorting();
       Sorting.selectionSort(a);
        System.out.println("選擇排序後的數組");
        for(Comparable c:a)
        {
            System.out.print(c+" ");
        }
        System.out.println();
        Comparable a2[]= {10, 25, 2304,  44, 56, 11, 9, 8};
         Sorting.insertionSort(a2);
        System.out.println("插入排序後的數組");
        for(Comparable c:a2)
        {
            System.out.print(c+" ");
        }
        System.out.println();
        Comparable a3[]= {10, 25, 2304,  44, 56, 11, 9, 8};
        Sorting.quickSort(a3);
        System.out.println("快速排序後的數組");
        for(Comparable c:a3)
        {
            System.out.print(c+" ");
        }
        System.out.println();
        Comparable a4[]= {10, 25, 2304,  44, 56, 11, 9, 8};
        Sorting.shellSort(a4);
        System.out.println("希爾排序後的數組");
        for(Comparable c:a4)
        {
            System.out.print(c+" ");
        }
        System.out.println();
        Comparable a5[]= {10, 25, 2304,  44, 56, 11, 9, 8};
        Sorting.heapSort(a5);
        System.out.println("堆排序後的數組");
        for(Comparable c:a5)
        {
            System.out.print(c+" ");
        }
        System.out.println();
        Comparable a6[]= {10, 25, 2304,  44, 56, 11, 9, 8};
        Sorting.binarySearchTreeSort(a6);
        System.out.println("二叉查找樹排序後的數組");
        for(Comparable c:a6)
        {
            System.out.print(c+" ");
        }
        Comparable[] a7={10, "a", 2304,  44, "b", 11, 9, 8};
        Sorting.binarySearchTreeSort(a7);
        System.out.println("二叉查找樹排序後的數組");
        for(Comparable c:a7)
        {
            System.out.print(c+" ");
        }
    }
}

測試結果截圖

這裏我放置了一組異常對照。
實驗五
實驗五是真的沒什麼好說的了,就是將代碼在android上實現

代碼調試時遇見的問題

問題:爲什麼斐波那契查找的結果和預期結果不一致
解決方案:後來發現是在進行斐波那契查找時沒有使用已經排序好的數組。

其他

 這次實驗又是一次複習實驗,經過多次的磨練相信我們對各種短髮的理解會更加深入,對各種代碼的運用會更加熟練。我們會不斷地成長進步直至自己能開拓出一片屬於自己的天空。

參考資料

1.藍墨雲班課
2.java軟件結構與數據結構

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章