问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

C语言如何用数组实现快速排序

创作时间:
作者:
@小白创作中心

C语言如何用数组实现快速排序

引用
1
来源
1.
https://docs.pingcode.com/baike/1040698

快速排序是一种高效的排序算法,基于分治法的递归排序算法,在平均情况下具有O(n log n)的时间复杂度。它通过选择一个“基准”元素,将数组分成两部分,再递归地排序这两部分。本文将详细介绍如何在C语言中用数组实现快速排序,并结合实际代码示例进行说明。

一、快速排序的基本概念和原理

快速排序(Quicksort)是由Tony Hoare在1960年提出的。它的基本思想是通过一个基准值将数组分成两个子数组,使得左子数组的所有元素都小于基准值,而右子数组的所有元素都大于基准值,然后递归地对这两个子数组进行排序。

1.1 基本步骤

  1. 选择基准值:通常选择数组的第一个元素、最后一个元素或中间元素作为基准值。
  2. 分区操作:通过一趟排序将数组分为两部分,左边部分小于等于基准值,右边部分大于等于基准值。
  3. 递归排序:对分区后的两个子数组继续进行快速排序。

1.2 时间复杂度

  • 平均时间复杂度:O(n log n)
  • 最坏时间复杂度:O(n^2)(当每次选择的基准值是数组的最大或最小值时)
  • 空间复杂度:O(log n)(递归调用使用的栈空间)

二、在C语言中实现快速排序

为了在C语言中实现快速排序,我们需要实现以下几个部分:

  1. 交换函数:用于交换数组中的两个元素。
  2. 分区函数:用于将数组分成两部分。
  3. 快速排序函数:用于递归地排序数组。

2.1 交换函数

交换函数用于交换数组中的两个元素,代码如下:

void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

2.2 分区函数

分区函数用于将数组分成两部分,使得左边部分小于等于基准值,右边部分大于等于基准值。代码如下:

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;
}

2.3 快速排序函数

快速排序函数用于递归地排序数组,代码如下:

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);
    }
}

2.4 主函数

主函数用于测试快速排序算法,代码如下:

#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[] = {10, 7, 8, 9, 1, 5};
    int n = sizeof(arr) / sizeof(arr[0]);
    quicksort(arr, 0, n - 1);
    printf("Sorted array: \n");
    printArray(arr, n);
    return 0;
}

三、快速排序的优化

尽管快速排序在平均情况下具有O(n log n)的时间复杂度,但在最坏情况下可能退化到O(n^2)。为了避免这种情况,可以采取以下几种优化措施:

3.1 随机选择基准值

通过随机选择基准值,可以减少最坏情况发生的概率。具体做法是在分区前随机选择一个元素作为基准值,并将其与当前基准值交换。

#include <stdlib.h>

int randomPartition(int arr[], int low, int high) {
    int randomPivot = low + rand() % (high - low + 1);
    swap(&arr[randomPivot], &arr[high]);
    return partition(arr, low, high);
}

void quicksort(int arr[], int low, int high) {
    if (low < high) {
        int pi = randomPartition(arr, low, high);
        quicksort(arr, low, pi - 1);
        quicksort(arr, pi + 1, high);
    }
}

3.2 三向切分快速排序

在处理包含大量重复元素的数组时,三向切分快速排序可以显著提高效率。其基本思想是将数组分为三部分:小于基准值的部分、等于基准值的部分和大于基准值的部分。

void quicksort3way(int arr[], int low, int high) {
    if (low < high) {
        int lt = low, gt = high;
        int pivot = arr[low];
        int i = low;
        while (i <= gt) {
            if (arr[i] < pivot) {
                swap(&arr[lt], &arr[i]);
                lt++;
                i++;
            } else if (arr[i] > pivot) {
                swap(&arr[i], &arr[gt]);
                gt--;
            } else {
                i++;
            }
        }
        quicksort3way(arr, low, lt - 1);
        quicksort3way(arr, gt + 1, high);
    }
}

四、快速排序的应用场景和注意事项

快速排序在实际应用中具有广泛的应用场景,但在使用时也需要注意一些事项。

4.1 适用场景

  • 适用于大多数情况:快速排序在平均情况下表现优秀,适用于大多数需要排序的场景。
  • 适用于内存限制较小的情况:快速排序的空间复杂度较低,适用于内存限制较小的情况。

4.2 注意事项

  • 避免最坏情况:通过随机选择基准值或三向切分快速排序,可以有效避免最坏情况的发生。
  • 处理小数组:对于较小的数组,可以使用插入排序等其他排序算法,以减少递归开销。
  • 递归深度:在递归调用快速排序时,需要注意递归深度,防止栈溢出。

五、快速排序的性能分析和比较

在实际应用中,快速排序与其他排序算法相比具有较高的性能,但在某些特定情况下,其他排序算法可能表现更好。

5.1 与归并排序比较

  • 时间复杂度:快速排序在平均情况下具有O(n log n)的时间复杂度,而归并排序的时间复杂度为O(n log n)。
  • 空间复杂度:快速排序的空间复杂度为O(log n),而归并排序的空间复杂度为O(n)。
  • 适用场景:快速排序适用于大多数情况,而归并排序适用于需要稳定排序或处理大规模数据的情况。

5.2 与堆排序比较

  • 时间复杂度:快速排序在平均情况下具有O(n log n)的时间复杂度,而堆排序的时间复杂度为O(n log n)。
  • 空间复杂度:快速排序的空间复杂度为O(log n),而堆排序的空间复杂度为O(1)。
  • 适用场景:快速排序适用于大多数情况,而堆排序适用于需要稳定排序或处理大规模数据的情况。

六、总结

快速排序是一种高效的排序算法,基于分治法的递归排序算法,具有O(n log n)的时间复杂度。通过选择基准值、分区操作和递归排序,可以实现对数组的快速排序。为了避免最坏情况的发生,可以采取随机选择基准值和三向切分快速排序等优化措施。在实际应用中,快速排序具有广泛的应用场景,但在使用时也需要注意一些事项,如避免最坏情况、处理小数组和递归深度等。通过与归并排序和堆排序的比较,可以更好地了解快速排序的性能和适用场景。

七、示例代码完整实现

以下是快速排序在C语言中的完整实现代码,包括优化措施和性能分析:

#include <stdio.h>
#include <stdlib.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;
}

int randomPartition(int arr[], int low, int high) {
    int randomPivot = low + rand() % (high - low + 1);
    swap(&arr[randomPivot], &arr[high]);
    return partition(arr, low, high);
}

void quicksort(int arr[], int low, int high) {
    if (low < high) {
        int pi = randomPartition(arr, low, high);
        quicksort(arr, low, pi - 1);
        quicksort(arr, pi + 1, high);
    }
}

void quicksort3way(int arr[], int low, int high) {
    if (low < high) {
        int lt = low, gt = high;
        int pivot = arr[low];
        int i = low;
        while (i <= gt) {
            if (arr[i] < pivot) {
                swap(&arr[lt], &arr[i]);
                lt++;
                i++;
            } else if (arr[i] > pivot) {
                swap(&arr[i], &arr[gt]);
                gt--;
            } else {
                i++;
            }
        }
        quicksort3way(arr, low, lt - 1);
        quicksort3way(arr, gt + 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[] = {10, 7, 8, 9, 1, 5};
    int n = sizeof(arr) / sizeof(arr[0]);
    quicksort(arr, 0, n - 1);
    printf("Sorted array using quicksort: \n");
    printArray(arr, n);

    int arr2[] = {10, 7, 8, 9, 1, 5, 10, 7, 8, 9, 1, 5};
    int m = sizeof(arr2) / sizeof(arr2[0]);
    quicksort3way(arr2, 0, m - 1);
    printf("Sorted array using 3-way quicksort: \n");
    printArray(arr2, m);
    return 0;
}

通过上述代码示例,可以清晰地了解如何在C语言中用数组实现快速排序,并进行优化和性能分析。希望这篇文章对你有所帮助!

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号