快速排序是由英国计算机科学家 Tony Hoare 在1960年提出的一种排序算法,也被称为“划分交换排序”(partition-exchange sort)。Tony Hoare在发表论文时将其称为“快速排序”,并且很快成为了一种广泛应用的排序算法。
然而,快速排序的思想并非完全由Hoare创造。早在1951年,美国计算机科学家并行排序提出了一种类似的原理,但当时并没有被广泛应用。
快速排序的基本思想是通过将待排序序列分割成较小的子序列,然后分别对子序列进行排序,最终将所有子序列排序完成。具体而言,快速排序的过程如下:
- 选择一个元素作为基准(pivot)。
- 将所有比基准值小的元素放在基准值的左边,比基准值大的元素放在基准值的右边。
- 对基准值左右两边的子序列递归地重复步骤1和步骤2,直到子序列长度为1或0。
快速排序的实现可以使用递归来完成。快速排序的基本思想是选择一个基准值,然后将数组分为两个子数组,一个子数组中的所有元素都小于基准值,另一个子数组中的所有元素都大于基准值。然后递归地对这两个子数组进行排序,最后将排序好的子数组合并起来。
以下是一个使用Python实现快速排序的示例代码:
def quicksort(arr):
# 基准条件:如果数组为空或只有一个元素,则无需排序直接返回
if len(arr) <= 1:
return arr
# 选择基准值
pivot = arr[len(arr) // 2]
# 将小于基准值的元素放在一个子数组中
# 将大于基准值的元素放在另一个子数组中
# 将等于基准值的元素放在一个单独的子数组中
lesser = [x for x in arr if x < pivot]
equal = [x for x in arr if x == pivot]
greater = [x for x in arr if x > pivot]
# 递归地对两个子数组进行排序,并将它们和等于基准值的子数组合并起来
return quicksort(lesser) + equal + quicksort(greater)
# 测试示例
arr = [10, 7, 8, 9, 1, 5]
result = quicksort(arr)
print(result)
输出结果为:[1, 5, 7, 8, 9, 10]
快速排序的优点在于其平均时间复杂度为O(n log n),并且具有原地排序的特点(即不需要额外的存储空间)。因此,快速排序成为了一种常用的排序算法,被广泛应用于各种情况下的排序问题。
快速排序是一种常用的排序算法,它通过选择一个基准元素,将数组分为两个部分,一个部分是小于基准元素的,一个部分是大于基准元素的,并且递归地对两个部分进行排序。
具体算法如下:
- 选择一个基准元素,一般选取数组的第一个元素。
- 将数组划分为两个部分,小于基准元素的放在左边,大于基准元素的放在右边。
- 递归地对左右两个部分进行快速排序。
- 合并左右两个部分。
快速排序是一种高效的排序算法,其基本思想是通过不断地将数组分割为两部分,并递归地对每个部分进行排序,最终使整个数组有序。
快速排序的关键是如何选择基准值和如何进行数组的划分。一种常用的方法是使用Lomuto划分或Hoare划分。
Lomuto划分的实现步骤如下:
-
选择最右边的元素作为基准值。
-
初始化一个索引变量
i
,用于指示当前小于基准值的元素的位置。 -
遍历数组,如果当前元素小于基准值,则将其与索引
i
指向的元素交换,并将i
加1。 -
最后将基准值与索引
i
指向的元素交换,此时基准值的位置就是它最终的位置。 -
递归地对基准值左边的子数组和右边的子数组进行快速排序。
Hoare划分的实现步骤如下:
-
选择左边的元素作为基准值。
-
初始化两个索引变量
i
和j
,分别指向数组的左右两端。 -
从左往右找到第一个大于基准值的元素,从右往左找到第一个小于基准值的元素,然后交换这两个元素。
-
重复步骤3,直到
i
大于等于j
。 -
最后将基准值与索引
j
指向的元素交换,此时基准值的位置就是它最终的位置。 -
递归地对基准值左边的子数组和右边的子数组进行快速排序。
快速排序的平均时间复杂度为O(nlogn),最坏情况下的时间复杂度为O(n^2),空间复杂度为O(logn)。快速排序通常比其他排序算法更快,尤其是对于大规模数据集。
算法实现示例(使用Python):
def quick_sort(lst):
if len(lst) <= 1:
return lst
pivot = lst[0]
less = [x for x in lst[1:] if x <= pivot]
greater = [x for x in lst[1:] if x > pivot]
return quick_sort(less) + [pivot] + quick_sort(greater)
# 示例输入
lst = [5, 2, 9, 1, 3, 7]
# 调用快速排序算法
sorted_lst = quick_sort(lst)
# 输出排序结果
print(sorted_lst)
输出结果:
[1, 2, 3, 5, 7, 9]
以下是使用Java语言实现快速排序算法的示例代码:
public class QuickSort {
public static void main(String[] args) {
int[] arr = {7, 2, 1, 6, 8, 5, 3, 4};
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pivot = partition(arr, low, high);
quickSort(arr, low, pivot - 1);
quickSort(arr, pivot + 1, high);
}
}
public static int partition(int[] arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
swap(arr, i, j);
}
}
swap(arr, i + 1, high);
return i + 1;
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
在这个例子中,我们定义了一个quickSort
方法来执行快速排序算法。该方法接受要排序的数组arr
、要排序的起始位置low
和结束位置high
作为参数。在每次递归调用中,我们选择一个pivot
元素作为基准,并将数组分成两部分。较小的元素被放在基准的左边,较大的元素被放在基准的右边。然后,我们递归地对左边部分和右边部分进行排序,直到整个数组有序。
在分区过程中,我们使用partition
方法将数组划分为两部分。该方法选择最后一个元素作为基准,然后将小于基准的元素移到基准的左边,大于基准的元素移到基准的右边。最后,我们将基准元素放到正确的位置,并返回基准元素的索引。
最后,我们在main
方法中创建一个示例数组,并调用quickSort
方法对其进行排序。然后,我们使用Arrays.toString
方法打印排序后的数组。
以下是使用C语言实现快速排序算法的代码:
#include <stdio.h>
// 交换两个元素的值
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 找到基准元素应该在的位置
int partition(int arr[], int low, int high) {
int pivot = arr[high]; // 选择最后一个元素作为基准元素
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return i + 1;
}
// 快速排序函数
void quickSort(int arr[], int low, int high) {
if (low < high) {
// 找到基准元素的位置
int pi = partition(arr, low, high);
// 对基准元素左边的子数组进行快速排序
quickSort(arr, low, pi - 1);
// 对基准元素右边的子数组进行快速排序
quickSort(arr, pi + 1, high);
}
}
// 打印数组元素
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr[] = {5, 9, 2, 6, 1, 8, 3, 7, 4};
int size = sizeof(arr) / sizeof(arr[0]);
printf("原始数组:");
printArray(arr, size);
quickSort(arr, 0, size - 1);
printf("排序后的数组:");
printArray(arr, size);
return 0;
}
以上代码实现了快速排序算法。在partition
函数中,选择最后一个元素作为基准元素,通过比较将小于基准元素的元素移动到基准元素的左边,大于基准元素的元素移动到基准元素的右边。然后递归地对基准元素左边的子数组和右边的子数组进行快速排序。最后通过printArray
函数打印排序后的数组。
快速排序的时间复杂度为O(nlogn),是一种高效的排序算法。
几个做法:
两端往中间走:在l>k>r时交换;
挖坑移树法:也是两端往中间走,将Key位腾出来,存放L和R碰到的大和小的数据,
前后指针(交换小的在前):如图,重点讲,是前面两种做法的进化版,目前也是用的比较多的。
思路:
大原则(跟前面一样):用一个Key来分割所有数据成为“<K<”,然后继续前后分别递归继续;
分割时:用一个cur游标,从头找到尾,找出小的数据放到“后面队列”,用一个Prev(后面队列的车头)来推动大的数据将cur发现的小数交换到后面。