希尔排序是对直接插入排序方法的改进。
其基本思想是:对待排序的n个元素,首先取d1(d1<n)作为分组间距,将所有距离为d1倍数的元素放在同一组中,由此将所有待排列元素分为d1组,在每个组内做直接插入排序;接着取d2(d2<d1)作为分组间距得到d2个组,组内进行直接插入排序…重复上述操作直到di=1,此时得到所有待排序元素分为一组且基本有序,进行直接插入排序可以得到最终有序排列的数组。
/**
-
希尔排序
-
@param data
*/
public void shellSort(int[] data){
int i, j, k, s, tmp;
k = data.length;
int[] dist = new int[k/2];
i = 0;
do{
k = k / 2;
dist[i++] = k;
}while(k > 1);//得到每次分组的间距,直到1为止
for(i=0;(s = dist[i])>0;i++){//取分组间距
System.out.println(“分组间距:” + s + “,此次排序得到:”);
for(k=s;k<data.length;k++){//对每个分组内元素做直接插入排序
if(data[k] < data[k-s]){
tmp = data[k];
for(j=k-s;j>=0&&data[j]>tmp;j-=s){
data[j+s] = data[j];
}
data[j+s] = tmp;
}
}
System.out.println(Arrays.toString(data));
}
}
快速排序的基本思想是:通过一趟排序将待排的元素划分为独立的两部分,成为前半区和后半区。前半区中的元素都不大于后半区中的元素。然后再分别对这两部分进行快速排序,进而使整个序列有序。
快速排序中一次划分的具体方法是:设待排序元素中的一个元素为枢轴元素pivot,另外设两个指针 i 和 j 分别指向序列的首尾位置。假设本次枢轴元素取i最初指向元素,则首先从j所指位置起向前搜索,找到第一个小于pivot的元素时,将该元素移到i所指的位置;然后从i所在位置开始向后搜索,找到第一个大于pivot的元素时将其移到j所指位置。重复该过程直到i等于j,将pivot复制到i和j指向位置。同理,若枢轴元素取j最初指向元素,则首先从i所指位置向后搜索。
如下图所示,对数组进行一次划分得到前半区[5,9,12,21]和后半区[23,76,32],再分别对两个分区进行快速排序,即可得到有序序列[5,9,12,21,23,32,76]。
快速排序被认为是在复杂度为O(nlogn)的排序方法中最好的一种,但是若初始序列元素有序或基本有序时,每次划分结果都会得到一个长度为0的分区,此时快速排序的性能退化为O(n²)。为了避免性能退化,一般会在选择枢轴元素时采用三数取中的方法。
三数取中:即在待排序数组中对首、中、尾三个元素进行大小比较,选择中间大小的元素作为枢轴元素。
/**
-
快速排序
-
@param data
*/
public void quickSort(int[] data, int low, int high){
if(low < high){
int loc = partition(data, low, high);//进行一次分区
quickSort(data, low, loc - 1);//对前半区快速排序
quickSort(data, loc + 1, high);//对后半区快速排序
}
}
/**
-
一次划分后,得到数组以枢轴元素data[i]为界,前半区元素都不大于data[i],后半区元素都不小于data[i]
-
@param data
-
@param low
-
@param high
-
@return
*/
public int partition(int[] data, int low, int h