任务描述
本关任务:生成n个随机数,使用快速排序,将随机数排成一个从小到大的序列输出。
相关知识
随机数
编写程序过程中,经常需要产生一些随机数。随机数在程序中分为两种: 真随机数:完全没有规则,无法预测接下来要产生的数。 伪随机数:通过一些预先设定好的规则产生不能简单预测的数。
在C语言中比较常用的随机函数是 rand()函数,它可以随机的产生 0 ~ rand_max 的随机数,定义类型不同最大值也不同,rand 函数包含在头文件stdlib.h中。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a;
a=rand();
printf("%d",a);
return 0;
}
运行结果: 1804289383
你会发现每次产生的随机数都是相同的,因为rand()函数产生的随机数是伪随机数,是根据一个数按照某个公式推算出来的,这个数我们称之为“种子”,但是这个种子在系统启动之后就是一个定值。要想每次产生的随机数不一样,那么,就要用到 srand ()函数。
srand() 函数原型是: void srand (usigned int seed);
rand() 产生随机数时,如果用srand(seed) 播下种子之后,一旦种子相同,产生的随机数将是相同的。为了让rand()函数产生真随机数,用时间作种子 srand(time(NULL)) ,因为每次运行程序的时间肯定是不相同的,产生的随机数肯定就不一样了。
代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int a;
srand( time(NULL) );
a =rand();
printf("%d",a);
return 0;
}
可以看到第一次运行结果和第二次运行的结果是不一样的。
随机产生10个[0,100)
范围内随机数的C程序示例:
include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int a[10];
int i;
printf("随机产生10个[0,100)范围内随机数:\n");
srand(time(0)); //srand(time(NULL));
for(i=0;i<10;i++)
a[i]=rand()%100; //一般键盘随机输入10个数方式:scanf("%d",&a[i]);
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
return 0;
}
快速排序算法思想
快速排序(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;
}