Java中几种常用排序的实现与比较

[b]关于排序的算法,大约分为两大类:顺序排序与对数排序。
顺序排序一般使用一对嵌套的循环结构(多为两个for循环),因此排序n个元素需要大约n的2次方的比较。比较常用的顺序排序有(1)选择排序法 (2)插入排序法 (3)冒泡排序法
对数排序一般需要大约n*log2n(2为底数)次比较。这两种排序,当n越大的时候,他们性能上的差别就越大。快速排序与归并排序都属于对数排序,同样是使用递归。[/b]


[size=large][color=green][b]1)选择排序法[/b][/color][/size]

public class Sort {

// 选择排序
public static void selectionSort(Comparable[] data) {
int min;
Comparable temp;
// 从第一个元素开始比较,找出最小那个,放在第一位
// 从第二个元素开始比较,找出最小那个,放在第二位
// 总共需要放N-1次
for (int index = 0; index < data.length - 1; index++) {
min = index;
for (int scan = index + 1; scan < data.length; scan++) {
if (data[scan].compareTo(data[min]) < 0) {
min = scan;
}
}
//跳回到第一层循环的时候,才进行交换,把最小的数放在第一位...如此类推
temp = data[min];
data[min] = data[index];
data[index] = temp;

}
}
}


[color=brown]策略是:搜索整个数组,找到最小值。然后将这个值与第一个位置上的值交换。然后搜索除第一个值钱外的次小值,然后与第二个位置上的值进行交换。如此类推。这种算法最简单易明[/color]


[b][size=large][color=green]2)插入排序[/color][/size][/b]


// 插入排序
public static void insertionSort(Comparable[] data) {
// 插入一个数,与前面的数比较,放到适当的位置,如此类推
for (int index = 1; index < data.length; index++) {
Comparable temp = data[index];

int position = index;

while (position > 0 && data[position - 1].compareTo(temp) > 0) {

data[position] = data[position - 1];
position--;
}
data[position] = temp;
}
}

[color=brown]插入排序相对于选择排序要复杂一些,策略是:每插入一个数,与前面的所有数进行比较,然后把这个数放到适当的位置。比如:数组里只有3,插入6,3与6排序后,插入4,然后4就放到第2位,之后插入5,3与4位置不变,5放在第3位,6换到第4位...插入的过程需要移动数组的其他值,为插入的元素腾出存储空间。[/color]


[b][size=large][color=green]3)冒泡算法[/color][/size][/b]

public static void bubbleSort2(Comparable[] data) {

Comparable temp;

for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data.length - 1 - i; j++) {
if (data[j].compareTo(data[j + 1]) > 0) {
temp = data[j + 1];
data[j + 1] = data[j];
data[j] = temp;
}
}
}
}

[color=brown]冒泡算法大家应该最熟悉了...它的策略是:第一次对数组所有值进行比较,重复地比较相邻两个元素,比较后进行交换,把最大值移动到最后一个位置,然后再扫描除最后一位外的数组其他值,不断进行交换,把次大值移到倒数第2位,如此类推。每次比较都找出该次所有数中的最大值[/color]


上面3种顺序排序实现都很相似,效率也接近
现在看看如何使用递归实现排序
[b][size=large][color=green]4)快速排序[/color][/size][/b]

public static void quickSort(Comparable[] data, int min, int max) {
int mid;

if (min < max) {
mid = findPartition(data, min, max);
quickSort(data, min, mid - 1);
quickSort(data, mid + 1, max);
}
}

// quickSort的支撑方法
private static int findPartition(Comparable[] data, int min, int max) {
int left;
int right;
Comparable temp;
Comparable partitionelement;

// 以第一个元素为分割元素(不一定是data[min])
partitionelement = data[min];

left = min;
right = max;

while (left < right) {

// 从左边找到比partitionelement大的数就跳出循环
while (data[left].compareTo(partitionelement) <= 0 && left < right) {
left++;
}

// 从右边找到比partitionelement小的数就跳出循环
while (data[right].compareTo(partitionelement) > 0) {
right--;
}

// 交换左边比partitionelement大的与右边比partitionelement小的元素
if (left < right) {
temp = data[left];
data[left] = data[right];
data[right] = temp;
}
}

// 当left>=right的时候,交换分割元素与data[right]的位置(把分割元素放到去一个比较中间的位置)
temp = data[min];
data[min] = data[right];
data[right] = temp;

return right;
}

[color=brown]策略:首先在数组中任意选择一个元素作为分割元素,上面的例子是选择第一个数。然后开始分割数组,把比这个分割元素小的值都移到它的左边,比他大的都移到它的右边。然后递归调用这个方法,对左右两部分排序,类似地从左边选择一个分割元素,把左边比它小的排在它的左边,比它大的排在它的有...然后到右边。直到只剩下一个元素时(即不能再分割时)完成排序。
这种排序需要3个参数,第一个为对象数组,第2个是数组索引的起始位置,第3个是数组索引的结束位置。[/color]


下面对这几种排序的实现和性能进行测试

public static void main(String[] args) {
long start = System.currentTimeMillis();

Random rand = new Random();

Integer array[] = new Integer[40000];

for(int i=0;i<40000;i++){
array[i] = rand.nextInt(10);
}

// 插入排序
// insertionSort(array);

// 选择排序
// selectionSort(array);

// 冒泡排序
// bubbleSort(array);

// 快速排序
quickSort(array, 0, 39999);


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

long end = System.currentTimeMillis();

System.out.println("时间差:" + (end - start) + "毫秒");
}


[size=medium][color=red]结论:
对有4万个(1~9)随机数的数组进行排序,在我的机器上运行,使用递归的快速查询约1秒,插入查询用5秒左右,选择查询11秒+,冒泡算法要几乎14秒。当然要查询的对象越少,他们之间效率的差别就越小。在排序对象的数量不多时,用顺序查询会比较方便与直观。[/color][/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值