Java小白--几种常用的数组排序算法

660 阅读8分钟

1、求数组中的最大值

emm...先来个简单点的算法热热身.奥利给

//求数组的最大值和最小值
public class Test5{
	public static void main(String[] args){	
	int[]num={12,3,54,67,88,34};
	int max=max(num);
	int min=min(num);
	System.out.println(max);
	System.out.println(min);
	}
	public static int max(int[] num){
		int max=num[0];
		int numLen=num.length;
		for(int i=1;i<numLen;i++){
			if(num[i]>max)
				max=num[i];
		}
		return max;
	}
	public static int min(int[] num){
		int min=num[0];
		int numLen=num.length;
		for(int i=1;i<numLen;i++){
			if(num[i]<min)
				min=num[i];
		}
		return min;
	}
}

2、冒泡排序

数组排序在面试中也会经常会遇到到,面试官通过基本的排序算法来了解你对程序基本算法的了解,我们先学习一下最稳定的排序方式冒泡排序!

//冒泡排序第一版
public class Test6{
	/*
	比较相邻的元素。如果第一个比第二个大,就交换他们两个。
	对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
	针对所有的元素重复以上的步骤,除了最后一个。
	持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
	相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。

	5 8 6 3 9 2 1 7 一堆乱序的数字,对他排序
	5 6 3 8 2 1 7 9 第一轮
	5 3 6 2 1 7 8   第二轮
	3 5 2 1 6 7   	第三轮
	3 2 1 5 6   	第四轮
	2 1 3 5         第五轮
	1 2 3           第六轮 		现在顺序已经出来了 但是我们不能保证其他数组排到 第六轮 就能排出来
	1 2             第七轮
	*/
	public static void main(String[] args){	
		int[] nums={5,8,6,3,9,2,1,7};
		//外循环控制轮数
		int times=nums.length-1;//轮数等于数组长度减1
		for(int i=0;i<times;i++){
			for(int j=0;j<times-1-i;j++){
				if(nums[j]>nums[j+1]){//交换位置
					nums[j]=nums[j]+nums[j+1];
					nums[j+1]=nums[j]-nums[j+1];
					nums[j]=nums[j]-nums[j+1];
				}
			}
		}
		//输出结果
		for(int n:nums){
			System.out.println(n);
		}
	}
	
}

我们发现第六轮已经排完了,第七轮就没有必要排了嘛,但是算法还是认真的执行了第七轮比较了下去,在这种情况下我们可衣判断一下数组是否有序,如果有序就直接结束循环,,提高效率

//冒泡排序第二版
public class Test6{
	/*
    我们用一个bool来标记是否有序,初始值为true
	*/
	public static void main(String[] args){	
		int[] nums={5,8,6,3,9,2,1,7};
		boolean isSorted=true;
		//外循环控制轮数
		int times=nums.length-1;//轮数等于数组长度减1
		for(int i=0;i<times;i++){
			for(int j=0;j<times-1-i;j++){
				if(nums[j]>nums[j+1]){//交换位置
					nums[j]=nums[j]+nums[j+1];
					nums[j+1]=nums[j]-nums[j+1];
					nums[j]=nums[j]-nums[j+1];
					isSorted=flase;//如果发生了数组交换,所以数组不是有序把 标志变成false
				}
			}
			if(isSorted){
			    break;
			}
		}
		//输出结果
		for(int n:nums){
			System.out.println(n);
		}
	}
	
}

这只是冒泡排序的一个点,为了说明问题我们用一个新数列来讲解一下,
3 4 2 1 5 6 7 8
这个数列后四个是有序的,前边四个是无序的但是,我们每一轮排序的时候,后边四个都需要比较
第一轮
3和4比较 4和2比较 4和1比较 4和5比较 5和6比较 6和7比较 7和8比较 第一轮结果
3 2 1 4 5 6 7 8
第二轮
3和2比较 3和1比较 3和4比较 4和5比较 5和6比较 6和7比较 7和8比较
第二轮结果
2 1 3 4 5 6 7 8
第三轮 2和1比较 2和3比较 3和4比较 4和5比较 5和6比较 6和7比较 7和8比较
第三轮结果
1 2 3 4 5 6 7 8
我们发现什么了 发现后边都有顺序了但是我们还是比较了很多次,冒泡排序第二个优化的点就是数列有序区的界定
我们可以在每一轮排序后,记录一下数组最后一次交换的位置,该位置就是无序数列的边界,再往后就是有序区了,直接上代码

//冒泡排序第三版
public class Test6{
	/*
    我们用一个bool来标记是否有序,初始值为true
	*/
	public static void main(String[] args){	
		int[] nums={3,4,2,1,5,6,7,8};
		boolean isSorted=true;
		//外循环控制轮数
		//无序序列的边界,每次比较到这里就可以了
		int sortedBorder=nums.length-1;
		int times=nums.length-1;//轮数等于数组长度减1
		for(int i=0;i<times;i++){
			for(int j=0;j<sortedBorder;j++){
				if(nums[j]>nums[j+1]){//交换位置
					nums[j]=nums[j]+nums[j+1];
					nums[j+1]=nums[j]-nums[j+1];
					nums[j]=nums[j]-nums[j+1];
					isSorted=flase;//如果发生了数组交换,所以数组不是有序把 标志变成false
					sortedBorder=j
				}
			}
			if(isSorted){
			    break;
			}
		}
		//输出结果
		for(int n:nums){
			System.out.println(n);
		}
	}
	
}

为什么说冒泡是稳定的排序算法呢,如果数组中有相同的元素的话 排序完他俩的位置没有改变,
5 8 8 3 9 2 1 7,现在我们给第一个8标号 1, 第二个8标号2 ,使用冒泡排完序,数组的第1个位置还是1号的8,第2个位置还是2号的8,所以它的排序是稳定,既然有稳定的排序方式,那么就有不稳定的排序方式,来我们继续。。

3、选择排序

//选择排序
public class Test7{
	/*每一趟从待排序的数据元素中选出最小(或最大)的一个元素,
	顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
	选择排序是不稳定的排序方法。
	34,4,56,17,90,65
	4 34 56 17 90 65 第一轮
	4 17 56 34 90 65 第二轮
	4 17 34 56 90 65 第三轮
	4 17 34 56 90 65  第四轮
	4  17 34 56 65 90 第五轮
	*/
	public static void main(String[] args){	
		int[] nums={34,4,56,17,90,65};//待排序的数列
		int minIndex=0;//用于记录每次比较的最小值下标
		int times=nums.length-1;
		//控制轮数
		for(int i=0;i<times;i++){
			minIndex=i;//每轮假设一个最小值下标
			for(int j=i+1;j<nums.length;j++){
				if(nums[minIndex]>nums[j]){
					minIndex=j;
				}
			}
			//判断需要交换的数下标是否为自己
			if(minIndex!=i){
				nums[minIndex]=nums[minIndex]+nums[i];
				nums[i]=nums[minIndex]-nums[i];
				nums[minIndex]=nums[minIndex]-nums[i];
			}
			
		}
		//输出结果
		for(int n:nums){
			System.out.println(n);
		}
	}
	
}

选择排序,它比较的次数和冒泡是一样的但是一轮就交换了一次,所以它效率比较高,但是它不稳定,很有可能两个相同的元素他们位置会互换,如果不考虑稳定性,建议使用选择排序!
选择排序排完,咱们趁热打铁,直接插入排序..

4、直接插入排序算法

插入排序思路: 34,4,56,17,90,65

第一轮
从下标1 开始 把下标1当做操作数,把操作数用一个临时变量存起来,然后和前一个比较,如果第0个数大于操作数,那么整个数列往后移,怎么个移法呢,就是操作数的下标位置等于 第0个数 4变成34,第一轮就算结束了,然后看发生变化的变量是操作数自己吗不是就吧操作数赋给它
第二轮
操作数变成了56, 操作数和34比 34小,所以操作数一定大于34 前边的所有的数,所以就不用比较了,第二轮结束,也不用交换变量
第三轮 操作数变成了17, 操作数和56 比 操作数比较小,所以56往后移,17位置的数变成56,然后操作数再和34比,比34还小,那么34往后移最开始的56变成34,操作数和4比,操作数大于4,结束第三轮 然后最后往后移的数的位置变成操作数,也就是17,第三轮结束,依次往下进行,我们看代码

//插入排序
public class Test8{
	/*
    
	34,4,56,17,90,65
	
	*/
	public static void main(String[] args){	
		int[] nums={34,4,56,17,90,65};//待排序的数列
	
		int times=nums.length;
	
		for(int i=1;i<times;i++){
			int temp=nums[i];//记录操作数
			int j=0;
			for(j=i-1;j>=0;j--){
				if(nums[j]>temp){
					nums[j+1]=nums[j];
				}else{
					break;
				}
			}
			//判断需要交换的数下标是否为自己
			if(nums[j+1]!=temp){
				nums[j+1]=temp;
			}
			
		}
		//输出结果
		for(int n:nums){
			System.out.println(n);
		}
	}
	
}

小结

这几种常用的排序算法,先介绍到这里,肯定有小伙伴问?有没有比冒牌要快的排序算法呢?那是当然有啦,比如快速排序,归并排序和堆排序等等.由于有写算法设计到数据结构,所以不打算在这个系列里写,但是肯定会写的.