实验三 查找和排序 实验报告 20162305

实验三 查找和排序 实验报告 20162305

一、查找和排序-1

1、实验要求

  • 完成教材P302 Searching.Java ,P305 Sorting.java中方法的测试
    不少于10个测试用例,提交测试用例设计情况(正常,异常,边界,正序,逆序),用例数据中要包含自己学号的后四位
    提交运行结果图(可多张)

2、实验过程

  • 这个实验是在教材上的代码基础上实现的。教材中给了Searching类和Sorting类,测试这两个代码中给出的方法。查找类中包含了线性查找和二分查找两种方法。排序类中包含了像选择排序,插入排序,冒泡排序等等方法。这些方法在之前的学习中已经了解过,设计测试类,在两个类的测试类中一一实现这些方法。

3、实验成果截图

二、查找和排序-2

1、实验要求

  • 重构你的代码
    把Sorting.java Searching.java放入 cn.edu.besti.cs1623.(姓名首字母+四位学号) 包中
    把测试代码放test包中
    重新编译,运行代码,提交编译,运行的截图(IDEA,命令行两种)

2、实验过程

  • 按照实验要求,我在IDEA中新建了一个package包,命名为cn.edu.besti.cs162305.lyx。在IDEA中重构代码,将代码加入相应的文件夹中,然后运行,在IDEA中可以实现。不过打开命令行后编译成功后,命令行中显示代码编译没问题,不过结果却没能显示出来。

3、实验成果截图

  • 命令行

  • IDEA

  • 1、

  • 2、

三、查找和排序-3

1、实验要求

  • 参考 查找算法博客 在Searching中补充查找算法并测试
    提交运行结果截图

2、实验过程

  • 在这篇学习博客中,一共提到了7种查找的方法,分别是顺序查找、二分查找、插值查找、斐波那契查找、树表查找、分块查找和哈希查找。其中的顺序查找和二分查找在教材的代码中都已经实现,下面介绍其他五种查找方法
(1)、插值查找
  • 插值查找是基于二分查找算法,将查找点的选择改进为自适应选择,可以提高查找效率。当然,差值查找也属于有序查找。对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。

  • 插值查找在实际使用时,一般要满足两个假设条件:
    (1)每一次对数据的访问与通常的指令相比,费用都是相当昂贵的。例如,待查找的表一定是在磁盘而非内存中,因而每一次比较都
    要进行磁盘访问。
    (2)数据不仅是已被排好序的,而且呈现均匀分布特征。

  • 实验代码


public static Comparable InsertionSearch(int[] num, int key) {
        //定义三个判断数
        int low, high, mid;
        low = 0;
        high = num.length - 1;
        while (low <= high) {
            // mid = (low + high) / 2;
            //二分查找
            mid = low + (high - low) * (key - num[low]) / (num[high] - num[low]); // 插值查找
            if (key < num[mid]) high = mid - 1;
            else if (key > num[mid]) low = mid + 1;
            else
                // 如果等于则直接还回下标值
                return mid;
        }
        return -1;
    }

(2)、斐波那契查找
  • 斐波那契查找也是二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,提高查找效率。同样地,斐波那契查找也属于一种有序查找算法。
      

  • 相对于折半查找,一般将待比较的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;
    3、high=mid-1,k-=1。

  • 说明: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个,所以可以递归的应用斐波那契查找。

  • 实验代码


 private int max_size = 20;//斐波那契数组的长度

    /*构造一个斐波那契数组*/
    public 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];
    }

    /*定义斐波那契查找法*/
    int FibonacciSearch(int[] a, int key)  //a为要查找的数组,n为要查找的数组长度,key为要查找的关键字
    {
        int low = 0;
        int high = a.length - 1;

        int[] F = new int[max_size];
        Fibonacci(F);//构造一个斐波那契数组F

        int k = 0;
        while (a.length > F[k] - 1)//计算n位于斐波那契数列的位置
            ++k;
        //将数组a扩展到F[k]-1的长度

        int[] temp = new int[F[k] - 1];
        
        for (int i = 0; i < a.length; i++)
            temp[i] = a[i];


        for (int i = a.length; i < F[k] - 1; ++i)
            temp[i] = a[a.length - 1];

        while (low <= high) {
            int mid = low + F[k - 1] - 1;
            if (key < temp[mid]) {
                high = mid - 1;
                k -= 1;
            } else if (key > temp[mid]) {
                low = mid + 1;
                k -= 2;
            } else {
                if (mid < a.length) return mid; //若相等则说明mid即为查找到的位置
                else return a.length - 1; //若mid>=n则说明是扩展的数值,返回n-1
            }
        }

        return 0;
    }

(3)、二叉树查找
  • 实现这个方法相对简单。我们可以利用之前实现过的二叉查找树来实现查找功能。定义一个二叉查找树,遍历整个数,利用二叉查找树中的find方法来查找目标值,从而实现查找功能。
  • 实验代码

 public int BinaryTreeSearch(int[] a, int key) {
        LinkedBinarySearchTree linkedBinarySearchTree = new LinkedBinarySearchTree();
        //添加元素进入查找树
        for (int i = 0; i < a.length; i++)
            linkedBinarySearchTree.add(a[i]);
        //利用find方法查找值
        if (linkedBinarySearchTree.find(key) == null) return Integer.parseInt(null);
        else return key;

    }

(4)、分块查找
  • 分块查找又称索引顺序查找,它是顺序查找的一种改进方法。将n个数据元素"按块有序"划分为m块(m ≤ n)。每一块中的结点不必有序,但块与块之间必须"按块有序";即第1块中任一元素的关键字都必须小于第2块中任一元素的关键字;而第2块中任一元素又都必须小于第3块中的任一元素,以此类推。

  • 实验代码


public static int blockSearch(int[] index, int[] a, int key, int m) {  
    // 在序列a数组中,用分块查找方法查找关键字为key的记录  
    // 1.在index[ ] 中折半查找,确定要查找的key属于哪个块中  
    int i = binarySearch(index, key);  
    if (i >= 0) {  
        int j = i > 0 ? i * m : i;  
        int length = (i + 1) * m;  
        // 在确定的块中用顺序查找方法查找key  
        for (int k = j; k < length; k++) {  
            if (key == a[k]) {  
                System.out.println("查询成功");  
                return k;  
            }  
        }  
    }  
  
    return -1;  
}  

(5)、哈希查找
  • 利用Java中的HashMap类实现查找功能。其实现过程和二叉查找树实现查找类似。利用HashMap中的put方法将元素添加入表中,再用containKey方法判断有无目标元素,从而实现查找功能。
  • 实验代码

    public int HashSearch(int[] a , int key){
        HashMap<Integer,Integer> hashMap = new HashMap();
        for(int i = 0;i <a.length;i++)
            hashMap.put(i,a[i]);
        if(hashMap.containsKey(key) == true)
            return key;
        else
            return 0;
    }

3、实验成果截图

四、查找和排序-4

1、实验要求

  • 补充实现课上讲过的排序方法:希尔排序,堆排序,桶排序,二叉树排序等。测试实现的算法(正常,异常,边界),提交运行结果截图,推送相关代码到码云上

2、实验过程

(1)、希尔排序
  • 希尔排序的思想是先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 =1( < …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
  • 实验代码

 public static void shellSort(int[] data) {
        int j = 0;
        int temp = 0;
        for (int a = data.length / 2; a > 0; a /= 2) {
            for (int i = a; i < data.length; i++) {
                temp = data[i];
                for (j = i - a; j >= 0; j -= a) {
                    if (temp < data[j]) {
                        data[j + a] = data[j];
                    } else {
                        break;
                    }
                }
                data[j + a] = temp;
            }
            for (int i = 0; i < data.length; i++)
                System.out.print(data[i] + " ");
        }
    }

(2)、堆排序
  • 利用之前完成的LinkedMaxHeap实现排序功能。根据最大堆的性质依次返回值并打印出来,实现排序功能
  • 实验代码

 public void heapSort(Comparable[] data){
        LinkedMaxHeap linkedMaxHeap = new LinkedMaxHeap();
        for (int i = 0; i < data.length; i++)
            linkedMaxHeap.add(data[i]);
        for (int i = data.length-1; i>=0;i--)
            data[i]=linkedMaxHeap.removeMax();
    }


(3)、桶排序
  • 桶排序的基本思想是将一个数据表分割成许多buckets,然后每个bucket各自排序,或用不同的排序算法,或者递归的使用bucket sort算法。基本流程是先建立一堆buckets,再遍历原始数组,并将数据放入到各自的buckets当中,对非空的buckets进行排序; 按照顺序遍历这些buckets并放回到原始数组中即可构成排序后的数组。

  • 实验代码


 public static void bucketSort(int[] arr){

        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for(int i = 0; i < arr.length; i++){
            max = Math.max(max, arr[i]);
            min = Math.min(min, arr[i]);
        }

        //桶数
        int bucketNum = (max - min) / arr.length + 1;
        ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
        for(int i = 0; i < bucketNum; i++){
            bucketArr.add(new ArrayList<Integer>());
        }

        //将每个元素放入桶
        for(int i = 0; i < arr.length; i++){
            int num = (arr[i] - min) / (arr.length);
            bucketArr.get(num).add(arr[i]);
        }

        //对每个桶进行排序
        for(int i = 0; i < bucketArr.size(); i++){
            Collections.sort(bucketArr.get(i));
        }


    }


(4)、二叉树排序
  • 利用二叉查找树的性质实现排序功能,利用类中findMin()方法将数组中的元素排序。
  • 实验代码

public static void BinaryTreeSort(Comparable[] a){
        LinkedBinarySearchTree linkedBinaryTree = new LinkedBinarySearchTree();
        for (int i = 0; i < a.length; i++)
            linkedBinaryTree.add(a[i]);
        for (int i = 0; i < a.length; i++) {
            a[i] = linkedBinaryTree.findMin();
            linkedBinaryTree.remove(linkedBinaryTree.findMin());
        }
    }

3、实验成果截图

posted @ 2017-11-12 18:24  20162305李昱兴  阅读(404)  评论(0编辑  收藏