Java内部排序(一)-(选择排序法之直接选择排序)

假设含有n个记录的序列为{R1,R2,R3,......,Rn},其相应的关键字序列为{K1,K2,K3,......,kn}。将这些记录重新排序为{Ri1,Ri2,Ri3,.......,Rin},
使得相应的关键字值满足条件Ki1 <= Ki2 <= Ki3 <= .... <= Kin,这样的一种操作称之为排序。
对于一个排序算法来说,一般从如下三个方面来衡量算法的优劣。
√。时间复杂度:主要是分析关键字的比较次数和记录的移动次数。
√。空间复杂度:分析排序算法中需要的辅助内存。
√。稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的;反之就是不稳定的。
就现有的排序算法来看,排序大致可分为外部排序和内部排序。如果整个排序过程不需要借助于外部存储器,所有排序操作都在内存中运行,这种排序可称之为内部排序。
如果参与的元素非常多,数据非常的大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器,那么这种排序称之为外部排序。
外部排序基本思路:
1.把要排序的文件中的一组记录(将源文件分解成多个可以一次性装入内存)读入内存的排序区,对读入内存的记录按照内部排序法进行排序,排序之后输出带外部存储器。不断重复这一过程,每次读取一条记录。知道源文件所有的记录处理完毕。</span>
2.将上一步排序好的记录两组两组地合并排序,在内存容量允许的情况下,每组中包含的记录越大越好,这样可以减少合并的次数。
当然了我们常说的排序都是指内部排序。对于外部排序而言,(个人认都是公司或企业内部的机密,不到核心高层没必要去想那么多)。
直接选择排序的思想很简单。他需要经过n-1趟比较
第一趟比较:程序将记录定位在第一个数据上,拿第一个数据依次和它后面的每个数据进行比较,如果第一个数据大于后面某个数据,就交换他们。。。以此类推。经过第一趟比较,这组数据中最小的数据被选出,它排在第一位。</span>
第二趟比较:程序将记录定位在第二个数据上,拿第二个数据依次和它后面的每个数据进行比较,如果第二个数据大于后面某个数据,就交换他们。。。依次类推。经过第二趟比较,这组数据中第二小的数据被选出,它排在第二位。</span>
。。。
按此规则一共进行n-1趟比较,这组数据中第n-1小的数据被选出,被排在第n-1位;剩下的就是做大的数据,它排在最后。
假设有下面一组数据:
21, 30 ,49, 16, 9 ,30*

模拟效果如下:
//定义一个数据包装类


class DataWrap implements Comparable<DataWrap>{
	int data;
	String flag;
	
	public DataWrap(int data, String flag){
		this.data = data;
		this.flag = flag;
	}
	
	@Override
	public String toString() {
		return data + flag;
	}


	public int compareTo(DataWrap dw) {
		return this.data > dw.data ? 1 : (this.data == dw.data ? 0 : -1);
	}
	
}


 

<pre name="code" class="java">public class SelectSort{
	public static void selectSort(DataWrap[] data){
		System.out.println( "-开始排序-");
		int arrayLength = data.length;
		//依次进行n-1趟比较,第i趟比较将第i大的值选出放在i位置上
		for(int i = 0; i < arrayLength - 1; i ++){
			//第i个数据只需和它后面的数据进行比较
			for(int j = i + 1; j < arrayLength; j ++){
				if(data[i].data > data[j].data){
					DataWrap dw = data[i];
					data[i] = data[j];
					data[j] = dw;
				}
			}
			//没进行一趟比较后输出结果
			System.out.println( java.util.Arrays.toString(data));
		}
	}
}
	
	public static void main(String[] args){
		//21,30,49,30*,16,9,
		DataWrap[] data = {new DataWrap(21,""),
							new DataWrap(30,""),
							new DataWrap(49,""),
							new DataWrap(30,"*"),  //为了查看稳定性如何
							new DataWrap(16,""),
							new DataWrap(9,"")};
		
		System.out.println("-排序前-:"+java.util.Arrays.toString(data));
		selectSort(data);
		System.out.println("-排序后-:"+java.util.Arrays.toString(data));
	}
}


 

输出结果为:

从上面的直接选择排序算法可以看出,直接选择排序算法的关键就是n-1趟比较,每趟的目的就是选择本趟比较的最小数据,并将它放在本趟比较的第一位。对于上面的实现算法,其实有一个很大的问题:就是每趟比较过程中,程序一旦发现某个数据比第一个数据小,就会立即交换他们。但这没有太大的必要,反而是增加了交换的次数,导致算法效率降低。

对于上面的算法进行了改进:

public class SelectSort{
	public static void selectSort(DataWrap[] data){
		/*System.out.println( "-开始排序-");
		int arrayLength = data.length;
		//依次进行n-1趟比较,第i趟比较将第i大的值选出放在i位置上
		for(int i = 0; i < arrayLength - 1; i ++){
			//第i个数据只需和它后面的数据进行比较
			for(int j = i + 1; j < arrayLength; j ++){
				if(data[i].data > data[j].data){
					DataWrap dw = data[i];
					data[i] = data[j];
					data[j] = dw;
				}
			}
			//没进行一趟比较后输出结果
			System.out.println( java.util.Arrays.toString(data));
		}*/
		
		System.out.println( "-开始排序-");
		int arrayLength = data.length;
		for(int i = 0; i < arrayLength; i ++){
			//minIndex 永远保留本趟比较中最小值的索引
			int minIndex = i;
			for(int j = i + 1; j < arrayLength; j ++){
				if(data[minIndex].compareTo(data[j]) > 0){
<span style="white-space:pre">					</span>//将j的值赋给minIndex
					minIndex = j;
				}
			}
<span style="white-space:pre">			</span>//每趟比较最多交换一次
			if(minIndex != i){
				DataWrap dw = data[i];
				data[i] = data[minIndex];
				data[minIndex] = dw;
			}
			System.out.println( java.util.Arrays.toString(data));
		}
	}

输出结果为:


从输出结果来看,直接选择排序的第n趟比较之多交换一次,且永远是那n-1位的数据和中间最小的一个数据进行交换(当然除了他本身就是最小的数据)。

对于注解选择排序算法而言,假设有n个数据,数据交换的次数最多有n-1次,但程序的比较次数较多。总体来说,其时间效率为  O(n^2)。

直接选择排序算法的空间效率很高,他只需要一个附加单元用于交换,其空间效率为    O(1)。

从上面程序中的两个为30的DataWrap的排序结果来看,直接选择排序是不稳定的。


参考资料见:《疯狂Java程序员的基本修养》 --李刚








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值