数组专项练习

数组专项练习

接下来我们做一些专项练习题,把数组的常见操作练习一下。在学习这个案例时,重点掌握数组求最值的思路,代码只是用来表达你的思路的。

1.数组求最值

需求:定义一个int类型数组,求数组中元素的最大值,并打印最大值

image-20230813201817821

数组求最大值思路:
1)先找出数组中0索引的元素,假设为最大值,用max表示【擂主】
2)遍历后面的每一个元素和max比较,把较大的元素值重新赋值给max(擂主换人)
3)最后max就是所有元素的最大值(最后站在台上的擂主)
public static void main(String[] args) {
	int[] arr=new int[]{15,9000,10000,20000,9500,5};//定义数组
    int max=arr[0];//为最大值赋一个初值
    for (int i = 0; i < arr.length; i++) {//遍历数组从0开始比较
        if (max<arr[i]){//当最大值小于这个值时
             max=arr[i];//把这个值赋给最大值
          }
      }
    System.out.println(max);//遍历完后输出一个最大值
}

总结一下:

通过这个案例,我们主要掌握求最值的思路,以后不管遇到求最大值还是最小值,编程思路都是一样的,不同的可能是数据不同。

求最小值
public static void main(String[] args) {
	int[] arr=new int[]{15,9000,10000,20000,9500,5};//定义数组
    int min=arr[0];//为最小值赋一个初值
    for (int i = 0; i < arr.length; i++) {//遍历数组从0开始比较
        if (min>arr[i]){//当最小值小于这个值时
             max=arr[i];//把这个值赋给最小值
          }
      }
    System.out.println(max);//遍历完后输出一个最小值
}

2.数组元素反转

需求:某个数组有5个数据:10,20,30,40,50,请将这个数组中的数据进行反转。
[10, 20, 30, 40, 50] 反转后 [50, 40, 30, 20, 10]

怎么样,才能达到元素反转的效果呢?我们只需将第一个和最后一个元素互换、第二个和倒数第二个互换、依次内推… 如下图所示

image-20230813203509803

怎么样写代码,才能达到上面的效果呢?我们继续分析

1.每次交换,需要有左右两边的两个索引,我们可以用i和j表示
刚开始i=0,j=数组长度-1;
2.每次让i和j索引位置的两个元素互换位置
arr[i]和arr[j]互换位置
3.每次还完位置之后,让i往右移动一位,让j往前移动一位

具体代码如下

public static void main(String[] args) {
	// 现有一个 int 数组,数组中有十个元素。将数组反转后输出。
	int[] arr = new int[]{9, 1, 3, 4, 54, 56, 23, 22, 20, 43};
	// for (int i = arr.length - 1; i >= 0; i--) {
	// System.out.println(arr[i]);
	// }
	for (int i = 0, j = arr.length - 1; i < arr.length / 2; i++,
j--) {
		// int temp = arr[i];
		// arr[i] = arr[j];
		// arr[j] = temp;
		arr[i] = arr[i] ^ arr[j]; // 1100 0000 1100 1100 0000
		arr[j] = arr[i] ^ arr[j]; // arr[i] ^ arr[j] ^ arr[j] =
								  //arr[i] ^ 0 = arr[i]
		arr[i] = arr[i] ^ arr[j]; // arr[i] ^ arr[j] ^ arr[i] = 0
								  //^ arr[j] = arr[j]
		}
	for (int a : arr) {
		System.out.println(a);
	}
}

总结一下:

通过上面的案例,需要我们掌握元素互换位置的编程思路;以后遇到数据互换问题,都这样做。

3.排序

排序算法 有多种,常用的排序算法有冒泡排序、插入排序、选择排序、快速排序、堆排序、归并排序、希尔排序、二叉树排序、计数排序等。

3.1选择排序

表现最稳定的排序算法之一,因为无论什么数据进去都是**O(n2)**的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。理论上讲,选择排序可能也是平时排序一般人想到的最多的排序方法了吧。

选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有素均排序完毕。

n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:

  • 初始状态:无序区为R[1…n],有序区为空;
  • 第 i 趟 排 序 (i=1,2,3…n-1) 开 始 时 , 当 前 有 序 区 和 无 序 区 分 别 为 R[1…i-1] 和R(i…n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1…i]和R[i+1…n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
  • n-1趟结束,数组有序化了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IyJK5q6o-1691944286121)(https://gitee.com/wang-moumin/images/raw/master/images/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F.gif)]

public class SelectSort {
    public static void main(String[] args) {
        int[] arr=new int[]{2,5,8,6,3};//定义数组
        for (int i = 0; i < arr.length; i++) {//为数组中的每一个下标排好序
            int min=arr[i];//把数组中原来的值先给出去
            int minIndex=i;//定义最小值的下标
            for (int j = i+1; j < arr.length; j++) {//选择排序从头开始,默认前面已经排好序了,从数组的下一个元素开始比较
                if (arr[minIndex]>arr[j]){//当最小值大于后一个元素时
                    minIndex=j;//把后一个元素的下标值赋给最小值下标
                }
            }
            arr[i]=arr[minIndex];//让最小值按数组的顺序排
            arr[minIndex]=min;//按顺序排到的最小值和真的最小值做交换

        }
        for (int a : arr) {//遍历排好序的数组
            System.out.println(a);
        }
    }
}

3.2插入排序

插入排序的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

算法描述:

  1. 从第一个元素开始,该元素可以认为已经被排序;
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  5. 将新元素插入到该位置后;
  6. 重复步骤2~5。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kiIPlOhd-1691944286121)(https://gitee.com/wang-moumin/images/raw/master/images/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F.gif)]

public class InsertSort {
    public static void main(String[] args) {
        int[] arr=new int[]{2,5,8,6,3};//定义数组
        for (int i = 1; i < arr.length; i++) {
            int prevIndex=i-1;//排好序的前一个元素的最大下标值
            int current=arr[i];
            while(prevIndex>=0&&current<arr[prevIndex]){//循环
                //当排好序的前一个元素的下标值大于等于0时且下一个要排序的元素小于前一个元素的值
                arr[prevIndex+1]=arr[prevIndex];//没排好序的元素值往后诺一个下标
                prevIndex--;//排一次序就少一个
            }
            arr[prevIndex+1]=current;//跳出循环,把后面排到的最小值插入到已排序的后一位
        }
        for (int a : arr) {//遍历排好序的数组
            System.out.println(a);
        }
    }
}

3.3冒泡排序

它重复地走访过要排序的数组,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数组的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DXG1b8Km-1691944286122)(https://gitee.com/wang-moumin/images/raw/master/images/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F.gif)]

public class Maopao {
    public static void main(String[] args) {
        int[] arr=new int[]{2,5,8,6,3};//定义数组
        for (int i = 0; i < arr.length-1; i++) {//为数组中的每一个下标排好序
            for (int j = 0; j < arr.length-i-1; j++) {//循环遍历排序,遍历完先排好最大的值,每次循环到最大的值的前一个
                if(arr[j]>arr[j+1]){//如果前一个值大于后一个值
                    int temp=arr[j+1];//把后一个值交还给前一个值
                    arr[j+1]=arr[j];
                    arr[j]=temp;
                }
            }
        }
        for (int a : arr) {//遍历排好序的数组
            System.out.println(a);
        }
    }
}

3.4快速排序

快速排序用到了分治思想,同样的还有归并排序。乍看起来快速排序和归并排序非常相似,都是将问题变小,先排序子串,最后合并。不同的是快速排序在划分子问题的时候经过多一步处理,将划分的两组数据划分为一大一小,这样在最后合并的时候就不必像归并排序那样再进行比较。但也正因为如此,划分的不定性使得快速排序的时间复杂度并不稳定。

快速排序的基本思想:通过一趟排序将待排序列分隔成独立的两部分,其中一部分记录的元素均比另一部分的元素小,则可分别对这两部分子序列继续进行排序,以达到整个序列有序。

算法步骤

快速排序使用分治法策略来把一个序列分为较小和较大的 2 个子序列,然后递回地排序两个子序列。具体算法描述如下:

  1. 从序列中随机挑出一个元素,做为 “基准”( pivot );

  2. 重新排列序列,将所有比基准值小的元素摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个操作结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

  3. 递归地把小于基准值元素的子序列和大于基准值元素的子序列进行快速排序。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S5lRbARC-1692113404981)(https://gitee.com/wang-moumin/images/raw/master/images/%E5%BF%AB%E6%8E%92%E5%BA%8F.webp)]

public class QuickSort {
    public static void main(String[] args) {
        // 快排
        int[] nums = {2, 7, 9, 0, -1, 2, -9};//定义数组
        quickSort(nums, 0, nums.length - 1);//调用方法
        System.out.println(Arrays.toString(nums));//输出数组
    }

    public static void quickSort(int[] arr, int left, int right) {
        if (left >= right) {//如果数组的下标左边大于等于右边
            return;//返回
        }
        int jiZhun = arr[left];//定义一个基准值在数组的左边即下标为0的元素
        int i = left;//i从左边走
        int j = right;//j从右边走
        while (i != j) {//如果i不等于j进入循环
            // 找到比基准值小的下标
            while (j > i && arr[j] >= jiZhun) {//大于基准值
                j --;
            }
            // 找到比基准值大的下标
            while (j > i && arr[i] <= jiZhun) {//小于基准值
                i ++;
            }
            if (i < j) {//交换两个值
                arr[j] = arr[i] ^ arr[j];
                arr[i] = arr[i] ^ arr[j];
                arr[j] = arr[i] ^ arr[j];
            }
        }
        if (arr[i] < jiZhun) {//循环完后i和j同时指向的值和基准比大小
            arr[left] = arr[i];//比基准小就和基准的位置交换
            arr[i] = jiZhun;
        }
        // 数组以 i 下标分成左边 和右边两部分   i 左边 小于 基准值  i 右边比基准值大
        // 排序左边
        quickSort(arr, left, i - 1);//递归基准左边的排序
        quickSort(arr, i + 1, right);//递归基准右边的排序
    }
}

4.二分查找

二分查找(Binary Search)算法,也叫折半查找算法。二分查找的思想非常简单,有点类似分治的思想。二分查找针对的是一个有序的数据集合,每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。

image-20230813212025318

public class BinarySearch {
    public static void main(String[] args) {
        int[] arr=new int[]{1,3,5,7,9,15,16,18,24,30,68};//定义一个排好序的数组
        int key=6;//要查询的值
        int start=0;//查找的起始位置
        int end= arr.length-1;//查找的终止位置
        int mid=(start+end)/2;//查询的中间值
        while(start<=end){//循环当起始位置小于终止位置时
            if(key>arr[mid]){//要查询的值大于中间位置的元素时
                start=mid+1;//下一次查询时起始位置从中间位置的下一个开始
            } else if (key==arr[mid]) {//当查询的元素值等于中间位置的元素时
                System.out.println("这个数的下标是"+mid);//输出中间位置的下标
                break;//找到后就跳出循环
            }else{//否则当要查询的值小于中间位置的元素时
                end=mid-1;//下一次查询时终止位置从中间位置的前一个开始
            }
            mid=(start+end)/2;//每循环完一次就重新为中间值赋值
        }
        if (start>end){//当起始位置大于终止位置时说明在数组中找不到要查询的值
            System.out.println(-1);//输出-1
        }
    }
}

5.随机排名

先来看一下需求

需求:某公司开发部5名开发人员,要进行项目进展汇报演讲,现在采取随机排名后进行汇
报。请先依次录入5名员工的工号,然后展示出一组随机的排名顺序。

分析一下随机排名的思路

1.在程序中录入5名员工的工号存储起来 ---> 使用动态初始化数组的方式。
2.依次遍历数组中的每个数据。
3.每遍历到一个数据,都随机一个索引值出来,让当前数据与该索引位置处的数据进行交
换。

如下图所示,每次遍历到一个元素,随机将当前位置元素和随机索引元素换位置

image-20230813213743570

代码如下

public class Test3 {
    public static void main(String[] args) {
        // 目标:完成随机排名
        // 1、定义一个动态初始化的数组用于存储5名员工的工号
        int[] codes = new int[5];
        // 2、提示用户录入5名员工的工号。
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < codes.length; i++) {
            // i = 0 1 2 3 4
            System.out.println("请您输入第" + (i + 1) + "个员工的工号:");
            int code = sc.nextInt();
            codes[i] = code;
        }
        // 3、打乱数组中的元素顺序。
        // [12, 33, 54, 26, 8]
        // i index
        Random r = new Random();
        for (int i = 0; i < codes.length; i++) {
            // codes[i]
            // 每遍历到一个数据,都随机一个数组索引范围内的值。
            //然后让当前遍历的数据与该索引位置处的值交换。
            int index = r.nextInt(codes.length); // 0 - 4
            // 定义一个临时变量记住index位置处的值
            int temp = codes[index];
            // 把i位置处的值赋值给index位置处
            codes[index] = codes[i];
            // 把index位置原来的值赋值给i位置处
            codes[i] = temp;
        }
        // 4、遍历数组中的工号输出即可
        for (int i = 0; i < codes.length; i++) {
            System.out.print(codes[i] + " ");
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值