选择排序及其不稳定性介绍

【问题描述】

1.给定任意长度的乱序整型数组,使用选择排序算法将其按照从小到大的顺序进行排列即可。

2.在1的基础上优化选择排序算法,要求每次遍历同时确定最小元素和最大元素,达到减少遍历次数的目的。

3.分析选择排序的时间复杂度和空间复杂度。

4.解释说明选择排序的不稳定性。

【问题解决】

1.原始选择排序代码如下:

public class SelectionSortTest {
	public static void main(String[] args) {
		int[] arr= {5,3,6,8,1,7,9,9,4,2,1};
		printIntArray(selectionSort(arr));
	} 
	
	static int[] selectionSort(int[] arr) {
		for (int i = 0; i < arr.length-1; i++) {
			//定义最小元素的索引
			int minIndex=i;
			//查找最小元素索引
			for (int j = i+1; j < arr.length; j++) {
				minIndex=arr[j]<arr[minIndex]?j:minIndex;
			} 
			//交换两个位置上的元素
			swapIntArray(arr, i, minIndex);
			System.out.print("第"+(i+1)+"次循环:");
			printIntArray(arr);
		}
		return arr;
	}
	
	//打印整型数组
	public static void printIntArray(int[] arr){
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
		System.out.println();
	}
    //交换整型数组指定位置的元素
	public static void swapIntArray(int[] arr,int i,int j) {
		int temp = arr[i];
		arr[i]=arr[j];
		arr[j]=temp;
	}
	
}

执行结果:

第1次循环:1 3 6 8 5 7 9 9 4 2 1 
第2次循环:1 1 6 8 5 7 9 9 4 2 3 
第3次循环:1 1 2 8 5 7 9 9 4 6 3 
第4次循环:1 1 2 3 5 7 9 9 4 6 8 
第5次循环:1 1 2 3 4 7 9 9 5 6 8 
第6次循环:1 1 2 3 4 5 9 9 7 6 8 
第7次循环:1 1 2 3 4 5 6 9 7 9 8 
第8次循环:1 1 2 3 4 5 6 7 9 9 8 
第9次循环:1 1 2 3 4 5 6 7 8 9 9 
第10次循环:1 1 2 3 4 5 6 7 8 9 9 
1 1 2 3 4 5 6 7 8 9 9 

2.优化后的代码:

public class SelectionSortTest {
    public static void main(String[] args) {
        int[] arr= {5,3,6,8,1,7,9,9,4,2,1};
        printIntArray(selectionSort(arr));
    }

    static int[] selectionSort(int[] arr) {

        for (int i = 0; i <= arr.length-(1+i); i++) {
            int maxlength = arr.length-(1+i);
            //定义最小元素的索引
            int minIndex=i;
            //定义最大元素索引
            int maxIndex=i;

            //定位到最小值索引和最大值索引
            for (int j = i+1; j <= maxlength; j++) {
                minIndex=arr[j]<arr[minIndex]?j:minIndex;
                maxIndex=arr[j]>arr[maxIndex]?j:maxIndex;
            }

            //交换指定位置上的元素
            SelectionSortTest.swapIntArray(arr, i, minIndex);
            SelectionSortTest.swapIntArray(arr, maxlength, maxIndex);

            if(arr[maxlength-1]>arr[maxlength]){
                SelectionSortTest.swapIntArray(arr, maxlength-1, maxlength);
            }

            System.out.print("第"+(i+1)+"次循环:");
            SelectionSortTest.printIntArray(arr);
        }
        return arr;
    }

    //打印整型数组
    public static void printIntArray(int[] arr){
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
    }
    //交换整型数组指定位置的元素
    public static void swapIntArray(int[] arr,int i,int j) {
        int temp = arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
}

执行结果:

第1次循环:1 3 6 8 5 7 1 9 4 2 9 
第2次循环:1 1 6 8 5 7 3 2 4 9 9 
第3次循环:1 1 2 4 5 7 3 6 8 9 9 
第4次循环:1 1 2 3 5 6 4 7 8 9 9 
第5次循环:1 1 2 3 4 5 6 7 8 9 9 
第6次循环:1 1 2 3 4 5 6 7 8 9 9 
1 1 2 3 4 5 6 7 8 9 9 

3.选择排序使用双层循环,最消耗时间的代码是内层循环里定位目标元素索引的代码,即:

//定位到最小值索引
for (int j = i+1; j <= arr.length-(1+i); j++) {
		minIndex=arr[j]<arr[minIndex]?j:minIndex;//此行代码是最消耗时间的
}

若数组长度为n,则该行代码执行次数是:(n-1)+(n-2)+......2+1,所以时间复杂度为:O(n^2),由于选择排序本身的特性(遍历元素并在内层循环确定指定元素的索引然后进行元素交换,必然会使用(n*n)数量级的时间),不管在最好还是最坏的情况下,时间复杂度都是O(n^2)

空间上除了目标数组本身以外没有使用额外的数据结构,因此空间复杂度为O(1)

4.只要能够证明经过选择排序后,大小相同的两个元素,相对前后位置对换了,就可以说明选择排序算法是不稳定的。我们可以在上列的代码中加入相应的打印语句,查看选择排序的整个过程:

public class SelectionSortTest {
	public static void main(String[] args) {
		int[] arr= {5,3,3,8,1,6,7,9,4,2};
		printIntArray(selectionSort(arr));
	} 
	
	static int[] selectionSort(int[] arr) {
		for (int i = 0; i < arr.length-1; i++) {
			//定义最小元素的索引
			int minIndex=i;
			//查找最小元素索引
			for (int j = i+1; j < arr.length; j++) {
				minIndex=arr[j]<arr[minIndex]?j:minIndex;
			} 
			
			System.out.print("第"+(i+1)+"次循环:");
			printIntArray(arr);
			//交换两个位置上的元素
			swapIntArray(arr, i, minIndex);
			System.out.print("索引["+i+"]与["+minIndex+"]即元素‘"+arr[minIndex]+"’与‘"+arr[i]+"’交换:");
			printIntArray(arr);
		}
		return arr;
	}
	
	//打印整型数组
	public static void printIntArray(int[] arr){
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
		System.out.println();
	}
    //交换整型数组指定位置的元素
	public static void swapIntArray(int[] arr,int i,int j) {
		int temp = arr[i];
		arr[i]=arr[j];
		arr[j]=temp;
	}
	
}

执行结果:

第1次循环:5 3 3 8 1 6 7 9 4 2 
索引[0]与[4]即元素‘5’与‘1’交换:1 3 3 8 5 6 7 9 4 2 
第2次循环:1 3 3 8 5 6 7 9 4 2 
索引[1]与[9]即元素‘3’与‘2’交换:1 2 3 8 5 6 7 9 4 3 
第3次循环:1 2 3 8 5 6 7 9 4 3 
索引[2]与[2]即元素‘3’与‘3’交换:1 2 3 8 5 6 7 9 4 3 
第4次循环:1 2 3 8 5 6 7 9 4 3 
索引[3]与[9]即元素‘8’与‘3’交换:1 2 3 3 5 6 7 9 4 8 
第5次循环:1 2 3 3 5 6 7 9 4 8 
索引[4]与[8]即元素‘5’与‘4’交换:1 2 3 3 4 6 7 9 5 8 
第6次循环:1 2 3 3 4 6 7 9 5 8 
索引[5]与[8]即元素‘6’与‘5’交换:1 2 3 3 4 5 7 9 6 8 
第7次循环:1 2 3 3 4 5 7 9 6 8 
索引[6]与[8]即元素‘7’与‘6’交换:1 2 3 3 4 5 6 9 7 8 
第8次循环:1 2 3 3 4 5 6 9 7 8 
索引[7]与[8]即元素‘9’与‘7’交换:1 2 3 3 4 5 6 7 9 8 
第9次循环:1 2 3 3 4 5 6 7 9 8 
索引[8]与[9]即元素‘9’与‘8’交换:1 2 3 3 4 5 6 7 8 9 
1 2 3 3 4 5 6 7 8 9

我们可以观察到,对于初始数组int[] arr= {5,3,3,8,1,6,7,9,4,2};进行选择排序过程中,原本位于索引[1]上的元素“3”在第二次循环里和索引[9]上的元素“2”交换位置,使得原本索引[1]位置上的元素“3”在前,索引[2]位置上的元素“3”在后的相对状态,变成了索引[2]位置上的元素“3”在前,索引[1]位置上的元素“3”在后的相对状态。而且在后续的排序交换过程中,两者的相对位置依旧没有被换回来,导致选择排序前后,相同元素的相对前后相对位置发生了交换。所以,选择排序是不稳定的排序算法。

 

 

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值