zoukankan      html  css  js  c++  java
  • 快速排序算法分析和实现

    快速排序的思想:

    选择一个基准元素,比基准元素小的放基准元素的前面,比基准元素大的放基准元素的后面,这种动作叫分区,每次分区都把一个数列分成了两部分,每次分区都使得一个数字有序,然后将基准元素前面部分和后面部分继续分区,一直分区直到分区的区间中只有一个元素的时候,一个元素的序列肯定是有序的嘛,所以最后一个升序的序列就完成啦

    但是关于基准元素的选择有两种

    1.第一种是每次都选序列的子序列的第一个元素(有缺陷)

    2.第二种是每次都选择子序列中的第x个元素,x随机

    普通快速排序

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    #define n 5
    int a[n];
    void swap_t(int a[],int i,int j)
    {
        int t=a[i];
        a[i]=a[j];
        a[j]=t;
    }
    int par(int a[],int p,int q)
    {
        int i=p;//p是轴
        int x=a[p];//基准元素
        for(int j=p+1;j<=q;j++)
        {
            if(a[j]<=x)//升序
            {
                i++;
                swap_t(a,i,j);
            }
        }
        swap_t(a,p,i);
        return i;//轴位置
    }
    void QuickSort(int a[],int p,int q)
    {
        if(p<q)//序列中元素个数大于1
        {
            int r=par(a,p,q);
            QuickSort(a,p,r-1);
            QuickSort(a,r+1,q);
        }
    }
    int main()
    {
        int i;
        for(i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
        }
        QuickSort(a,0,n-1);
        for(i=0;i<n;i++)
        {
            printf("%d
    ",a[i]);
        }
        return 0;
    }
    View Code

    算法分析:

    1.最好情况:(每次分区时子序列中元素个数相同)

    T(n)=2T(n/2)+O(n)=O(n*logn) log的底是2

    2.最坏情况:序列是由大到小排序的

    比如:7 6 5 4 3 2 1   -----> ( 进行依次分区,基准元素是7)  1 6 5 4 3 2 7,元素7的后面是没有元素的,同理 再将序列1 6 5 4 3 2分区,变成了1 2 5 4 3 6,分区6的后面也是没有元素的(7不属于这个分区),所以最坏情况的快速排序相当于冒泡排序了。。。。。。。有没有一种操蛋的感觉

    T(n)=T(1)+T(n-1)+O(n)

          =T(1)+T(1)+T(n-2)+T(n-1)+O(n-1)+O(n) 

          继续变形下去

          T(常数)可以去掉

         T(n)=O(1)+O(2)+.......+O(n)//等差数列求和

          T(n)=O((1+n)*n/2)=n*n //常数可以省略

    所以T(n)=n*n

    3.一般情况:

    T(n)=T(n/5)+T(4*n/5)+O(n) //假设前面分成1份后面分成4份这种情况

          =T(n/25)+T(4*n/25)+O(n/5)+T(4*n/25)+T(16*n/25)+O(4*n/5) 

    我们假设T(n/5) 和T(4*n/5)展开成一颗树的形状,经过一系列比较复杂的推导之后(不好描述。。。。。)得到树的最大深度是log 5/4 n(底数的5/4),然后log 5/4 n 经过数学等价变形为log 2 n(底数为2)

    然后又经过一系列复杂推导后(。。。。。。。。。。),树的最大宽度为:n

    所以T(n)=n*log 2 n(底数为2)

    总结:普通快排存在缺陷,缺陷在于每次基准元素的选择

    二,改进之后的快速排序:随机化快速排序(每次随机在序列中选择基准元素),因为快排的性能取决于划分的对称性

    附加知识:生成p,q之间的随机数:

    方法:先生成随机数n,int i=n%(q-p+1)+p ,i就是p,q之间的随机数

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    #define n 5
    int a[n];
    void swap_t(int a[],int i,int j)
    {
        int t=a[i];
        a[i]=a[j];
        a[j]=t;
    }
    int par(int a[],int p,int q)
    {
        int i=p;//p是轴
        int x=a[p];
        for(int j=p+1;j<=q;j++)
        {
            if(a[j]<=x)
            {
                i++;
                swap_t(a,i,j);
            }
        }
        swap_t(a,p,i);
        return i;//轴位置
    }
    int Random(int p,int q)
    {
        return rand()%(q-p+1)+p;
    }
    int Randomizedpar(int a[],int p,int q)
    {
        int i=Random(p,q);
        swap_t(a,p,i);//第一个和第i个交换,相当于有了一个随机基准元素
        return par(a,p,q);
    }
    void RandomizedQuickSort(int a[],int p,int q)
    {
        if(p<q)
        {
            int r=Randomizedpar(a,p,q);
            printf("%d到%d之间的随机数:%d
    ",p,q,r);
            RandomizedQuickSort(a,p,r-1);
            RandomizedQuickSort(a,r+1,q);
        }
    }
    int main()
    {
        int i;
        for(i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
        }
        RandomizedQuickSort(a,0,n-1);
        for(i=0;i<n;i++)
        {
            printf("%d
    ",a[i]);
        }
        return 0;
    }
    View Code

    总结:快排虽然不稳定,但是高效(关于不稳定的概念请百度。。。)

        

    有错误的地方麻烦大佬们指正!!!

  • 相关阅读:
    Pro ASP.NET Core MVC2
    vscode
    git命令使用
    单行函数
    过滤和排序
    oracle基本查询
    斐波那契数列的递归实现
    队列的顺序存储结构
    队列的链式存储结构
    折半查找法
  • 原文地址:https://www.cnblogs.com/yinbiao/p/8805233.html
Copyright © 2011-2022 走看看