数组常见算法代码总结

一、数组排序

1、冒泡排序

对数组进行排序是程序中非常基本的需求。常用的排序算法有冒泡排序、插入排序和快速排序。二冒泡排序是对于初学者相对好理解以及重要的排序算法。

实现步骤(演示升序排序)

  1. 比较相邻的元素,如果第一个比第二个大则交换位置。
  2. 对每一对相邻元素作同样的工作,从一开始第一对到最后一对。这个步骤完成后,末尾的元素会是最大的数。
  3. 针对所有的元素重复以上步骤,除最后一个元素。
  4. 持续每次对越来越少的元素重复上面的步骤,知道没有任何一对数字需要比较。

冒泡排序的特点是,每一轮循环后,最大的一个数就被交换到末尾,因此,下一轮循环就可以”排除“最后的数,每一轮循环都比上一轮循环的结束位置靠前一位。

import java.util.Arrays;

public class Main {
	public static void main(String[] args) {
		int[] numbers = { 3, 6, 2, 4, 8, 12, 7, 9 };

		System.out.println(Arrays.toString(numbers));

		int count=0;

		//比较N-1轮
		for (int i = 0, n = numbers.length; i < n - 1; i++) {

			count++;//计数器

			//是否已经处于"有序"状态
			//true表示有序
			//false表示无序
			//每次一轮后第二轮开始将isSorted归为true
			//若为进入if则表示已经有序,退出循环
			boolean isSorted=true;
			for (int j = 0; j < n - 1 - i; j++) {
				if (numbers[j] > numbers[j + 1]) {
					numbers[j] = numbers[j] ^ numbers[j + 1];
					numbers[j + 1] = numbers[j] ^ numbers[j + 1];
					numbers[j] = numbers[j] ^ numbers[j + 1];
					isSorted=false;
				}
			}
			if(isSorted) {
				break;
			}
		}

		System.out.println("总共比较了"+count+"轮");//总共比较了3轮
		System.out.println(Arrays.toString(numbers));//[2, 3, 4, 6, 7, 8, 9, 12]
    }
}

2、使用Arrays工具类排序

实际上,Java的标准库已经内置了排序功能,我们只需要调用Arrays.sort()就可以排序:


public class Main{
    public static void main(String[] args){
        int[] ns ={28,12,89,73,65,18,96,50,8,36};
 
        //排序前
        System.out.println("排序前:"+Arrays.toString(ns));
        
        //排序
        Arrays.sort(ns);
 
        //排序后
        System.out.println("排序后:"+Arrays.toString(ns));
    }
}

小结

  • 常用的排序算法有冒泡排序、插入排序和快速排序等
  • 冒泡排序使用两次for循环实现排序
  • 交换两个变量的值需要借助一个临时变量
  • 可以直接使用Java标准库提供的Arrays.sort()进行排序
  • 对数组排序会直接修改数组本身

二、无序数组查找

1、无序数组查找元素

在一个无序数组中,如果进行指定元素的查找,可以通过循环遍历或Arrays工具类两种方法进行查找。

遍历查找

遍历的方式进行查找:可以通过对该无序数组进行遍历,将数组的每个元素与指定元素进行比较,从而确定该数组中是否存在指定元素。

整型数组

int[] array={28,12,89,73,65,18,96,50,8,36};
int target=36;//目标元素
int index=-1;//目标元素下标,默认为-1,代表不存在

//遍历查找
for(int i=0;i<array.length;i++){
    if(array[i]==target){
        index=i;
        break;
    }
}

System.out.printf("目标值%d在数组中的下标为:%d",target,index);

字符串数组

String[] singerArray = {"李荣浩","盘尼西林","王菲","王贰浪","鹿先森乐队","孙燕姿","G.E.M.邓紫棋","方大同","品冠儿子"};

Scanner input = new Scanner(System.in);
String target = "方大同";
int index = -1;

//遍历查找
for(int i = 0; i < singerArray.length; i++){
    //字符串等值判断使用equals()方法
    if(target.equals(singerArray[i])){
        index = i;
        break;
    }
}

双指针遍历查找

双指针遍历的方式进行查找:通过两个下标,分别从数组头部和尾部,同时对该无序数组进行遍历,将数组中的每个元素与指定元素进行比较,从而确定该数组中是否存在指定元素。

 整型数组

int[] array={28,12,89,73,65,18,96,50,8,36};
int target=36;//目标元素
int index=-1;//目标元素下标,默认为-1,代表不存在

//双指针查找
for(int i = 0, k = array.length - 1; i <= k; i++, k--){
    if(array[i] == target){
        index = i;
        break;
    }

    if(array[k] == target){
        index = k;
        break;
    }
}

System.out.printf("目标值%d在数组中的下标为:%d",target,index);

字符串数组

String[] singerArray = {"李荣浩","盘尼西林","王菲","王贰浪","鹿先森乐队","孙燕姿","G.E.M.邓紫棋","方大同","品冠儿子"};

Scanner input = new Scanner(System.in);
String target = "方大同";
int index = -1;

//双指针查找
for(int i = 0, k = singerArray.length - 1; i <= k; i++, k--){
    if(singerArray[i] == target){
        index = i;
        break;
    }

    if(singerArray[k] == target){
        index = k;
        break;
    }
}

2、有序数组查找元素

Arrays工具类binarySearch()方法

除了遍历查找,还可以通过调用Arrays.binarySearch()方法,进行查找:由于该方法是基于二分查找实现,数组必须处于有序状态。所以,需要先对数组进行排序,然后再通过Arrays.binarySearch()进行查找。

public class Main{
    public static void main(String[] args){
        int[] array = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
        int target = 36;

        //先排序
        Arrays.sort(array);
        
        //再查找
        int index = Arrays.binarySearch(array,target);

        System.out.printf("目标值%d在数组中的下标为:%d",target,index); 
    }
}

 该方发只能对有序数组进行查找,所以必须先排序,再查找指定元素。

二分查找元素

二分查找的作用

在一个有序数组中,如果需要指定元素进行查找,可以采用二分查找算法,提高查找元素的效率。

二分查找的过程

  1. 判断搜索数组的“中位元素”与要查找的“目标元素”是否相等。
    1. 如果相等,代表查找成功,退出算法;
    2. 如果不相等,继续比较”中位元素“与要查找的”目标元素“的大小关系;
      1. 如果“中位元素”大于“目标元素”,当前数组的前半部分作为新的搜素数组,因为后半部分的所有元素都大于“目标元素”,他们全都被排除了。
      2. 如果“中位元素”小于“目标元素”,当前数组的后半部分作为新的搜素数组,因为前半部分的所有元素都小于“目标元素”,他们都被排除了
  2. 在新的搜素数组上,重新开始第一步的工作

二分查找的效率高效,是因为它在匹配不成功的时候,每次都能排除剩余元素中的一般的元素。因此可能包含目标元素的有效范围就收缩的很快,而不像遍历查找那样每次仅能排除一个元素。

public class Main{
    public static void main(String[] args){
        int[] array = { 1, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59};
        int target = 37;//目标元素
        int index  = -1;//目标元素的下标,默认为-1,表示不存在

        //low和high分别表示搜索数组的开始下标与结束下标
        //默认搜索数组是整个数组
        int low = 0, high = array.length - 1;

        while(low <= high){
            //计算“中位元素”的下标
            int mid = (high + low) / 2;
            
            if(array[mid] < target){
                //如果“中位元素”等于“目标元素”,查找成功,退出
                index = mid;
                break;
            }else if(array[mid] < target){
                //如果“中位元素”小于“目标元素”,当前数组的后半部分作为新的搜索数组
                low = mid + 1;
            }else if(array[mid] > target){
                //如果“中位元素”大于“目标元素”,当前数组的前半部分作为新的搜索数组
                high = mid - 1;
            }
        }
        System.out.printf("目标值%d在数组中的下标为:%d",target,index);
    }
}

 二分查找,除了在有序数组中使用之外,也应用于BST二叉搜索树中进行指定节点值的查找。

小结

  • 查找数组中的指定元素分为两种情况:无序数组查找和有序数组查找
  • 无序数组可以通过遍历数组或Arrays工具类两种方式查找指定元素
  • 有序数组可以通过二分查找算法查找指定元素

三、数组乱序

算法简述

假设题目:有一个大小为100的数组,里面的元素是从1到100,随机从数组中选择50个不重复数(也可以理解为产生50个不重复的1-100的数字)。

实现过程中,不仅仅是用Math.random()*100重复50次,就可以拿到50个1到100的随机数,因为在这个过程中,产生重复数字的概率是非常大的。例如,第一次遇到5,第二次如果再一次遇到5,不符合“不重复”的要求,所以需要重新生成随机数。所以,要选出50个不重复数的话,随机次数远远大于50,因为越到后面随机带的数与前面选出的数重复的概率越大。这个时候,就需要用到数组乱序算法。

数组乱序,也被称为数组洗牌,实际算法中有一个非常著名的洗牌算法Fisher-Yates算法,是由Ronald A.Fisher和Frank Yates于1938年发明的,后来被Kunth在自己的著作《The Art of Computer Programming》中介绍,很多人直接成Knuth洗牌算法。

实现步骤

  1. 假设有一组等待乱序的数组P
  2. 从P中随机选取一个未乱序的元素
  3. 将该元素与数组P中最后一个未乱序的元素交换
  4. 重复 2 - 3 的步骤,直到数组P中元素全部完成乱序
int[] p = { 1, 2, 3, 4, 5, 6, 7};

for(int i = p.length - 1; i >0; i--){
    int index = (int) (Math.random() * i);
    int temp = p[index];
    p[index] = p[i];
    p[i] = temp;
}

System.out.println(Arrays.toString(p));

四、数组旋转

数组旋转可以实现类似于音乐播放器的播放列表的功能,例如:将数组(音乐列表)的第一位通过旋转放置在最后一位,第二位放置在第一位以此类推。

向左旋转

例:向左旋转两位

[ 1, 2, 3, 4, 5, 6, 7, 8] 
            ↓
[ 3, 4, 5, 6, 7,8,1, 2]
原始:[ 1, 2, 3, 4, 5, 6, 7, 8]
第一次:[ 2, 3, 4, 5, 6, 7, 8, 1]
第二次:[ 3, 4, 5, 6, 7, 8, 1, 2]
public void left(int w, int[] array){
    for(int i = 1; i <= w; i++){
        for(int k = 0; k < array.length - 1; k++){
            array[k] = array[k] ^ array[k+1];
            array[k+1] = array[k] ^ array[k+1];
            array[k] = array[k] ^ array[k+1];
        }
    }
}

向右旋转

例:向右旋转两位

[ 1, 2, 3, 4, 5, 6, 7, 8] 
            ↓
[ 7, 8, 1, 2, 3, 4, 5, 6]
原始:[ 1, 2, 3, 4, 5, 6, 7, 8]
第一次:[ 8, 1, 2, 3, 4, 5, 6, 7]
第二次:[ 7, 8, 1, 2, 3, 4, 5, 6]
public void rigth(int w, int[] array){
    for(int i = 1; i <= w; i++){
        for(int k = array.length - 1; k > 0; k--){
            array[k] = array[k] ^ array[k-1];
            array[k-1] = array[k] ^ array[k-1];
            array[k] = array[k] ^ array[k-1];
        }
    }
}

  • 43
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓晨CH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值