实训三—分治算法专题—第6关:快速排序


任务描述

本关任务:生成n个随机数,使用快速排序,将随机数排成一个从小到大的序列输出。

相关知识

随机数

编写程序过程中,经常需要产生一些随机数。随机数在程序中分为两种: 真随机数:完全没有规则,无法预测接下来要产生的数。 伪随机数:通过一些预先设定好的规则产生不能简单预测的数。

在C语言中比较常用的随机函数是 rand()函数,它可以随机的产生 0 ~ rand_max 的随机数,定义类型不同最大值也不同,rand 函数包含在头文件stdlib.h中。

 
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. int a;
  6. a=rand();
  7. printf("%d",a);
  8. return 0;
  9. }

运行结果: 1804289383

你会发现每次产生的随机数都是相同的,因为rand()函数产生的随机数是伪随机数,是根据一个数按照某个公式推算出来的,这个数我们称之为“种子”,但是这个种子在系统启动之后就是一个定值。要想每次产生的随机数不一样,那么,就要用到 srand ()函数。

srand() 函数原型是: void srand (usigned int seed); rand() 产生随机数时,如果用srand(seed) 播下种子之后,一旦种子相同,产生的随机数将是相同的。为了让rand()函数产生真随机数,用时间作种子 srand(time(NULL)) ,因为每次运行程序的时间肯定是不相同的,产生的随机数肯定就不一样了。

代码示例:

 
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. int main()
  5. {
  6. int a;
  7. srand( time(NULL) );
  8. a =rand();
  9. printf("%d",a);
  10. return 0;
  11. }

可以看到第一次运行结果和第二次运行的结果是不一样的。

随机产生10个[0,100)范围内随机数的C程序示例:

 
  1. include<stdio.h>
  2. #include<stdlib.h>
  3. #include<time.h>
  4. int main()
  5. {
  6. int a[10];
  7. int i;
  8. printf("随机产生10个[0,100)范围内随机数:\n");
  9. srand(time(0)); //srand(time(NULL));
  10. for(i=0;i<10;i++)
  11. a[i]=rand()%100; //一般键盘随机输入10个数方式:scanf("%d",&a[i]);
  12. for(i=0;i<10;i++)
  13. printf("%d ",a[i]);
  14. printf("\n");
  15. return 0;
  16. }
快速排序算法思想

快速排序(Quicksort)是对冒泡排序的一种改进。 快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。 快速排序算法通过多次比较和交换来实现排序,其排序流程如下: (1)首先设定一个分界值,通过该分界值将数组分成左右两部分。 (2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。 (4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
排序步骤编辑 原理 设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它左边,所有比它大的数都放到它右边,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1; 2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]的值交换; 4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]的值交换;
5)重复第3、4步,直到i==j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。 排序演示 假设一开始序列{xi​}是:5,3,7,6,4,1,0,2,9,10,8。 此时,key=5,i=0,j=10,从后往前找,第一个比5小的数是x7​=2,因此序列为:2,3,7,6,4,1,0,5,9,10,8。 此时i=0,j=7,从前往后找,第一个比5大的数是x2​=7,因此序列为:2,3,5,6,4,1,0,7,9,10,8。 此时,i=2,j=7,从第7位往前找,第一个比5小的数是x6​=0,因此:2,3,0,6,4,1,5,7,9,10,8。 此时,i=2,j=6,从第2位往后找,第一个比5大的数是x3​=6,因此:2,3,0,5,4,1,6,7,9,10,8。 此时,i=3,j=6,从第6位往前找,第一个比5小的数是x5​=1,因此:2,3,0,1,4,5,6,7,9,10,8。 此时,i=3,j=5,从第3位往后找,直到第5位才有比5大的数,这时,i=j=5,key成为一条分界线,它之前的数都比它小,之后的数都比它大,对于前后两部分数,可以采用同样的方法来排序。

编程要求

根据提示,在右侧编辑器补充代码,对给定数组进行快速排序并输出排序前后的数组元素。

测试说明

平台会对你编写的代码进行测试:

测试输入: 10 预期输出: Before merge sort: 295,8,678,725,418,377,675,271,747,307, After merge sort: 8,271,295,307,377,418,675,678,725,747,

#include<iostream>  
using namespace std;  
#include <stdio.h>  
#include<stdlib.h>  
#include <time.h>  
#include <math.h>  


void output(int *a,int n)  
{  
    int i;  
    for(i=0;i<n;i++)  
    {  
    printf("%d,",a[i]);  
    }  
    printf("\n");  
}
void swap(int &a, int &b)  
{  
    int t;  
    t=a;a=b;b=t;  
}

//交换顺序表L中子表L[low..high]的记录,使枢轴记录到位,并返回其所在位置,此时在它之前(后)的记录均不大(小)于它。  
//交换顺序表L中子表L[low..high]的记录,使枢轴记录到位,并返回其所在位置,此时在它之前(后)的记录均不大(小)于它。  
int Partition(int *L,int low,int high)  
{  
    int pivotkey = L[low]; // 用子表的第一个记录作枢轴记录
    while (low < high) 
    {
        while (low < high && L[high] >= pivotkey)
            --high;
        L[low] = L[high];
        while (low < high && L[low] <= pivotkey)
            ++low;
        L[high] = L[low];
    }
    L[low] = pivotkey;
    return low;
}

    // 对顺序表L中的子序列L[low..high]作快速排序  
void QSort(int *L,int low,int high)  
{   
    if (low < high) 
    {
        int pivotloc = Partition(L, low, high); // 划分
        QSort(L, low, pivotloc - 1); // 递归地对左子表进行快速排序
        QSort(L, pivotloc + 1, high); // 递归地对右子表进行快速排序
    }
}
 
int main ()  
{   
    int i;
    int *a=0;  
    int n;
    scanf("%d",&n);  
    srand(n);  
    a=new int[n];      
    for(i=0;i<n;i++)  
    {       
       a[i]=rand() % 1000;      
    }
    printf("Before merge sort:\n");    
    output(a,n);   
    QSort(a,0,n-1);
    printf("After merge sort:\n");     
    output(a,n);      
    delete []a;      
    return 0;  
} 

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值