快速排序问题

目录

1.快速排序的原理

2.划分过程

3.划分函数的实现

4.快速排序的退化

5.随机选择策略

6.用队列实现快排


1.快速排序的原理

快速排序算法是基于分治策略的一个排序算法。其基本思想是,对于输入的子数组nums[left:right]按下3个步骤进行排序:

(1)分解(divide) :以nums[left]为基准元素将nums[left:right]划分成3段nums[left: mid-1],nums[mid]nums[mid+1:right],使得nums[left:mid-1]中任何元素小于等于nums[mid], nums[mid+1:right]中任何元素大于等于nums[right]。下标mid在划分过程中确定。

(2)递归求解(conquer) :通过递归调用快速排序算法,分别对nums[left:mid-1]和nums[mid+1:right]进行排序。

(3)合并(merge):由于对nums[left:mid-1]和nums[mid+1:right]的排序是就地进行的,所以在nums[left:mid-1]和nums[mid+1:right]都已排好的序后不需要执行任何计算,nums[left:right]就已排好序。

2.划分过程

 

 

 

 

 

 

 

 

 

3.划分函数的实现

代码:

int Partition(int* nums, int left, int right)
{
    int i = left, j = right;
    int tmp = nums[i];
    while (i < j)
    {
        while (i<j && nums[j]>tmp) --j;
            if (i < j)nums[i] = nums[j];
            while (i < j && nums[i] <= tmp) ++i;
            if (i < j)nums[j] = nums[i];
    }
    nums[i] = tmp;
    return i;
}

事实上,算法Partition的主要功能就是将小于tmp的元素放到数组的左半部分。而将大于tmp的元素放在数组的右半部分。其中有一些细节需要注意。算法中的下标i和j不会超出nums[left:right]的下标届。while循环中的“i<j”就是防止越界。

代码实现:

void PrintInt(const int* nums, int n)
{
    for (int i = 0; i < n; i++)
    {
        cout << nums[i] << "    ";
    }
    cout << endl;
}
int Partition(int* nums, int left, int right)
{
    int i = left, j = right;
    int tmp = nums[i];
    while (i < j)
    {
        while (i<j && nums[j]>tmp) --j;
            if (i < j)nums[i] = nums[j];
            while (i < j && nums[i] <= tmp) ++i;
            if (i < j)nums[j] = nums[i];
    }
    nums[i] = tmp;
    return i;
}
void QuickSort(int* nums, int left, int right)
{
    if (left < right)
    {
        int mid = Partition(nums, left, right);
        QuickSort(nums, left, mid - 1);
        QuickSort(nums, mid + 1, right);
    }
}
int main()
{
    int arr[] = { 56,23,78,45,90,89,12,34,67,89,100 };
    int n = sizeof(arr) / sizeof(arr[0]);
    PrintInt(arr, n);
    QuickSort(arr, 0, n - 1);
    PrintInt(arr, n);
    return 0;
}

4.快速排序的退化

当数组有序:

{12,23,34,45,56,67,78,89,90,100}

{100,   90,   89,  78,   67,   56,   45,   34,   23,   12}

分析:

      快速排序的运行时间与划分是否对称有关,其最坏情况发生在划分过程产生的两个区域分别包含n-1个元素和1个元素的时候。由于算法Partition的计算时间为O(n),如果算法Partition的每一步都出现这种不对称划分:

 在最好情况下,每次划分所取的基准都恰好为中值,即每次划分都产生两个大小为n/2的区域:

5.随机选择策略

       快速排序算法的性能取决于划分的对称性。通过修改算法 partition,可以设计出采用随机选择策略的快速排序算法。在快速排序算法的每一步中,当数组还没有被划分时,可以在nums[left:right]中随机选出一个元素作为划分基准,这样可以使划分基准的选择是随机的,从而可以期望划分是比较对称的。

随机化的划分算法代码实现:

int RandomPartition(int* nums, int left, int right)
{
    srand(time(nullptr));
    int rapos = (rand() % (right - left + 1)) + left;
    std::swap(nums[left], nums[rapos]);
    return Partition(nums, left, right);
}

代码实现:

void PrintInt(const int* nums, int n)
{
    for (int i = 0; i < n; i++)
    {
        cout << nums[i] << "    ";
    }
    cout << endl;
}
int Partition(int* nums, int left, int right)
{
    int i = left, j = right;
    int tmp = nums[i];
    while (i < j)
    {
        while (i<j && nums[j]>tmp) --j;
            if (i < j)nums[i] = nums[j];
            while (i < j && nums[i] <= tmp) ++i;
            if (i < j)nums[j] = nums[i];
    }
    nums[i] = tmp;
    return i;
}
int RandomPartition(int* nums, int left, int right)
{
    srand(time(nullptr));
    int rapos = (rand() % (right - left + 1)) + left;
    std::swap(nums[left], nums[rapos]);
    return Partition(nums, left, right);
}
void QuickSort(int* nums, int left, int right)
{
    if (left < right)
    {
        int mid = RandomPartition(nums, left, right);
        QuickSort(nums, left, mid - 1);
        QuickSort(nums, mid + 1, right);
    }
}
int main()
{
    int arr[] = { 56,23,78,45,90,89,12,34,67,89,100 };
    int n = sizeof(arr) / sizeof(arr[0]);
    PrintInt(arr, n);
    QuickSort(arr, 0, n - 1);
    PrintInt(arr, n);
    return 0;
}

 

6.用队列实现快排

void QuickSort1(int* nums, int left, int right)//队列实现
{
    std::queue<int>qu;
    qu.push(left);
    qu.push(right);
    while (!qu.empty())
    {
        int sleft = qu.front();
        qu.pop();
        int sright = qu.front();
        qu.pop();
        int mid = Partition(nums, sleft, sright);
        if (sleft < sright)
        {
            qu.push(sleft);
            qu.push(mid - 1);
        }
        if (mid + 1 < sright)
        {
            qu.push(mid + 1);
            qu.push(sright);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值