快速排序

快速排序是由英国计算机科学家 Tony Hoare 在1960年提出的一种排序算法,也被称为“划分交换排序”(partition-exchange sort)。Tony Hoare在发表论文时将其称为“快速排序”,并且很快成为了一种广泛应用的排序算法。

然而,快速排序的思想并非完全由Hoare创造。早在1951年,美国计算机科学家并行排序提出了一种类似的原理,但当时并没有被广泛应用。

快速排序的基本思想是通过将待排序序列分割成较小的子序列,然后分别对子序列进行排序,最终将所有子序列排序完成。具体而言,快速排序的过程如下:

  1. 选择一个元素作为基准(pivot)。
  2. 将所有比基准值小的元素放在基准值的左边,比基准值大的元素放在基准值的右边。
  3. 对基准值左右两边的子序列递归地重复步骤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),并且具有原地排序的特点(即不需要额外的存储空间)。因此,快速排序成为了一种常用的排序算法,被广泛应用于各种情况下的排序问题。

快速排序是一种常用的排序算法,它通过选择一个基准元素,将数组分为两个部分,一个部分是小于基准元素的,一个部分是大于基准元素的,并且递归地对两个部分进行排序。

具体算法如下:

  1. 选择一个基准元素,一般选取数组的第一个元素。
  2. 将数组划分为两个部分,小于基准元素的放在左边,大于基准元素的放在右边。
  3. 递归地对左右两个部分进行快速排序。
  4. 合并左右两个部分。

快速排序是一种高效的排序算法,其基本思想是通过不断地将数组分割为两部分,并递归地对每个部分进行排序,最终使整个数组有序。

快速排序的关键是如何选择基准值和如何进行数组的划分。一种常用的方法是使用Lomuto划分或Hoare划分。

Lomuto划分的实现步骤如下:

  1. 选择最右边的元素作为基准值。

  2. 初始化一个索引变量i,用于指示当前小于基准值的元素的位置。

  3. 遍历数组,如果当前元素小于基准值,则将其与索引i指向的元素交换,并将i加1。

  4. 最后将基准值与索引i指向的元素交换,此时基准值的位置就是它最终的位置。

  5. 递归地对基准值左边的子数组和右边的子数组进行快速排序。

Hoare划分的实现步骤如下:

  1. 选择左边的元素作为基准值。

  2. 初始化两个索引变量ij,分别指向数组的左右两端。

  3. 从左往右找到第一个大于基准值的元素,从右往左找到第一个小于基准值的元素,然后交换这两个元素。

  4. 重复步骤3,直到i大于等于j

  5. 最后将基准值与索引j指向的元素交换,此时基准值的位置就是它最终的位置。

  6. 递归地对基准值左边的子数组和右边的子数组进行快速排序。

快速排序的平均时间复杂度为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发现的小数交换到后面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值