基础知识(青铜挑战)
-
快速排序通过多次比较与交换来完成排序。而这个过程又被分为了多次重复单趟排序,接下来我们先从每一趟的排序讲起。
-
快速排序思想很简单,也很重要:
-
在一个无序数组中取一个数key,每一趟排序的最终目的是:让key的左边的所有数小于key,key的右边都大于key(假设排升序)
-
接下来,我们对key的左右区间进行单趟排序,可以预见的是,每次排序都固定好了一个数。而当我们对细分的左右区间进行单趟排序,最终整个数组都会化为有序
-
最常用的快排实现方法:快慢指针法
-
取最左边的数为key
-
定义两个快慢指针,都从key的下一位往右走
-
ast每走一步判断一下它指向的元素是否小于key,若小于则交换fast和slow位置的元素,并且让slow向前走
-
直到fast走到底,结束循环
-
最后让slow和key位置的值交换,再返回key的位置
-
-
具体代码如下:(2023/09/19午)
public void quickSort(int[] nums, int start, int end) {
// 判断递归结束的条件
if (start >= end) {
return;
}
// 选定最左边的元素作为基准值
int pivot = nums[start];
// 初始化快慢指针
int slow = start;
int fast = start + 1;
// 快慢指针法进行划分
while (fast <= end) {
if (nums[fast] < pivot) {
// 如果当前元素小于基准值,将其交换到基准值的左侧
slow++;
swap(nums, slow, fast);
}
fast++;
}
// 将基准值交换到正确的位置
swap(nums, start, slow);
// 递归对基准值的左右两部分进行排序
quickSort(nums, start, slow - 1);
quickSort(nums, slow + 1, end);
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
实战训练(白银挑战)
数组中K大的数
-
我们要找第K大的元素,如果我们能够将数组排好序,再取 nums[K - 1] 元素,就是目标值了
-
试想一下,每一轮快排结束之后,我们能知晓基准值的位置,即我们知晓基准值的下标
-
如果目标元素在基准元素的左侧,就对左侧进行递归快排
-
否则,对右侧进行递归快排
-
最后,在已经 ”排好序的“ 数组中,轻松就能找到第K大的元素
-
其实就是快速排序对半砍,每次只快排一半元素,要么左侧,要么右侧(2023/09/27晚)
-
public static void quicksort(int[] nums, int left, int right) {
int start = left;
int end = right;
int pivot = nums[(end + start) / 2]; //取中位值作左右参考对比
//每次循环都将大的放到左边,小的放到右边
while (start < end) {
while (nums[start] > pivot) {
start++;
}
while (nums[end] < pivot) {
end--;
}
//如果l>=r说明mid左边的值全部大于等于mid的值,右边全是小的,退出
if (start >= end) {
break;
}
//交换
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
//解决值相同的情况,如果交换后发现左边的值等于mid目标值,则使右边指针向左移
if (nums[start] == pivot) {
end--;
}
//右边的值等于mid目标值,则使左边指针向左移
if (nums[end] == pivot) {
start++;
}
}
if (start == end) { //退出循环防止栈溢出
start++;
end--;
}
if (left < end) {
quicksort(nums, left, end); //向左递归
}
if (right > start) {
quicksort(nums, start, right); //向右递归
}
}
归并排序
-
好难好难,需要先理解思路,再考虑编码实现:
-
归并排序简单来讲,就是将大的序列视为若干小的数组,利用归并思想实现排序的方法。
-
分治策略(分:把问题分成小的问题分别求解;治:将分的阶段得到的各答案合在一起)
-