数据结构-快速排序
一.概要
快速排序是一种基于分治思想的排序算法,其基本思路是选取一个基准值(pivot),通过一趟排序将待排序列分成两个部分,其中左半部分都小于基准值,右半部分都大于基准值,然后对左右两部分分别递归地进行快速排序,最终得到有序序列。
具体的实现过程如下:
- 选取基准值
任意选定一个数作为基准值。
- 分割操作
设定两个指针,左指针和右指针,分别指向序列的开头和结尾。从右指针开始向左扫描,找到第一个小于基准值的元素,将其与左指针所指的元素交换位置。然后从左指针开始向右扫描,找到第一个大于基准值的元素,将其与右指针所指的元素交换位置。重复以上过程,直到左指针与右指针相遇,此时将基准值与相遇位置的元素交换。
- 递归操作
递归地对左右两部分分别进行快速排序,直到每个部分只有一个元素或为空。
最终得到一个有序序列。
快速排序的时间复杂度是 O(nlogn),平均情况下比较快,最坏情况下为 O(n^2),是一种不稳定的排序算法。在实际应用中,可以通过随机选择基准值、三数取中等方法来避免出现最坏情况,提高排序效率。
二、代码实现
int GetMidNumi(int* a, int left, int right)
{int mid = (left + right) / 2;if (a[left]<a[mid]){if (a[mid]<a[right]){return mid;}else if (a[left]>a[right]){return left;}else{return right;}}else{if (a[mid]>a[right]){return mid;}else if(a[left]<a[right]){return left;}else{return right;}}
}void QuickSort(int* a, int left, int right){if (left > right)return;int begin = left, end = right;//随机选KEY//int randi = left + (rand() % (right - left));//Swap(&a[left], &a[randi]);//三数取中int midi = GetMidNumi(a, left, right);Swap( &a[midi], &a[left]);int keyi = left;while (left < right){//右边找小while (left < right && a[right] >= a[keyi])--right;//左边找大while (left < right && a[left] <= a[keyi])++left;Swap(&a[left], &a[right]);}Swap(&a[keyi], &a[left]);keyi = left;QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);
}
这段代码是实现快速排序的程序,具体工作流程如下:
- 选取关键字 keyi,一般选择序列中的第一个元素。
- 从序列的两端开始搜索,右边找到小于keyi的元素,左边找到大于keyi的元素,然后交换这两个元素的位置。
- 继续执行步骤2,直到左右指针相遇。
- 将关键字 keyi 与相遇位置的元素交换位置。
- 递归地对左右两部分分别进行快速排序。
在实现过程中,该程序使用了三数取中的方法来选择关键字,避免了最坏情况的发生。同时,在搜索元素时,也采用了双向搜索的方法,提高了排序效率。
整个快速排序的时间复杂度为 O(nlogn),最坏情况下为 O(n^2),空间复杂度为 O(logn),是一种高效的排序算法。
三、总结
快速排序是一种基于分治思想的排序算法。其基本思想是选取一个基准值,通过一趟排序将待排序列分成两个部分,其中左半部分都小于基准值,右半部分都大于基准值,然后对左右两部分分别递归地进行快速排序,最终得到有序序列。
快速排序具有以下优点:
时间复杂度较低:平均时间复杂度为 O(nlogn),在实践中表现良好,较适合大规模数据的排序。
空间复杂度较低:空间复杂度为 O(logn),不需要额外的存储空间,能够节省内存。
实现简单:快速排序的实现比较简单,易于理解和掌握。
但是快速排序也存在以下缺点:
最坏情况下时间复杂度较高:在某些特殊情况下,如原序列已经排好序或基准值选择不当时,快速排序的时间复杂度会退化到 O(n^2)。
不适合稳定性排序:由于交换过程不一定保证元素的相对位置不变,因此快速排序不适合对序列中有相同元素的数据进行排序。
针对上述缺点,可以采用以下方法来改进快速排序:
随机选取基准值:避免最坏情况的发生,提高排序效率。
三数取中法选取基准值:通过选取序列头、尾和中间位置的元素的中位数作为基准值,避免最坏情况的发生,提高排序效率。
在小规模数据时采用插入排序:当待排序的子序列长度小于一定值时,采用插入排序代替快速排序,可以降低算法的时间复杂度。