快排是一种高效的数据结构,它使用一个关键字(Key)来表示数据元素的一个集合。也就是说,快排是一个有序数组,而这个有序数组由两个元素组成。 快排的基本思想是:如果数组元素的值比它前面的两个元素都大,则它们被排在一起,如果小于这个数组的元素值,则它们被排在一起。例如:a+b=c这句话中,a就是一个关键字“a”,b就是一个关键字“b”,c就是一个关键字“c”。 快排和其他数据结构相比的特点主要有以下几点: 1、快排不需要额外存储空间; 2、快排算法是线性的,而且空间复杂度为O (1); 3、快排比较适合于数据量较小的场景下使用; 5、快排不适合用于插入和删除操作。 下面就介绍一下快排的一些概念: 1、快排数组是有序数组,即:元素的值小于或者等于其前面两个元素值之和; 2、当数组元素大于等于两个元素时,快排数组就被称为空数组;
-
1、快排简介
快排是一种线性排序,也就是说,快排是按照关键字(key)进行排序的,即:当数组中的关键字小于数组中的元素时,我们就将数组中的关键字加到这个数组的前面;当关键字大于数组中的元素时,我们就将数组中的关键字减到后面。 在 Java语言中,快排是以关键字(Key)为基准对数组进行排序的,在 Java语言中,可以使用java.lang.re cv ()函数来进行操作。但是需要注意的是,在 Java中使用关键字(Key)来进行排序是一种非常简单的方式,因为关键字是我们自己定义的,它只是一个对象。 在 Java语言中有许多内置类来实现快排算法。这些类中有些是以关键字作为参数使用的,比如:dependency_count ()、dependency_parent ()和dependency_region ()。有些是以关键字作为参数使用的,比如: next、 list和 table。 下面介绍几种常见的内置快排算法。
-
2、快排的时间复杂度
在 Java中,快排的时间复杂度是O (1),但是在其它编程语言中,快排的时间复杂度可能会更高一些。具体来说,不同语言对快排的时间复杂度的定义可能会有所不同。例如, Python和 Java对于快排时间复杂度的定义可能是不一样的。 在 Java中,快排的时间复杂度是O (1),而在 Python中则是O (logN)。对于不同语言,快排的时间复杂度可能会有所不同,这是因为不同语言在处理数据结构时使用了不同的算法。例如,对于 Python来说,当数组中元素个数小于等于2时,就需要将它们放入空数组中;而对于 Java来说,当数组中元素个数大于2时,就需要将它们放入空数组中。 与之相比,在不同语言中使用了不同的算法来处理数据结构时,快排所需要做的操作也不一样。那么对于不同语言来说,快排的时间复杂度是一样的吗?答案是不一定。例如在 Python中使用了递归算法来处理数组元素个数大于等于2时所做的操作;而在 Java中则使用了循环算法来处理数组元素个数大于等于2时所做的操作。
-
3、快排数组大小计算公式
上面的公式是快排大小计算公式,但是在实际应用中,快排并不是按这个公式来计算的,因为如果按照这个公式来计算,那么在判断数组是否小于或者等于两个元素时,我们要先判断一个数组的元素是否大于或者等于两个元素,然后再判断数组元素是否小于或者等于两个元素。 但是在实际应用中,我们往往会忽略一个问题,就是我们不能仅凭一个简单的计算公式来判断数组的大小。在下面的例子中,如果我们输入a和b两个关键字,计算结果是2个关键字之和,那么我们就认为这两个关键字是大于的。但是实际上并非如此,因为我们还有一个判断条件:如果a大于b小于1。所以我们认为这两个关键字是小于的。而快排中的判断条件就是:a+b<1。 所以当我们输入a和b两个关键字时,计算结果就变成了a+b<1和a+b>2。 上面这个例子就是一个简单的快排问题,但是如果把输入范围扩展到三个关键字时,那么就会出现问题了。 比如这样一个例子: 这是一个快排问题的简化版:输入a和b后,计算结果是1和2。因为输入a大于等于2和a小于等于1这两个关键字时,我们认为这个数组就是大于的。但是实际上并非如此,因为快排计算结果不一定就是大于1和小于1这两个关键字之和。当输入a大于2和b时,计算结果是2+3<2+4<2+5=6-5>2+6=7-5;当输入b大于2和c时,计算结果是3-3=4-3>2+3
-
4、快排的插入与删除操作
快排的插入与删除操作和数组的元素个数有关。数组中的元素个数大于或小于两个时,则插入操作发生,否则删除操作发生。插入操作是指在数组中先插入一个新的关键字,然后删除原来数组中的一个关键字,再将新插入的关键字和原来数组中的一个关键字合并为新数组的过程。 我们在 Java中可以使用两种方法来实现快排的插入与删除操作。 第一种方法是:当数据量不大时,我们可以使用双指针实现快排插入与删除操作,其中一个指针指向新插入的关键字,另一个指针指向旧插入的关键字。单链表是一种特殊的链表,它能够保证数据在链表中以固定顺序有序存储。 由于快排是线性结构,因此可以使用二分查找来实现快排插入与删除操作。 二分查找是指在给定时间内返回指定大小(n)个元素所占用空间(n)个元素的查找方法。例如:给定一个时间长度为T=2,我们可以使用二分查找来找到T在2-T之间所有可能位置上的值。
-
5、快排算法的优缺点
快排算法的优点: 1、快排算法是一种线性的数据结构,只需要O (1)个运算即可完成。对于中等大小的数据,快排比其他数据结构要快; 比如,你有一个100人的班级,你想知道每个学生的名字,你可以用快排算法来实现。 1、快排算法只适合于有序数组,而不适合于无序数组。 2、如果数组中有很多关键字相同的元素,那么就会导致在查找时会很慢。
-
以下是三种常用的 Java 快速排序代码:
1. 递归实现
```java
public static void quickSort(int[] arr, int left, int right) {
if (left < right) {
int pivotIndex = partition(arr, left, right);
quickSort(arr, left, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, right);
}
}
public static int partition(int[] arr, int left, int right) {
int pivot = arr[left];
int i = left + 1;
int j = right;
while (i <= j) {
while (i <= j && arr[i] <= pivot) {
i++;
}
while (i <= j && arr[j] > pivot) {
j--;
}
if (i < j) {
swap(arr, i, j);
}
}
swap(arr, left, j);
return j;
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
```
2. 非递归实现
```java
public static void quickSort(int[] arr, int left, int right) {
Stack<Integer> stack = new Stack<>();
stack.push(left);
stack.push(right);
while (!stack.isEmpty()) {
int r = stack.pop();
int l = stack.pop();
if (l < r) {
int pivotIndex = partition(arr, l, r);
stack.push(l);
stack.push(pivotIndex - 1);
stack.push(pivotIndex + 1);
stack.push(r);
}
}
}
public static int partition(int[] arr, int left, int right) {
int pivot = arr[left];
int i = left + 1;
int j = right;
while (i <= j) {
while (i <= j && arr[i] <= pivot) {
i++;
}
while (i <= j && arr[j] > pivot) {
j--;
}
if (i < j) {
swap(arr, i, j);
}
}
swap(arr, left, j);
return j;
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
```
3. 双路快排
```java
public static void quickSort(int[] arr, int left, int right) {
if (left < right) {
int[] pivotIndex = partition(arr, left, right);
quickSort(arr, left, pivotIndex[0] - 1);
quickSort(arr, pivotIndex[1] + 1, right);
}
}
public static int[] partition(int[] arr, int left, int right) {
int pivot = arr[left];
int i = left + 1;
int j = right;
int p = left;
int q = right + 1;
while (true) {
while (i <= j && arr[i] < pivot) {
i++;
}
while (i <= j && arr[j] > pivot) {
j--;
}
if (i > j) {
break;
}
swap(arr, i, j);
if (arr[i] == pivot) {
p++;
swap(arr, p, i);
}
if (arr[j] == pivot) {
q--;
swap(arr, q, j);
}
}
swap(arr, left, j);
j--;
i++;
for (int k = left + 1; k <= p; k++, j--) {
swap(arr, k, j);
}
for (int k = right; k >= q; k--, i++) {
swap(arr, k, i);
}
return new int[]{j + 1, i - 1};
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
```