目录
希尔排序
归并排序
快速排序
一、希尔排序
希尔排序又叫“缩小增量”,(是不稳定的排序方法)。 先将整个数组 k=(n/2)分。把k数作为“增量”。然后将所有距离为k的倍数的数分到同一组。一共分为k组。然后对每一组进行插入排序。再进行 (k/2),重复上面。直到排序成功
时间复杂度:O(n的1.3次方)
- 首先选择增量为10/2 = 5,所以按照增量为5,划分为5组。[8,3]、[9,5]、[1,4]、[7,6]、[2,0]
- 对上面5组进行插入排序,变为:3,5,1,6,0,8,9,4,7,2。
- 下一步缩小增量,5/2 = 2,然后分为两组[3,1,0,9,7]、[5,6,8,2,4]。
- 再对上面的两组进行插入排序0,1,3,7,9,2,4,5,6,8
- 重复步骤,一直到排序完成。
int[] arr = new int[] {8,9,1,7,2,3,5,4,6,0};
// 拿到每轮的步长,步长的计算方法就是用数组长度除2。
// 下一轮的步长就是d/=2。
for (int d = arr.length / 2; d > 0; d /= 2) {
// 拿到步长后,就要遍历每一组元素。进行插入比较了
// 就是从步长位置,遍历后面的元素。
for (int i = d; i < arr.length; i++) {
// 因为,要比较的元素不是从步长开始的。
// 要从第一号元素开始的。所以j = i - d;
/*
* 因为插入排序,当前和后面的比较后,换位。还要和前面的比较的, 所以,换位后的下一步是和前面的进行比较的。所以j-=d;
*/
for (int j = i - d; j >= 0; j -= d) {
// 比较换位
if (arr[j] > arr[j + d]) {
int temp = arr[j];
arr[j] = arr[j + d];
arr[j + d] = temp;
}
}
}
}
System.out.println(Arrays.toString(arr));
二、归并排序
将两个或两个以上的有序文件合并成为一个新的有序文件。将n个记录无序的文件看成是由n个长度为1的有序子文件组成的文件,然后进行两两归并。得到n/2个长度为2或1的有序文件、再重复。知道得到n个记录的有序文件为止。称为 两路归并排序。
有两种归并排序的方式:从上往下,从下往上。
- 先把数组进行对半分解,一直分到只有一个元素。
- 然后,对单个元素的数组进行合并。一直到合并成整个数组
public static void main(String[] args) {
int[] arr = { 10, 20, 30, 50, 40, 60};
int[] tmp = new int[arr.length]; // 新建一个临时数组存放
mergeSort(arr, 0, arr.length - 1, tmp);
System.out.println(Arrays.toString(arr));
}
public static void merge(int[] arr, int low, int mid, int high, int[] tmp) {
int i = 0;
int j = low, k = mid + 1; // 左边序列和右边序列起始索引
while (j <= mid && k <= high) {
if (arr[j] < arr[k]) {
tmp[i++] = arr[j++];
} else {
tmp[i++] = arr[k++];
}
}
// 若左边序列还有剩余,则将其全部拷贝进tmp[]中
while (j <= mid) {
tmp[i++] = arr[j++];
}
while (k <= high) {
tmp[i++] = arr[k++];
}
for (int t = 0; t < i; t++) {// 存储排序后的顺序数组。
arr[low + t] = tmp[t];
}
}
public static void mergeSort(int[] arr, int low, int high, int[] tmp) {
if (low < high) {
int mid = (low + high) / 2;
mergeSort(arr, low, mid, tmp); // 对左边序列进行归并排序
mergeSort(arr, mid + 1, high, tmp); // 对右边序列进行归并排序
merge(arr, low, mid, high, tmp); // 合并两个有序序列
}
}
三、快速排序
一趟排序将数组分成独立的两部分。分为前半区和后半区。前半区的记录均不大于后半区记录的关键字。然后,再分别对这两部分进行快速排序。
- 首先拿数组的第一个数出来作为基准数x = 30,记第一位为i = 0,
- 先从数组最后一位数向前查找,找到x > arr[ j ],然后把arr[ i ] = arr[ j ],
- 赋值完之后,然后,从i位起向后比较,找到x < arr[ i ],然后把arr[ j ] = arr[ i ];
- 然后一直重复,到最后,i = j,把x 赋值到最后的索引位置。
public static void main(String[] args) {
int[] arr = { 10, 20, 30, 50, 40, 60 };
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
private static void quickSort(int[] arr, int low, int high) {// 递归比那里查询比较
if (low < high) {
// 找寻基准数据的正确索引
int index = getIndex(arr, low, high);
// 进行迭代对index之前和之后的数组进行相同的操作使整个数组变成有序
quickSort(arr, 0, index - 1);
quickSort(arr, index + 1, high);
}
}
private static int getIndex(int[] arr, int low, int high) {
// 基准数据
int tmp = arr[low];
while (low < high) {
// 当队尾的元素大于等于基准数据时,向前挪动high指针
while (low < high && arr[high] >= tmp) {
high--;
}
// 如果队尾元素小于tmp了,需要将其赋值给low
arr[low] = arr[high];
// 当队首元素小于等于tmp时,向前挪动low指针
while (low < high && arr[low] <= tmp) {
low++;
}
// 当队首元素大于tmp时,需要将其赋值给high
arr[high] = arr[low];
}
// 跳出循环时low和high相等,此时的low或high就是tmp的正确索引位置
// 由原理部分可以很清楚的知道low位置的值并不是tmp,所以需要将tmp赋值给arr[low]
arr[low] = tmp;
return low; // 返回tmp的正确位置
}