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实现
折半查找的平均查找次数分析
二分查找的平均查找长度详解

返回目录

相关文章
相关标签/搜索