算法系列—快速排序及其优化(递归)

来源:互联网 发布:java做贪吃蛇游戏 编辑:程序博客网 时间:2024/04/30 09:49

快速排序和归并排序是互补的,归并排序将子数组分成两个子数组分别排序,并将有序的子数组归并以将整个数组排序。而快速排序则是当两个子数组有序时整个数组也就自然有序了。

归并排序:递归调用发生在整个数组处理之前,一个数组被等分为两半。

快速排序:递归调用发生在处理整个数组之后,切分的位置取决于数组的内容。

初步实现如下:

#include <iostream>#include <algorithm>void sort(int A[], int lo, int hi);int partition(int A[], int lo, int hi);void QuickSort(int A[], int size){std::random_shuffle(A, A + size - 1);//打乱数组sort(A, 0, size - 1);}void sort(int A[],int lo,int hi){if (lo >= hi)return;int j=partition(A, lo, hi);sort(A, lo, j - 1);sort(A, j + 1, hi);}int partition(int A[],int lo,int hi){//将数组切分为A[lo...i-1],A[i],A[i+1...hi]int i = lo, j = hi + 1; //扫描指针int a = A[lo];//切分元素while(true){while (A[++i] < a);//左侧元素小于切分元素则继续比较下一个while (A[--j] > a);//右侧元素大于切分元素则比较下一个if (i > j)//当两个指针相遇break;std::swap(A[i], A[j]);}std::swap(A[lo], A[j]);//扫描指针相遇后将切分元素放入正确位置return j;}int main(){int A[] = { 1,4,6,4,7,4,10,50,88,2,33,56,3,345,66,67,4 };QuickSort(A, sizeof(A) / 4);for (auto a : A){std::cout << a << " ";}}

random_shuffle()打乱数组的目的:快速排序在切分不平衡时程序可能会极为低效,比如第一次从第一小的元素开始切分,第二次从第二小的元素开始切分。。在快速排序前将数组打乱就是为了避免这种情况。


算法改进:

(1)对于小数组,快速排序比插入排序慢,因此排序小数组时切换到插入排序

将sort中的语句if(hi<=lo) return; 

改为

if(hi<=lo+M)

{

//插入排序

return;

}


(2)三取样切分

实际应用中常会出现大量重复元素的数组,一个简单的方法是将数组切分为三部分,分别小于,等于和大于切分元素。

思路:从左到右遍历数组一次,维护一个指针lt使得A[lo...lt-1]中的元素都小于切分元素。一个指针gt,使得A[gt+1...hi]中的元素都大于切分元素。一个指针i使得A[lt...i-1]中的元素都等于切分元素,A[i...gt]中的元素还不确定。

比较时:

A[i]小于切分元素,将A[lt]和A[i]交换,lt和i加一

A[i]大于切分元素,将A[gt]和A[i]交换,gt减一

A[i]等于切分元素,将i加一.。


三取样切分的快速排序如下:

#include <iostream>#include <algorithm>void sort(int A[], int lo, int hi);void QuickSort(int A[], int size){std::random_shuffle(A, A + size - 1);//打乱数组sort(A, 0, size - 1);}void sort(int A[], int lo, int hi){if (lo >= hi)  //如果越界return;int lt = lo, i = lo + 1, gt = hi;int v = A[lo];//切分元素while (i <= gt){if (A[i] < v)std::swap(A[i++], A[lt++]);else if (A[i] == v)i++;else {std::swap(A[i], A[gt--]);}}//sort(A, lo, lt - 1);sort(A, gt + 1, hi);}int main(){int A[] = { 1,4,6,4,7,4,10,50,88,2,33,56,3,345,66,67,4 };QuickSort(A, sizeof(A) / 4);for (auto a : A){std::cout << a << " ";}}



0 0
原创粉丝点击