打怪升级之小白的大数据之旅(七)<Java基础语法之数组的排序算法>

打怪升级之小白的大数据之旅(七)

Java基础语法之数组的排序算法


目录

打怪升级之小白的大数据之旅(七)

上次回顾

 

数组排序算法

数组的反转

数组的扩容

数组元素的插入

数组元素的删除

数组的二分查找

数组的直接选择排序

数组的折半插入排序

数组工具类

排序算法知识扩展

总结



上次回顾

上一期我们讲完了Java的数组的第一部分,数组的基本概念,本章开始分享数据的一些基础算法,由浅入深,下一章,会提到几个常见的排序,好了,开始进入正题


数组排序算法

数组的反转

  • 将数组内的元素进行倒置
  • 反转方式一:借助新数组进行反转

    示例代码:
    //反转数组1:
    public class ReverseArry {
        public static void main(String[] args){
            int[] arr = {1,2,3,4,5,6,7,8,9};
    //(1)先创建一个新数组
            int[] newArr = new int[arr.length];
    //(2)复制元素
            int len = arr.length;
            for(int i=0; i<newArr.length; i++){
                newArr[i] = arr[len -1 - i];
            }
    //(3)舍弃旧的,让arr指向新数组
            arr = newArr;//这里把新数组的首地址赋值给了arr
    //(4)遍历显示
            for(int i=0; i<arr.length; i++){
                System.out.println(arr[i]);
            }
        }
    

    缺点: 需要重新定义一个数组,浪费额外内存空间,原数组需要垃圾回收

  • 反转方式二:首位对应位置交换(数组对称位置的元素交换)

    示例代码:
    //反转数组2:
    public class ReverseArry {
        public static void main(String[] args){
            int[] arr = {1,2,3,4,5,6,7,8,9};
    //(1)计算要交换的次数:  次数 = arr.length/2
            //(2)首尾对称位置交换
            for(int i=0; i<arr.length/2; i++){//循环的次数就是交换的次数
                int temp = arr[i];
                arr[i] = arr[arr.length-1-i];
                arr[arr.length-1-i] = temp;
            }
    //(3)遍历显示
            for(int i=0; i<arr.length; i++){
                System.out.println(arr[i]);
            }
        }
    
  • 反转方式三:左右对称位置交换,然后再首尾交换


    示例代码:
    //反转数组2:
    public class ReverseArry {
        public static void main(String[] args){
            int[] arr = {1,2,3,4,5,6,7,8,9};
    //左右对称位置交换
            for(int left=0,right=arr.length-1; left<right; left++,right--){
                //首  与  尾交换
                int temp = arr[left];
                arr[left] = arr[right];
                arr[right] = temp;
            }
    //(3)遍历显示
            for(int i=0; i<arr.length; i++){
                System.out.println(arr[i]);
            }
        }
    }
    

     

数组的扩容

  • 当原数组长度不够时,就需要进行数组扩容
  • 数组扩容只是创建一个新数组,并将原数组元素复制进新数组中
  • 原数组被垃圾回收了
  • 示例代码:
    //数组扩容:
    public class ExpansionArry {
        public static void main(String[] args){
            int[] arr = {1,2,3,4,5,6,7,8,9};
             //如果要把arr数组扩容,增加1个位置
            //(1)先创建一个新数组,它的长度 = 旧数组的长度+1,或者也可以扩大为原来数组长度的1.5倍,2倍等
            int[] newArr = new int[arr.length + 1];
            //(2)复制元素
            //注意:i<arr.length   因位arr比newArr短,避免下标越界
            for(int i=0; i<arr.length; i++){
                newArr[i] = arr[i];
            }
            //(3)把新元素添加到newArr的最后
            newArr[newArr.length-1] = 10;
            //(4)如果下面继续使用arr,可以让arr指向新数组
            arr = newArr;
            //(4)遍历显示
            for(int i=0; i<arr.length; i++){
                System.out.println(arr[i]);
        }
    }

    注意事项:
    (1)至于新数组的长度定义多少合适,看实际情况,如果新增的元素个数确定,那么可以增加指定长度,如果新增元素个数不确定,那么可以扩容为原来的1.5倍、2倍等
    (2)数组扩容太多会造成浪费,太少会导致频繁扩容,效率低下

 

数组元素的插入

  • 在原数组的某个位置中[index]插入一个元素
  • 示例代码:
    //数组插入:
    public class InsertArry {
        public static void main(String[] args){
            //在索引index位置插入一个整数5
            int index=1;
            int[] arr={1,2,3,4};
            //创建新数组扩容
            int[] newArr=new int[5];
            //复制数组
            for (int i = 0; i < arr.length; i++) {
                newArr[i]=arr[i];
            }
            //向后移动插入位置之后的每个元素
            for (int i = newArr.length - 1; i >= 0; i--) {
                if(i>index){
                    newArr[i]=newArr[i-1];
                }
            }
            //插入新元素
            newArr[index]=5;
            arr=newArr;
            //遍历显示
            for(int i=0; i<arr.length; i++){
                System.out.println(arr[i]);
            }
            }
        }
    
    数组插入还有两种特殊的情况!
  • 数组插入的特殊情况一:
    • 原数组未满(暂时)
    • 示例代码:
      //数组插入1:
      public class InsertArry {
          public static void main(String[] args){
              /*
              * 目前数组的长度是5,而数组的实际元素个数是3,
              * 如果此时需要在“张三”和“李四”之间插入一个“赵六”,
              * 即在[index=1]的位置插入“赵六”,需要怎么做呢?
              * */
              String[] arr = new String[5];
              arr[0]="张三";
              arr[1]="李四";
              arr[2]="王五";
              //(1)移动2个元素,需要移动的起始元素下标是[1],它需要移动到[2],一共一共2个
              System.arraycopy(arr,1,arr,2,2);
              //(2)插入新元素
              arr[1]="赵六";
              //(3)遍历显示
              for(int i=0; i<arr.length; i++){
                  System.out.println(arr[i]);
                  }
            }
      }
  • 数组插入的特殊情况二:
    • 原数组已满(暂时)
    • 示例代码:
      //数组插入2:
      public class InsertArry {
          public static void main(String[] args){
              /*
              * 目前数组的长度是3,而数组的实际元素个数是3,
              * 如果此时需要在“张三”和“李四”之间插入一个“赵六”,
              * 即在[index=1]的位置插入“赵六”,需要怎么做呢?
              * */
              String[] arr = new String[3];
              arr[0]="张三";
              arr[1]="李四";
              arr[2]="王五";
              //(1)先扩容
              String[] newArr = new String[4];
              for(int i=0; i<arr.length; i++){
                  newArr[i] = arr[i];
              }
              arr=newArr;
              //(2)移动2个元素,需要移动的起始元素下标是[1],它需要移动到[2],一共2个
              System.arraycopy(arr,1,arr,2,2);
              //(3)插入新元素
              arr[1]="赵六";
              //(4)遍历显示
              for(int i=0; i<arr.length; i++){
                  System.out.println(arr[i]);
                  }
            }
      }

数组元素的删除

  • 根据索引位置删除元素(逻辑删除)
  • 示例代码1:
    //数组删除2:
    public class DeleteArry {
        public static void main(String[] args){
            //删除索引1位置的元素
            int[] arr={1,2,3,4,5};
            //把删除位置之后的每个元素向前移动
            for (int i = 0; i < arr.length-1; i++) {
                if(i>=1){
                    arr[i]=arr[i+1];
                }
            }
            //根据实际业务需求,把最后位置的元素修改为某个值
            arr[arr.length-1]=0;
            //遍历显示
            for(int i=0; i<arr.length; i++){
                System.out.println(arr[i]);
             }
         }
    }
  • 示例代码2:
    //数组删除2:
    public class DeleteArry {
        public static void main(String[] args){
            /*
            * 现在需要删除“李四”,我们又不希望数组中间空着元素,该如何处理呢?
            * */
            String[] arr = new String[3];
            arr[0]="张三";
            arr[1]="李四";
            arr[2]="王五";
            //(1)移动元素,需要移动元素的起始下标[2],该元素需要移动到[1],一共需要移动1个元素
            System.arraycopy(arr,2,arr,1,1);
            //(2)因为数组元素整体往左移动,这里本质上是复制,原来最后一个元素需要置空
            arr[2]=null;
        }
    }

数组的二分查找

  • 二分查找,也称之为折半查找,前提必须是有序的数组
  • 数组元素必须支持比较大小,并且数组中的元素已经按大小排好序
    示例代码:
    class BinarySearchArray{
        public static void main(String[] args){
            int[] arr = {2,5,7,8,10,15,18,20,22,25,28};//数组是有序的
            int value = 18;
            int index = -1;
            int left = 0;
            int right = arr.length - 1;
            int mid = (left + right)/2;
            while(left<=right){
                //找到结束
                if(value == arr[mid]){
                    index = mid;
                    break;
                }//没找到
                else if(value > arr[mid]){//往右继续查找
                    //移动左边界,使得mid往右移动
                    left = mid + 1;
                }else if(value < arr[mid]){//往左边继续查找
                    right = mid - 1;
                }
                mid = (left + right)/2;
            }
                if(index==-1){
                System.out.println(value + "不存在");
            }else{
                System.out.println(value + "的下标是" + index);
            }
        }
    }
    
  • 待查找数值在数组的右半部分
    查找流程:
  • 待查找数值在数组的左半部分
    查找流程:

数组的直接选择排序

  • 直接获取最值的下标,再进行排序

    示例代码1:
    // 直接排序
    class DirectSearchArray {
        public static void main(String[] args) {
            int[] arr = {49, 38, 65, 97, 76, 13, 27, 49};
            //比较轮数N-1
            for (int j = 0; j < arr.length - 1; j++) {
                int min = j;//假如当前位置是最小的元素
                //每轮比较次数N-j
                for (int i = j; i < arr.length - 1; i++) {
                    if (arr[min] > arr[i + 1]) {
                        //记录找到的最小元素下标
                        min = i + 1;
                    }
                }
                if (min != j) {
                    int temp = arr[j];
                    arr[j] = arr[min];
                    arr[min] = temp;
                }
            }
            //显示结果
            for (int i = 0; i < arr.length; i++) {
                System.out.print(arr[i]);
            }
        }
    }
    

    示例代码2:
    // 直接排序
    class DirectSearchArray {
        public static void main(String[] args) {
            int[] arr = {49,38,65,97,76,13,27,49};
            for(int i=1; i<arr.length; i++){//外循环的次数 = 轮数 = 数组的长度-1
                //(1)找出本轮未排序元素中的最值
                /*
                未排序元素:
                第1轮:i=1,未排序,[0,7],本轮未排序元素第一个元素是[0]
                第2轮:i=2,未排序,[1,7],本轮未排序元素第一个元素是[1]
                ...
                第7轮:i=7,未排序,[6,7],本轮未排序元素第一个元素是[6]
                
                每一轮未排序元素的起始下标:0,1,2,3,4,5,6,正好是i-1的
                未排序的后面的元素依次:
                第1轮:[1,7]  j=1,2,3,4,5,6,7
                第2轮:[2,4]  j=2,3,4,5,6,7
                。。。。
                第7轮:[7]    j=7
                j的起点是i,终点都是7
                */
                int max = arr[i-1];
                int index = i-1;
                for(int j=i; j<arr.length; j++){
                    if(arr[j] > max){
                        max = arr[j];
                        index = j;
                    }
                }
                    //(2)如果这个最值没有在它应该在的位置,就与这个位置的元素交换
                /*
                第1轮,最大值应该在[0]
                第2轮,最大值应该在[1]
                ....
                第7轮,最大值应该在[6]
                正好是i-1的值
                */
                if(index != i-1){
                    //交换arr[i-1]与arr[index]
                    int temp = arr[i-1];
                    arr[i-1] = arr[index];
                    arr[index] = temp;
                }
            }
                //显示结果
            for(int i=0; i<arr.length; i++){
                System.out.print(arr[i]);
                }
            }
    }
    

数组的折半插入排序

  • 利用二分法进行插入排序
  • 编程思路如下图:

    示例代码:
    import java.util.Arrays;
    // 折半二分插入排序
    class DirectSearchArray {
        public static void main(String[] args) {
            /*
            * 折半插入排序
            * 例如:数组{12,2,6,1,5}
            * 第一次:在[0,1)之间找插入2的位置==>left = [0] ==> {2,12,6,1,5}
            * 第二次:在[0,2)之间找插入6的位置==>left = [1] ==> {2,6,12,1,5}
            * 第三次:在[0,3)之间找插入1的位置==>left = [0] ==>{1,2,6,12,5}
            * 第四次:在[0,4)之间找插入5的位置==>left = [2] ==>{1,2,5,6,12}
            * */
            int[] arr = {12, 2, 6, 1, 5};
            for (int i = 1; i < arr.length; i++) {
                //找到[0,i)之间插入arr[i]的位置
                //使用二分查找法
                int left = 0;
                int right = i - 1;
                while (left <= right) {
                    int mid = (left + right) / 2;
                    if (arr[i] <= arr[mid]) {
                        right = mid - 1;
                    } else {
                        left = mid + 1;
                    }
                }
                //在[0,i)插入arr[i]
                if (left < i) {
                    int temp = arr[i];
                    System.arraycopy(arr, left, arr, left + 1, i - left);
                    arr[left] = temp;
                }
            }
            for (int i = 0; i < arr.length; i++) {
                System.out.print(arr[i]+", ");
            }
        }
    }
    

     

数组工具类

  • Java提供了现成的工具类,方便实现数组的相关操作
    • java.util.Arrays数组工具类,提供了很多静态方法来对数组进行操作,而且如下每一个方法都有各种重载形式,以下只列出int[]类型的,其他类型的数组类推:
    • static int binarySearch(int[] a, int key) :要求数组有序,在数组中查找key是否存在,如果存在返回第一次找到的下标,不存在返回负数
    • static int[] copyOf(int[] original, int newLength) :根据original原数组复制一个长度为newLength的新数组,并返回新数组
    • static int[] copyOfRange(int[] original, int from, int to) :复制original原数组的[from,to)构成新数组,并返回新数组
    • static boolean equals(int[] a, int[] a2) :比较两个数组的长度、元素是否完全相同
    • static void fill(int[] a, int val) :用val填充整个a数组
    • static void fill(int[] a, int fromIndex, int toIndex, int val):将a数组[fromIndex,toIndex)部分填充为val
    • static void sort(int[] a) :将a数组按照从小到大进行排序
    • static void sort(int[] a, int fromIndex, int toIndex) :将a数组的[fromIndex, toIndex)部分按照升序排列
    • static String toString(int[] a) :把a数组的元素,拼接为一个字符串,形式为:[元素1,元素2,元素3。。。]
  • 示例代码:
    import java.util.Arrays;
    import java.util.Random;
    public class Test{
        public static void main(String[] args){
            int[] arr = new int[5];
            // 打印数组,输出地址值
            System.out.println(arr); // [I@2ac1fdc4
            // 数组内容转为字符串
            System.out.println("arr数组初始状态:"+ Arrays.toString(arr));
    Arrays.fill(arr, 3);
            System.out.println("arr数组现在状态:"+ Arrays.toString(arr));
    Random rand = new Random();
            for (int i = 0; i < arr.length; i++) {
                arr[i] = rand.nextInt(100);//赋值为100以内的随机整数
            }
            System.out.println("arr数组现在状态:"+ Arrays.toString(arr));
    int[] arr2 = Arrays.copyOf(arr, 10);
            System.out.println("新数组:" + Arrays.toString(arr2));
    System.out.println("两个数组的比较结果:" + Arrays.equals(arr, arr2));
    Arrays.sort(arr);
            System.out.println("arr数组现在状态:"+ Arrays.toString(arr));
    }    
    

     

排序算法知识扩展

排序算法主要是为了加快代码的执行效率,节省我们的时间,这里为了方便小伙伴更加清晰地学习了解算法的原理,推荐一个网址,里面有相关排序算法的详细介绍:
直接输入全拼 http://www.rmboot.com/
注意:

如果地址栏输入下面两个网址进入,会进入别人的博客网站:
1. rmboot.com
2. https://www.rmboot.com/


总结

    本章对数组的排序进行了分享,我们常见的冒泡,二分查找,插入,选择,归并,快排等等,这些算法,首先是理解,借助我推荐的那个网址里的动画会更好理解一些,如果有可能,尽量多敲几遍代码,能做到手撸出这些算法,那就很可以了~下一章,二维数组,依旧是重在理解~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值