这几天趁着放假有时间,把几种常见的排序算法整理下,本次整理主要是根据http://blog.youkuaiyun.com/u012501459/article/details/44594719所写排序算法为基础,加上自己的一些理解,整理所得,下面继续介绍两种排序算法,希尔排序,选择排序。
希尔排序
希尔排序就是直接插入排序的进阶版,基本思想就是将一个无序数组分为几个子数组分别进行直接插入排序,排序完成后数组会基本有序,最后整体进行一次直接插入排序,因为数组整体基本有序,所以效率某些时候会比直接插入排序要高。其中数组分为几个子数组是按照步长来分隔,步长可变,当步长变为1的时候,就是对整个数组进行直接插入排序。下面是代码:
public class ShellSort {
public static void main(String[] args) {
int[] data = {2,5,9,6,3,4,7,1,5}; //测试数据
shellSort(data);
for(int h = 0;h<data.length;h++) {
System.out.print(data[h]+" ");
}
}
public static void shellSort(int[] data ) {
int gap,k;
/**
* 该循环决定步长,每次步长都缩小为原来的1/2,直至为1
* 就类似于将整个数组按步长分为几个子数组,每个元素之间隔一个步长
* 比如数组{2,5,9,6,3,4,7,1,5},假设步长为4,那么得到子数组为
* {2,3,5},{5,4},{9,7},{6,1}
*/
for(gap=(int)data.length/2;gap>0;gap = gap/2) {
/**
* 该循环每次循环就相当于遍历每个子数组,i=0时,遍历的第一个子数组为{2,3,5}
*此后每次i++,都会向后遍历子数组{5,4},{9,7},{6,1}
*/
for(int i = 0;i<data.length;i++) {
//下面就相当于一个插入排序
/**
* 以第一个子数组{2,3,5}为例,首先,j对应3的位置,表示准备要
* 插入的元素,每次循环都会自加一个步长,取得下一个元素(因为整体上
* 仍然是一个大的数组,只是逻辑上分为几个子数组)。
*/
for(int j =i +gap;j<data.length;j+=gap) {
//判断准备插入的元素是否小于前一个元素
if (data[j]<data[j-gap]) {
int temp = data[j]; //保存待插入元素的值
//将大于待插入元素的值向后移
for(k = j-gap;k>=0&&data[k]>temp;k=k-gap) {
data[k+gap] = data[k];
}
//前面k已经减去一个步长,这里要加回来
data[k+gap] = temp;
break;
}
}
}
}
}
}
结果如下:
选择排序
选择排序基本思想就是从无序数组中取出最小值,重新插入一个新数组,最后完成排序,原理很简单,代码如下,都有详细注释:
public class SelectSort {
public static void main(String[] args) {
int[] data = {2,5,9,6,3,4,7,1,5}; //测试数据
selectSort(data);//选择排序
//打印数组
for(int i = 0;i<data.length;i++) {
System.out.print(data[i]+" ");
}
}
/**
* 选择排序的基本思想就是从一个无序的数组中选出一个最小(最大)
* 的元素,插入到一个长度为零的空数组中,当插入完成后,原来的空数组就
* 变为有序
*/
public static void selectSort(int[] data ) {
int min = 0; //保存数组中最小值
int minIndex = 0;//保存数组中最小值的下标
/**
* 从i=0开始,i++,每次data[0...i]看成有序数组
* data[i...]为无序数组
*/
for(int i = 0;i<data.length;i++) {
min = data[i];//初始化最小值,为有序数组中最后一个
minIndex = i;//保存下标
//遍历后面无序数组,找到最小值和下标
for(int j = i+1;j<data.length;j++) {
if (data[j]<min) {
min = data[j];
minIndex = j;
}
}
//交换
data[minIndex] = data[i];
data[i] = min;
}
}
}
结果如下: