- 希尔排序
希尔排序是一种改进的插入排序算法,它的思想是:取一个数作为整个数组的间隔,从第一个数开始按照间隔依次将取出来的新数组进行插入排序,第一个数到第一个间隔间的数都执行该操作。这样就完成了第一次排序,然后将间隔缩小一半,再进行第二次排序,最后按照间隔等于1进行最后一次排序,也就是进行插入排序。
Knuth序列:(用来确定希尔排序的间隔,最小间隔是1,以后依次按照h * 3 + 1递增)
h = 1
h = h * 3 + 1
public class ShellSort {
public static void main(String[] args){
int[] arr = {9,6,11,3,5,12,8,7,10,15,14,4,1,13,2};
sort(arr);
print(arr);
}
private static void print(int[] arr) {
for (int i = 1; i < arr.length; i++) {
System.out.print( arr[i] + " ");
}
}
private static void sort(int[] arr) {
int h = 1;
while (h <= arr.length/3){
h = h * 3 + 1;
}
for (int gap = h; gap > 0 ; gap = (gap - 1)/3) {
for (int i = gap;i < arr.length;i++){
for (int j = i;j > gap - 1;j-=gap){
if (arr[j] < arr[j - gap]){
swap(arr,j,j - gap);
}
}
}
}
}
private static void swap(int[] arr,int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
-
归并排序
归并排序是java中默认的对象排序算法,java对象使用的排序算法是Tim Sort,它是归并排序的一种,python对象默认的排序算法也是归并排序。对象排序一般要求稳定,所以归并排序是稳定的。它的时间复杂度是O(n * log₂n),空间复杂度是O(n)排序思想:假如一个数组从中间分为两部分,前后两个数组分别都是有序的。那么我们可以创建一个大小等于该数组的新数组,用三个指针 i 指向前面部分数组的开始,j 指向后面部分数组的开始,k 指向新数组的开始。判断arr[i]和arr[j]的大小,将小的一个赋值到新数组newArr[k],同时 i 和 j 中数值小的指针向后移动一位,k也移动一位k++。这样就完成了对一个数组前后分别有序的排序。而没有顺序的数组就是不断将数组分为前后两部分,直到整个数组都变成前后有序的。也就是递归执行上面的排序操作,最后将前后两部分有序数组merge归并完成排序。
public class MergeSort {
public static void main(String[] args){
//arr数组已经分为{1,4,7,8}和{3,6,9}两个排好序的数组,进行归并
int[] arr = {1,4,7,8,3,6,9};
merge(arr);
print(arr);
//数组并不是左边两边已经排好序的就递归调用sort方法,直到左右两边都是有序数组,最后进行merge调用
int[] arr2 = {2,4,1,6,9,3,8,2,7};
sort(arr2,0.arr2.length - 1);
print(arr);
}
private static void sort(int[] arr,int left,int right){
if (left == right) return;
//将数组分成两半
int mid = left + (right - left)/2;
//左边排序
sort(arr,left,mid);
//右边排序
sort(arr,mid + 1,right);
//merge归并
merge(arr,left,mid + 1,right);
}
private static void merge(int[] arr) {
//mid取数组中间的数,将数组分为前后两部分
int mid = arr.length / 2;
int[] temp = new int[arr.length];
int i = 0;
int j = mid + 1;
int k = 0;
while (i <= mid && j < arr.length){
if (arr[i] <= arr[j]){
temp[k] = arr[i];
i++;
}else {
temp[k] = arr[j];
j++;
}
k++;
}
//归并之后如果前半部分的数有剩下的则把剩下的所有数依次添加到数组中
while (i <= mid){
temp[k++] = arr[i++];
}
//归并之后如果后半部分的数有剩下的则把剩下的所有数依次添加到数组中
while (j < arr.length){
temp[k++] = arr[j++];
}
}
//优化的merge方法,可以指定数组的一部分来排序
// leftPoint:左半部分从哪开始的指针
// rightPoint:右半部分从哪开始的指针
// rightBound:右边边界的索引
private static void merge(int[] arr,int leftPoint,int rightPoint,int rightBound) {
//mid取数组中间的数,将数组分为前后两部分
int mid = rightPoint - 1;
int[] temp = new int[rightBound - leftPoint + 1];
int i = leftPoint;
int j = rightPoint;
int k = 0;
while (i <= mid && j <= rightBound){
if (arr[i] <= arr[j]){
temp[k] = arr[i];
i++;
}else {
temp[k] = arr[j];
j++;
}
k++;
}
//归并之后如果前半部分的数有剩下的则把剩下的所有数依次添加到数组中
while (i <= mid){
temp[k++] = arr[i++];
}
//归并之后如果后半部分的数有剩下的则把剩下的所有数依次添加到数组中
while (j <= rightBound){
temp[k++] = arr[j++];
}
for (int m = 0; m < temp.length; m++) {
arr[leftPoint + m] = temp[m];
}
}
private static void print(int[] arr) {
for (int i = 1; i < arr.length; i++) {
System.out.print( arr[i] + " ");
}
}
}
网友评论