本次我们介绍基础算法中的快速排序,我们会从下面几个角度来介绍快速排序:
- 快速排序介绍
- 暴力求解算法
- 快速排序算法
- 快速排序代码
- 快速排序问题
- 快速查找算法
快速排序介绍
我们首先来简单介绍快速排序问题:
- 首先我们需要确定一个分界点
这个分界点我们可以任意选择
我们常用的分界点有q[l],q[(l+r)/2],q[r]这三个点位
关于q[l]和q[r]如果选择递归的参数不合适,可能会导致死循环,我们后面会讲解,所以最好选择q[(l+r)/2]
- 调整区间数大小
我们希望我们选择的分界点的数作为分界数,我们不需要保证分界点的数是这个数
我们只需要保证在分界点的左侧的数全部都小于等于该分界数,同时该分界点的右侧的数全部都大于等于该分界数
- 递归处理
我们需要在开头进行判断:l >= r ?
如果l >= r,那么我们就没有递归的必要,直接return即可
但是如果l > r,我们需要对其内部进行快速排序,并且在末尾处对排序后分界点的两侧再次进行递归处理
暴力求解算法
我们首先来介绍暴力求解法:
-
最简单最直观的方法就是采用两个数组,我们直接遍历l~r之间的所有数
-
如果该数小于分界数,那么放在a数组中;如果该数大于分界数,那么放在b数组中
-
最后我们将两个数组分别放到分界点的两侧处,然后再对其两侧进行暴力求解,最终达到效果
快速排序算法
我们采用指针来进行快速排序,因为这样不会开辟新的内存空间
我们来仔细介绍快速排序:
- 首先我们创建两个指针,分别指向数组的最左侧和最右侧
我们创建i和j指针,分别放于l-1和r+1处
因为我们后面需要判断该数与分界数的关系,所以我们首先移动指针再进行判断,所以我们需要将指针放在边缘处
- 在指针未相遇之前,我们将i向右移动,将j向左移动
首先我们需要判断两个指针没有相遇 i < j ?
没有相遇我们开始执行排序操作:
我们进行i++,如果当前数小于分界数,我们继续移动,直到当前数大于分界数,停止移动
我们进行j--,如果当前数大于分界数,我们继续移动,直到当前数小于分界数,停止移动
当两者都停止移动时,首先需要判断 i < j ?
若i < j 说明我们左侧停留的值大,右侧停留的值小
我们将两个数进行交换,将小的数移动到左侧,将大的数移动到右侧
- 递归处理
同样,我们在处理完当前数组后,需要将左侧和分界点之间的数进行排序,将分界点和右侧之间的数进行排序
快速排序代码
我们来简单实现一下快速排序算法:
import java.util.Scanner;
public class quick_sort {
public static void main(String[] args) {
// 输入数组的数量和数组的值
int n;
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
int[] ints = new int[n];
for (int i = 0 ; i < n;i++){
ints[i] = scanner.nextInt();
}
// 展示数组
System.out.print("排序前:");
for (int i = 0; i < n; i++) {
System.out.print(ints[i]);
}
System.out.println(" ");
// 进行快速排序
quick_sort(ints,0,n-1);
// 展示数组
System.out.print("排序后:");
for (int i = 0; i < n; i++) {
System.out.print(ints[i]);
}
System.out.println(" ");
}
public static void quick_sort(int[] ints,int l,int r){
// 判断数组是否存在
if (l >= r) return;
// 进行快速排序
int x = ints[(l+r)/2];
int i = l-1,j = r + 1;
while (i < j){
// 左指针
while (ints[++i] < x);
// 右指针
while (ints[--j] > x);
// 如果左右指针没有相遇进行交换
if (i < j){
int temp = ints[i];
ints[i] = ints[j];
ints[j] = temp;
}
}
// 实现递归处理
quick_sort(ints,l,j);
quick_sort(ints,j+1,r);
}
}
快速排序问题
我们前面说到我们选择分界点的时候尽量选择(r+l)/2,因为单l或单r可能会导致死循环
下面我们给出示例:
import java.util.Scanner;
public class quick_sort {
public static void main(String[] args) {
// 输入数组的数量和数组的值
int n;
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
int[] ints = new int[n];
for (int i = 0 ; i < n;i++){
ints[i] = scanner.nextInt();
}
// 展示数组
System.out.print("排序前:");
for (int i = 0; i < n; i++) {
System.out.print(ints[i]);
}
System.out.println(" ");
// 进行快速排序
quick_sort(ints,0,n-1);
// 展示数组
System.out.print("排序后:");
for (int i = 0; i < n; i++) {
System.out.print(ints[i]);
}
System.out.println(" ");
}
public static void quick_sort(int[] ints,int l,int r){
// 判断数组是否存在
if (l >= r) return;
// 进行快速排序
int x = ints[l];
int i = l-1,j = r + 1;
while (i < j){
// 左指针
while (ints[++i] < x);
// 右指针
while (ints[--j] > x);
// 如果左右指针没有相遇进行交换
if (i < j){
int temp = ints[i];
ints[i] = ints[j];
ints[j] = temp;
}
}
// 实现递归处理
quick_sort(ints,l,i-1);
quick_sort(ints,i,r);
}
}
下面我们模拟操作:
我们传入数据: 2 1 2
我们的分界数为: 1
最开始数组为:1 2
我们的i指针停在0处,我们的j指针也停在0处
这时我们进行第二轮递归处理
quick_sort(ints,0,-1)左侧递归直接结束
quick_sort(ints,0,1)右侧递归和第一轮完全相同,所以我们会一直循环下去
快速查找算法
我们在快速排序的基础上研究出了快速查找算法
题目:
- 给定一个长度为n的整数数列,以及一个整数k,请用最快选择算法求出数列的第k小的数是多少
求解方法:
- 我们根据快速排序算法来将数组进行排序,舍弃掉左右两侧的一侧,对另一侧进行查找排序,递归即可
求解代码:
import java.util.Scanner;
public class eee {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 输入总数
int n = scanner.nextInt();
// 输入查找第k小的值
int k = scanner.nextInt();
// 输入数组
int[] arr = new int[n];
for (int i = 0; i < arr.length; i++) {
arr[i] = scanner.nextInt();
}
// 运行方法查找第k小的值
int minK = findMinK(arr,0,n-1, k);
// 输出
System.out.println(arr[minK]);
}
public static int findMinK(int[] arr,int l,int r,int k){
// 如果相等,说明找到了
if (l >= r) return l;
// 下面是标准的快速排序
int x = arr[(l+r)/2];
int i = l-1;
int j = r+1;
while (i < j){
while (arr[++i] < x);
while (arr[--j] > x);
if (l < r){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 如果数在左侧,对左侧遍历;如果数在右侧,对右侧遍历并修改概述在右侧的k值
if (j > k) return findMinK(arr,l,j,k);
else return findMinK(arr,j+1,r,k-j+1);
}
}
结束语
好的,关于基础算法篇的快速排序就介绍到这里,希望能为你带来帮助~