scau 8642 快速排序

scau 8642 快速排序,第1张

Description
用函数实现快速排序,并输出每次分区后排序的结果
输入格式
第一行:键盘输入待排序关键的个数n
第二行:输入n个待排序关键字,用空格分隔数据
输出格式
每行输出每趟排序的结果,数据之间用一个空格分隔
输入样例
10
5 4 8 0 9 3 2 6 7 1
输出样例
1 4 2 0 3 5 9 6 7 8
0 1 2 4 3 5 9 6 7 8
0 1 2 4 3 5 9 6 7 8
0 1 2 3 4 5 9 6 7 8
0 1 2 3 4 5 8 6 7 9
0 1 2 3 4 5 7 6 8 9
0 1 2 3 4 5 6 7 8 9

好久都没有更新啦!五一玩过头了TUT

排序这一章的前面几个算法,像直接插入排序、折半插入排序都是比较简单的,这里我对快速排序做个小小的笔记。

首先,我们要了解快速排序的步骤。

书上其实介绍的蛮清楚的,不过全是文字,所以看起来会有点枯燥且难懂。下面我用样例来进行解释。(PS:快排也是有很多方法哒!我下面所介绍的这个方法和书上有点点不太一样,因为上课没听懂,所以在网上找了点小小资源,不过弄明白了一种方法,另一种方法也是很好理解的。我先介绍我的方法,再介绍书上的方法)

以题目所给输入样例为例。

步骤:

(1)以第一个数“5”为基准点,设置头尾指针,分别指向第一个数和最后一个数。

(2)从右往左,找出第一个小于基准点“5”的数,也就是“1”,找的同时要移动尾指针j哦,即j--

(3)再从左往右,找出第一个大于基准点“5”的数,也就是“8”,同理,找的时候要移动头指针,即i++

(4)现在的指针i和j如上图所示,交换指针i和j所指的数,如下图所示

 

(5)重复步骤(2)~(4),直至指针i和j相遇

 

当指针i和j相遇时,交换基准点“5”和指针i和j共同指向的数“3”

如上图所示,这就是第一次调用快排函数的结果。你会发现,此时的“5”已经归位,“5”左边的数均小于5,右边的数均大于5。

然后以“5”为中心,将这段数列分成左右两段,“3 4 1 0 2”和“9 6 7 8”,再调用快排函数对左右两个子段进行处理,即重复步骤(1)~(5)【左段以3为基准点,右段以9为基准点】

递归结束时,排序就完成了。

代码如下

#include 

using namespace std;

int n,a[100005];

void print()
{
    std::ios::sync_with_stdio(false);
    for(int k=1;k<=n;k++)
        cout << a[k] << ' ';
    cout << endl;
}

void kuaipai(int a[],int i,int j)//a[]为要排序的数组,i指向第一个数,j指向最后一个数
{
    if(i>=j)//结束条件写前面
        return;
    int temp=a[i];//基准数
    int m,n;
    m=i,n=j;
    while(m!=n)
    {
        while(a[n]>=temp && mm)//如果头尾指针没有相遇,则交换两个数
        {
            int t=a[m];
            a[m]=a[n];
            a[n]=t;
        }
    }
    a[i]=a[m];//当头尾指针相遇时,把头尾指针指向的那个数和基准数交换
    a[m]=temp;
    print();
    kuaipai(a,i,m-1);//归位的基准点的左半段
    kuaipai(a,m+1,j);//归位的基准点的右半段
}

int main()
{
    std::ios::sync_with_stdio(false);
    cin >> n;
    int k;
    for(k=1;k<=n;k++)
    {
        cin >> a[k];
    }
    kuaipai(a,1,n);
    return 0;
}

输入输出结果如下

 

 下面来介绍书上的方法。

 还是以这个为例

步骤:

(1)把第一个数作为基准点暂存在a[0]中,设置头尾指针i和j,分别指向第一个数和最后一个数。

(2)从右往左,找出第一个小于基准点“5”的数,没找到就j--,找到之后将j所指向的这个第一个小于“5”的数和基准点“5”交换

(3)从左往右,找出第一个大于基准点“5”的数,没找到就i++,找到之后将i所指向的这个第一个大于“5”的数和基准点“5”交换

{PS:注意我上面标成粉红色的字,这就是和上面第一种方法的区别所在。第一种是把指针i和j所指向的数进行交换,而这里是把指针i和j分别和基准点交换}

(4)重复步骤(2)~(3),直至指针i和j相遇

好了,上面就是第一次调用快排函数所得到的结果,此时指针i和j相遇,“5”已归位,以“5”为中心,原来的数列被分成两个子段“1 4 2 0 3”和“9 6 7 8”

和前面介绍的第一种方法得到的结果不太一样,但是规律是相似的哦——“5”归位,“5”左边的数均小于5,右边的数均大于5。

(5)重复步骤(1)~(4),调用函数对左右两个子段进行处理。

         例如左子段“1 4 2 0 3”,以“1”为基准点,最后得到“0 1 2 4 3”,“1”已归位,以“1”为中心,“0 1 2 4 3”又被分成了两个子段“0”和“2 4 3”,再进行递归调用……

直到所有递归结束,排序结束

代码如下

(1)这个提交可以过

#include 
#include 
#include 
#include 
#include 

using namespace std;

int n,a[100005];

int kuaipai(int a[],int i,int j)
{
    a[0]=a[i];//用a[0]暂存基准点
    while(i=a[0])
            j--;
        a[i]=a[j];
        while(i n;
    for(int k=1;k<=n;k++)
        cin >> a[k];
    Qsort(a,1,n);
    return 0;
}

运行结果如图 

 (2)下面这个也能得出正确答案,但是不知道为什么多了几行重复的。有没有兄弟可以帮我找找问题TUT

#include 
#include 
#include 
#include 
#include 

using namespace std;

int n,a[100005];

void print()
{
    std::ios::sync_with_stdio(false);
    for(int k=1;k<=n;k++)
        cout << a[k] << ' ';
    cout << endl;
}

void kuaipai(int a[],int i,int j)
{
    if(i>j)
        return;
    int m,n;
    m=i,n=j;//用于记录,最后递归需要用到

    a[0]=a[i];//用a[0]暂存基准点
    while(i=a[0])
            j--;
        a[i]=a[j];
        while(i> n;
    for(int k=1;k<=n;k++)
        cin >> a[k];
    kuaipai(a,1,n);
    return 0;
}

运行结果如图

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/915182.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-16
下一篇2022-05-16

发表评论

登录后才能评论

评论列表(0条)

    保存