JavaEE 学习笔记 第三章 数组 7

第三章 数组



3.5 算法的5大特征 

        说明:满足确定性的算法也称:确定性算法。现在人们也关注更广泛的概念,例如考虑各种非确定性的算法,如并行算法,概率算法等。另外,人们也关注并不要求终止的计算描述,这种描述有时被称为过程(procedure)。


3.6 数组元素的排序算法

3.6.1 排序算法的概念

        排序:假设含有n个记录的序列为{R1,R2,...,Rn},其相关的关键字序列{K1,K2,...,Kn}。将这些记录重新排序为{Ri1,Ri2,...,Rin},使得相应的关键字值满足条件Ki1<=Ki2<=...<=Kin,这样的一种操作称为排序。通常来说,排序的目的是快速查找。


3.6.2 衡量排序算法的优劣

        时间复杂度:分析关键字的比较次数和记录的移动次数

        空间复杂度:分析排序算法中需要多少辅助内存

        稳定性:若两个记录A和B的关键字值相等,但排序后A,B的先后次序保持不变,则称这种排序算法是最稳定的


3.6.3 排序算法分类:内部排序外部排序

        内部排序:整个排序过程不需要借助于外部存储器(如磁盘等),所有排序操作都在内存中完成。

        外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器(如磁盘)。外部排序最常见的是多路归并排序。可以认为外部排序是由多次内部排序组成的。


3.6.4 十大内部排序算法

                选择排序:直接选择排序,堆排序

                交换排序:冒泡排序快速排序

                插入排序:直接插入排序,折半插入排序,Shell排序

                归并排序,桶式排序,基数排序


3.6.5 冒泡排序

        介绍:冒泡排序的原理非常简单,它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

        排序思想

                ①.比较相邻的元素。如果第一个比第二个大(升序),就交换它们两个。

                ②.对每一对相邻元素做同样的操作,从开始的第一对到结束的最后一对,全部交换操作完成之后最后面的元素会是最大的元素。

                ③.针对所有的元素重复以上的步骤,除了最后一个。       

                ④.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止。

public class ArrayTest {
    public static void main(String[] args) {
        //初始化一个10位数组
        int arr[] = {22, 33, 11, 23, 76, 348, 89, 2, 54, 211};
        //冒泡排序
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
    }
}

3.6.6 快速排序

        介绍:快速排序通常明显比同为O(nlogn)的其他算法更快,因此常被采用,而且快速排序采用了分治法的思想,所以在很多笔试面试中能常看到快排的影子。可见掌握快排的重要性。

        快速排序(Quick Sort)由图灵奖获得者Tony Hoare发明,被列为20世纪十大算法之一,是迄今为止所有内排序算法中速度最快的一种。冒泡排序的升级版,交换排序的一种。快速排序的时间复杂度为O(nlog(n))。

package ca.demo03;

public class ArrayTest {
    public static void quickSort(int[] arr, int low, int high) {
        int i, j, temp, t;
        if (low > high) {
            return;
        }
        i = low;
        j = high;
        //temp就是基准位
        temp = arr[low];

        while (i < j) {
            //先看右边,依次往左递减
            while (temp <= arr[j] && i < j) {
                j--;
            }
            //再看左边,依次往右递增
            while (temp >= arr[i] && i < j) {
                i++;
            }
            //如果满足条件则交换
            if (i < j) {
                t = arr[j];
                arr[j] = arr[i];
                arr[i] = t;
            }

        }
        //最后将基准为与i和j相等位置的数字交换
        arr[low] = arr[i];
        arr[i] = temp;
        //递归调用左半数组
        quickSort(arr, low, j - 1);
        //递归调用右半数组
        quickSort(arr, j + 1, high);
    }

    public static void main(String[] args) {
        int[] arr = {10, 7, 2, 4, 7, 62, 3, 4, 2, 1, 8, 9, 19};
        quickSort(arr, 0, arr.length - 1);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
    }
}


3.6.7 排序算法性能对比

        ①.从平均时间而言:快速排序最佳。但在最坏情况下时间性能不如堆排序和归并排序。

        ②.从算法简单性看:由于直接选择排序,直接插入排序和冒泡排序的算法比较简单,将其认为简单算法。对于Shell排序,堆排序,快速排序和归并排序算法,其算法比较复杂,认为是复杂排序。

        ③.从稳定性看:直接插入排序,冒泡排序和归并排序是稳定的,而直接选择排序,快速排序,Shell排序和堆排序是不稳定排序。

        ④.从待排序的记录数n的大小看,n较小时,宜采用简单排序,而较大时宜采用改进排序。


3.6.8 排序算法的选择

        ①.若n较小(如n≤50),可采用直接插入或直接选择排序。当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插入,应该直接选择排序为宜。

        ②.若文件初始状态基本有序(指正序),则应选用直接插入,冒泡或随机的快速排序为宜。

        ③.若n较大时,则应采用时间复杂度为O(nlgn)的排序方法:快速排序,堆排序或归并排序。


3.7 Arrays工具类的使用

        java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法。

import java.util.Arrays;

public class ArrayTest {
    public static void main(String[] args) {

        //判断两个数组是否相等
        int[] arr1 = {1,2,3,4};
        int[] arr2 = {1,2,3,4};
        if (Arrays.equals(arr1, arr2)) {
            System.out.println("数组arr1与数组arr2相等");
        }else {
            System.out.println("数组arr1与数组arr2不相等");
        }

        //输出数组信息
        String string = Arrays.toString(arr1);
        System.out.println(string);

        //将指定值填充到数组之中
        Arrays.fill(arr1,5);
        System.out.println(Arrays.toString(arr1));

        //对数组进行排序
        int[] arr3 = {2,3,6,1,0,7};
        Arrays.sort(arr3);
        System.out.println(Arrays.toString(arr3));

        //对排序后的数组进行二分检索指定的值
        int i = Arrays.binarySearch(arr3, 6);
        System.out.println(i);
    }
}


3.8 数组使用中常见异常

        数组脚标越界异常:数组的索引中不存在需要访问的索引位置。

        空指针异常:访问空数组,访问不存在的数组。


练习

        1.使用冒泡排序,实现如下的数组从小到大排序

                int[ ] arr =  new int[ ]{34,5,22,-98,6,-76,0,-3}

        2.如何反转上面的数组。请代码实现

        3.复制上述数组,得到一个新的数组

        4.使用线性查找,从上述数组中查找22是否存在。存在,返回所在位置的索引。不存在,输出提示信息

        5.数组中常见的异常有哪些?请举例说明


点击进入 :下一节:JavaEE 学习笔记 第四章 面向对象(上)8

猜你喜欢

转载自blog.csdn.net/woailuo8214/article/details/121231707