Java进阶——数组中常见的算法

8 篇文章 0 订阅

排序算法:

  • 冒泡排序算法
  • 选择排序算法

查找算法:

  • 二分法查找

以上算法在以后的java实际开发中我们不需要使用的。
因为java已经封装好了,直接调用就行
只不过以后面试的时候,可能会有机会碰上

算法实际上在java中不需要精通,因为java中已经封装好了,要排序就调用方法就行。例如:java中提供了一个数组工具类:
java.util.Arrays
Arrays是一个工具类。其中有一个sort()方法,可以排序。静态方法,直接使用类名调用就行。

冒泡排序

参与比较的数据:9 8 10 7 6 0 11
第1次循环:
8 9 10 7 6 0 11 (第1次比较:交换)
8 9 10 7 6 0 11 (第2次比较:不交换)
8 9 7 10 6 0 11 (第3次比较:交换)
8 9 7 6 10 0 11 (第4次比较:交换)
8 9 7 6 0 10 11 (第5次比较:交换)
8 9 7 6 0 10 11 (第6次比较:不交换)
最终冒出的最大数据在右边:11

参与比较的数据:8 9 7 6 0 10
第2次循环:
8 9 7 6 0 10(第1次比较:不交换)
8 7 9 6 0 10(第2次比较:交换)
8 7 6 9 0 10(第3次比较:交换)
8 7 6 0 9 10(第4次比较:交换)
8 7 6 0 9 10(第5次比较:不交换)

参与比较的数据:8 7 6 0 9
第3次循环:
7 8 6 0 9(第1次比较:交换)
7 6 8 0 9(第2次比较:交换)
7 6 0 8 9(第3次比较:交换)
7 6 0 8 9(第4次比较:不交换)

参与比较的数据:7 6 0 8
第4次循环:
6 7 0 8(第1次比较:交换)
6 0 7 8(第2次比较:交换)
6 0 7 8(第3次比较:不交换)

参与比较的数据:6 0 7
第5次循环:
0 6 7(第1次比较:交换)
0 6 7(第2次比较:不交换)

参与比较的数据:0 6
第6次循环:
0 6 (第1次比较:不交换)

    for(int i = 6; i > 0; i--){ // 6次
	//7条数据比6次
	//6条数据比5次
	//5条数据比4次
	//4条数据比3次
	//3条数据比2次
	//2条数据比1次
	for(int j = 0; j < i; j++){
	
	   }
     }

冒泡排序算法实例分析:

  • 每一次循环节结束之后,都要找出最大的数据,放到参与比较的这堆数据的最右边(冒出最大的那个气泡)

  • 核心:
    拿着左边的数字和右边的数字对比,当左边 > 右边的时候,交换位置

      原始数据:
      3, 2, 7, 6, 8
      第1次循环:(最大的跑到最右边。)
      2, 3, 7, 6, 8 (3和2比较,2 < 3,所以2和3交换位置)
      2, 3, 7, 6, 8 (虽然不需要交换位置:但是3和7还是需要比较一次。)
      2, 3, 6, 7, 8 (7和6交换位置)
      2, 3, 6, 7, 8 (虽然不需要交换位置:但是3和7还是需要比较一次。)
      
      经过第1次循环,此时剩下参与比较的数据:2, 3, 6, 7
      第2次循环:
      2, 3, 6, 7 (2和3比较,不需要交换位置)
      2, 3, 6, 7 (3和6比较,不需要交换位置)
      2, 3, 6, 7 (6和7比较,不需要交换位置)
      
      经过第2次循环,此时剩下参与比较的数据:2, 3, 6
      第3次循环:
      2, 3, 6 (2和3比较,不需要交换位置)
      2, 3, 6 (3和6比较,不需要交换位置)
      
      经过第3次循环,此时剩下参与比较的数据:2, 3
      第4次循环:
      2, 3 (2和3比较,不需要交换位置)
    
public class BubbleSort {
    public static void main(String[] args) {

        // 这是int类型的数组对象
        //int[] arr = {3, 2, 7, 6, 8};
        int[] arr = {9, 8, 10, 7, 6, 0, 11};

        // 经过冒泡排序算法对以上数组中元素进行排序
        // 冒泡排序算法的核心是什么?

        // 7条数据,循环6次。以下的代码可以循环6次。
        /*
        for(int i = 0; i < arr.length-1; i++){
            System.out.println(i);
        }
         */

        // 7条数据,循环6次。以下的代码可以循环6次。(冒泡排序的外层循环采用这种方式)
        //int count = 0;
        int count2 = 0;
        for(int i = arr.length-1; i > 0; i--){
            for(int j = 0; j < i; j++){
                // 不管是否需要交换位置,总之是要比较一次的。
                //count++;
                if(arr[j] > arr[j+1]){
                    // 交换位置。
                    // arr[j] 和 arr[j+1] 交换
                    int temp;
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    count2++;
                }
            }
        }

        //System.out.println("比较次数:" + count);
        System.out.println("交换位置的次数:" + count2); //13
        // 输出结果
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

选择排序:
选择排序比冒泡排序的效率高
高在交换位置的次数上
选择排序的交换位置是有意义的

循环一次,然后找出参加比较的这堆数据中最小的,拿着这个最小的值和最前面的数据“交换位置”

参与比较的数据:3 1 6 2 5 (这一堆参加比较的数据中最左边的元素下标是0)
第1次循环之后的结果是:
1 3 6 2 5 

 参与比较的数据:3 6 2 5 (这一堆参加比较的数据中最左边的元素下标是1)
第2次循环之后的结果是:
2 6 3 5 

参与比较的数据:6 3 5 (这一堆参加比较的数据中最左边的元素下标是2)
第3次循环之后的结果是:
3 6 5 

参与比较的数据:6 5 (这一堆参加比较的数据中最左边的元素下标是3)
第4次循环之后的结果是:
5 6

注意:5条数据,循环4次。

选择排序算法实例分析:

  • 每一次从这堆“参与比较的数据当中”找出最小值,拿着这个最小值和“参与比较的这堆最前面的元素”交换位置。

  • 选择排序比冒泡排序好在:每一次的交换位置都是有意义的

  • 关键点:
    选择排序中的关键在于,你怎么找出一堆数据中最小的。

     3 2 6 1 5
      假设:
          第一个3是最小的。
          3和2比较,发现2更小,所以此时最小的是2.
          
          继续拿着2往下比对,2和6比较,2仍然是最小的。
          继续拿着2往下比对,2和1比对,发现1更小,所以此时最小的是1.
          继续拿着1往下比对,1和5比对,发现1还是小的,所以1就是最小的。
    
          拿着1和最左边的3交换位置。
     2 6 3 5
     假设:
      第一个2是最小的。
      ...
    
    6 3 5
      假设6是最小的:
      6和3比对,发现3更小,所以此时最小的是3.
      ...
    
public class SelectSort {
    public static void main(String[] args) {

        //int[] arr = {3, 1, 6, 2, 5};
        int[] arr = {9, 8, 10, 7, 6, 0, 11};

        int count = 0;
        int count2 = 0;

        // 选择排序
        // 5条数据循环4次。(外层循环4次。)
        for(int i = 0; i < arr.length - 1; i++){
            // i的值是0 1 2 3
            // i正好是“参加比较的这堆数据中”最左边那个元素的下标。
            //System.out.println(i);
            // i是一个参与比较的这堆数据中的起点下标。
            // 假设起点i下标位置上的元素是最小的。
            int min = i;
            for(int j = i+1; j < arr.length; j++){
                count++;
                //System.out.println("===>" + j);
                if(arr[j] < arr[min]){
                    min = j; //最小值的元素下标是j
                }
            }

            // 当i和min相等时,表示最初猜测是对的。
            // 当i和min不相等时,表示最初猜测是错的,有比这个元素更小的元素,
            // 需要拿着这个更小的元素和最左边的元素交换位置。
            if(min != i){
                // 表示存在更小的数据
                // arr[min] 最小的数据
                // arr[i] 最前面的数据
                int temp;
                temp = arr[min];
                arr[min] = arr[i];
                arr[i] = temp;
                count2++;
            }
        }

        // 冒泡排序和选择排序实际上比较的次数没变。
        // 交换位置的次数减少了。
        System.out.println("比较次数" + count); // 21
        System.out.println("交换次数:" + count2); // 5

        // 排序之后遍历
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

//1 2 3 4 5
//假设1是最小的,结果1确实是最小的,就不需要交换位置。

数组的元素查找

  • 数组元素查找有两种方式:
    第一种方式:一个一个挨着找,直到找到为止。
    第二种方式:二分法查找(算法),这个效率较高。
public class ArraySearch {
    public static void main(String[] args) {
        // 这个例子演示一下第一种方式
        int[] arr = {4,5,5,87,8};

        // 需求:找出87的下标。如果没有返回-1
        // 一个一个挨着找。
        /*
        for(int i = 0; i < arr.length;i ++){
            if(arr[i] == 87){
                System.out.println("87元素的下标是:" + i);
                return;
            }
        }
        // 程序执行到此处,表示没有87
        System.out.println("87不存在该元素!");
        */

        // 最好以上的程序封装一个方法,思考:传什么参数?返回什么值?
        // 传什么:第一个参数是数组,第二个参数是被查找的元素。
        // 返回值:返回被查找的这个元素的下标。如果找不到返回-1.
        int index = arraySearch(arr, 5);
        System.out.println(index == -1 ? "该元素不存在" : "该元素下标是:" + index);
    }

    /**
     * 从数组中检索某个元素的下标(返回的是第一个元素的下标。)
     * @param arr 被检索的数组
     * @param ele 被检索的元素
     * @return 大于等于0的数表示元素的下标,-1表示该元素不存在
     */
    public static int arraySearch(int[] arr, int ele) {
        for (int i = 0; i < arr.length; i++) {
            if(ele == arr[i]){
                return i;
            }
        }
        return -1;
    }
}

  • 数组工具类:自己写的。不是SUN的。

  • 关于查找算法中的:二分法查找。

      10(下标0) 11 12 13 14 15 16 17 18 19 20(下标10)   arr数组。
    
      通过二分法查找,找出18这个元素的下标:
          (0 + 10) / 2 --> 中间元素的下标: 5
    
      拿着中间这个元素和目标要查找的元素进行对比:
          中间元素是:arr[5] --> 15
          15 < 18(被查找的元素)
          被查找的元素18在目前中间元素15的右边。
          所以开始元素的下标从0变成 5 + 1.
    
      再重新计算一个中间元素的下标:
          开始下标是:5 + 1
          结束下标是:10
          (6 + 10) / 2 --> 8
    
      8下标对应的元素arr[8]是18
          找到的中间元素正好和被找的的元素18相等,表示找到了:下标为8
    
      二分法查找的终止条件:一直折半,直到中间的那个元素恰好是被查找的元素。
    
  • 二分法查找算法是基于排序的基础之上。(没有排序的数据是无法查找的。)

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

        int[] arr = {100,200,230,235,600,1000,2000,9999};

        // 找出arr这个数组中200所在的下标。
        // 调用方法
        int index = binarySearch(arr, 230);
        System.out.println(index == -1 ? "该元素不存在!" : "该元素下标" + index);
    }

    /**
     * 从数组中查找目标元素的下标。
     * @param arr 被查找的数组(这个必须是已经排序的。)
     * @param dest 目标元素
     * @return -1表示该元素不存在,其它表示返回该元素的下标。
     */
    public static int binarySearch(int[] arr, int dest) {
        // 开始下标
        int begin = 0;
        // 结束下标
        int end = arr.length - 1;
        // 开始元素的下标只要在结束元素下标的左边,就有机会继续循环。
        while(begin <= end) {
            // 中间元素下标
            int mid = (begin + end) / 2;
            if (arr[mid] == dest) {
                return mid;
            } else if (arr[mid] < dest) {
                // 目标在“中间”的右边
                // 开始元素下标需要发生变化(开始元素的下标需要重新赋值)
                begin = mid + 1; // 一直增
            } else {
                // arr[mid] > dest
                // 目标在“中间”的左边
                // 修改结束元素的下标
                end = mid - 1; // 一直减
            }
        }
        return -1;
    }

}

  • 介绍一下java.util.Arrays工具类。
    所有方法都是静态的,直接用类名调用
    主要使用的是两个方法:
    二分法查找,排序
    以后要看文档,不要死记硬背。
import java.util.Arrays;

/**
 * 好消息:
 *  SUN公司已经为我们程序员写好了一个数组工具类。
 *  java.util.Arrays;
 */
public class ArraysTest02 {
    public static void main(String[] args) {
        // java.util.Arrays; 工具类中有哪些方法,我们开发的时候要参考API帮助文档
        // 不要死记硬背。
        int[] arr = {3,6,4,5,12,1,2,32,5,5};
        // 排序
        Arrays.sort(arr);
        // 输出
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
        // 二分法查找(建立在排序基础之上。)
        int index = Arrays.binarySearch(arr, 5);

        System.out.println(index == -1 ? "该元素不存在" : "该元素下标是:" + index);
    }
}

下一篇:String

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值