排序算法——快速排序

快速排序算法由于它的方便和高效在实践中一直得到广泛的应用,是排序算法中非常值得学习和掌握的一种。

思想

设定被排序的数组是A,快速排序算法的基本思想是用数组的首元素作为标准将A划分成前、后两个部分,比首元素小的元素构成数组的前部分,比首元素大的元素构成数组的后部分。这两个部分构成两个新的子问题,算法接着分别对这两部分递归地进行排序。算法的关键在于怎样划分数组A而将其归约成两个子问题。这里用到了分治的算法思想。

先从后向前扫描数组A,找到第一个不大于A[p]的元素A[j],然后再从前往后扫描数组A,找到第一个不小于A[p]的元素A[i],当i<j时,交换A[i]与A[j]的值。这时候A[j]后面的元素都大于A[p],A[i]前边的数都小于A[p]。然后继续进行扫描,直到i>j时,就岱庙了A[p]在排好序的数组中的正确位置q,然后将A[p]与A[q]的值交换,一次排序就完成了。然后将位置q左右的数组元素,分成两个部分,再次递归调用排序算法。

代码

void QuickSort(int numArr[], int p, int r)
{
    int q;
    if(p<r)
    {
        q = Partition(numArr,p,r);
        QuickSort(numArr,p,q-1);
        QuickSort(numArr,q+1,r);
    }
}
int Partition(int numArr[],int p, int r)
{
    int x = numArr[p];
    int i = p;
    int j = r;

    while(1)
    {
        while(numArr[j]>x)
            j--;
        while(numArr[i]<x)
            i++;
        if(i<j)
        {
            int temp = numArr[i];
            numArr[i] = numArr[j];
            numArr[j] = temp;
        }
        else
            return j;
    }
}


分析

下面对这个算法进行实践复杂度分析,首先说明划分过程的工作量是O(n),因为每个元素都需要和首元素进行1次比较。除了这个工作量外,就是两个子问题递归调用的工作量。在最坏的情况下,比如说逆序排列,那么子问题的规模每次都接近于当前的数组大小,那么它的递推方程就成为T(n) = T(n-1) + O(n),也就是说,它的时间复杂度为O(n^2)。

在一般的情况下,每一个子问题的规模都接近于n/2,那么在这样的情况下,递推方程就是T(n) = 2T(n/2) + O(n),根据主定理,可以得知它的时间复杂度为O(nlogn)。这是快速排序最好的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MPI和OpenMP都是并行程序设计的重要工具,可以实现高效的并行计算。下面介绍两种基于MPI+OpenMP的并行排序算法:归并排序和快速排序。 ## 归并排序 归并排序是一种分治算法,它将待排序的数组分成两个子数组,分别排序,然后将已排序的子数组合并成一个更大的有序数组。该算法的时间复杂度为O(nlogn)。 ### 并行实现 1. 每个进程读取并分配一部分待排序数据。 2. 每个进程使用OpenMP并行进行归并排序。 3. 将每个进程排序后的子数组发送到Master进程。 4. Master进程使用归并操作合并每个子数组,得到最终的有序数组。 代码实现如下: ```c++ #include <stdio.h> #include <stdlib.h> #include <mpi.h> #include <omp.h> void merge(int *arr, int left, int mid, int right) { int i, j, k; int n1 = mid - left + 1; int n2 = right - mid; int L[n1], R[n2]; for (i = 0; i < n1; i++) L[i] = arr[left + i]; for (j = 0; j < n2; j++) R[j] = arr[mid + 1 + j]; i = 0; j = 0; k = left; while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } while (i < n1) { arr[k] = L[i]; i++; k++; } while (j < n2) { arr[k] = R[j]; j++; k++; } } void mergeSort(int *arr, int left, int right) { if (left < right) { int mid = left + (right - left) / 2; #pragma omp parallel sections { #pragma omp section { mergeSort(arr, left, mid); } #pragma omp section { mergeSort(arr, mid + 1, right); } } merge(arr, left, mid, right); } } int main(int argc, char **argv) { int *data = NULL; int *sub_data = NULL; int *sub_sorted_data = NULL; int n = 1000000; int i, j, k, p, rank, size; double start, end; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); sub_data = (int *)malloc(n / size * sizeof(int)); sub_sorted_data = (int *)malloc(n / size * sizeof(int)); if (rank == 0) { data = (int *)malloc(n * sizeof(int)); for (i = 0; i < n; i++) { data[i] = rand() % n; } } start = MPI_Wtime(); MPI_Scatter(data, n / size, MPI_INT, sub_data, n / size, MPI_INT, 0, MPI_COMM_WORLD); mergeSort(sub_data, 0, n / size - 1); MPI_Gather(sub_data, n / size, MPI_INT, data, n / size, MPI_INT, 0, MPI_COMM_WORLD); if (rank == 0) { int *temp = (int *)malloc(n * sizeof(int)); for (i = 0; i < size; i++) { for (j = 0; j < n / size; j++) { temp[i * n / size + j] = data[i + j * size]; } } mergeSort(temp, 0, n - 1); free(temp); } end = MPI_Wtime(); if (rank == 0) { printf("Time: %lf seconds\n", end - start); } MPI_Finalize(); free(data); free(sub_data); free(sub_sorted_data); return 0; } ``` ## 快速排序 快速排序是一种分治算法,它通过选择一个基准元素,将数组分成两个子数组,其中一个子数组中的元素都小于基准元素,另一个子数组中的元素都大于基准元素,然后递归地排序子数组。该算法的时间复杂度为O(nlogn)。 ### 并行实现 1. 每个进程读取并分配一部分待排序数据。 2. 每个进程使用OpenMP并行进行快速排序。 3. 将每个进程排序后的子数组发送到Master进程。 4. Master进程使用归并操作合并每个子数组,得到最终的有序数组。 代码实现如下: ```c++ #include <stdio.h> #include <stdlib.h> #include <mpi.h> #include <omp.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; int j; #pragma omp parallel for for (j = low; j <= high - 1; 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); #pragma omp parallel sections { #pragma omp section { quickSort(arr, low, pi - 1); } #pragma omp section { quickSort(arr, pi + 1, high); } } } } int main(int argc, char **argv) { int *data = NULL; int *sub_data = NULL; int *sub_sorted_data = NULL; int n = 1000000; int i, j, k, p, rank, size; double start, end; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); sub_data = (int *)malloc(n / size * sizeof(int)); sub_sorted_data = (int *)malloc(n / size * sizeof(int)); if (rank == 0) { data = (int *)malloc(n * sizeof(int)); for (i = 0; i < n; i++) { data[i] = rand() % n; } } start = MPI_Wtime(); MPI_Scatter(data, n / size, MPI_INT, sub_data, n / size, MPI_INT, 0, MPI_COMM_WORLD); quickSort(sub_data, 0, n / size - 1); MPI_Gather(sub_data, n / size, MPI_INT, data, n / size, MPI_INT, 0, MPI_COMM_WORLD); if (rank == 0) { int *temp = (int *)malloc(n * sizeof(int)); for (i = 0; i < size; i++) { for (j = 0; j < n / size; j++) { temp[i * n / size + j] = data[i + j * size]; } } quickSort(temp, 0, n - 1); free(temp); } end = MPI_Wtime(); if (rank == 0) { printf("Time: %lf seconds\n", end - start); } MPI_Finalize(); free(data); free(sub_data); free(sub_sorted_data); return 0; } ``` 以上两种算法都可以通过MPI+OpenMP实现并行排序,提高了算法的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值