快速排序 产生随机数 c语言,快速排序

快速排序的时间复杂度为O(nlogn),空间复杂度为O(logn)最坏情况下的时间复杂度为O(n2),空间复杂度O(n)。在C++标准库的实现过程中,为了保证快速排序的速度,用堆排序对快速排序做了优化,即使在最坏情况下,sort仍然可以维持O(nlogn)的时间复杂度,空间复杂度则不会超过O(logn)。在一般性应用场合,快速排序不会愧对它的名字,尽管时间复杂度为O(nlogn),但常数因子很小,因此排序速度比其它时间复杂度为O(nlogn)的堆排序和归并排序要快一些,甚至超越了理论上比它快的基数排序和计数排序以及桶排序,这后三种排序的时间复杂度理论值可是O(n)哦。C++继承了C库,因此C库里的qsort也被继承下来,只不过sort要比qsort排序速度快得多。

对于一个无需序列而言,当我们需要把它变成一个升序序列时,可以把它一分为二,使左边的子序列都小于或等于某个值,右边的子序列都大于等于某个值,左右子序列继续这种划分,直到整个序列有序为止。这是最原始的快速排序设计思想,它是分治算法的应用。

现在的问题是,拿什么作为基准把一个序列划分成两个子序列呢?弄不好一边只有一个元素,另一边则为其余所有元素,这种划分过程一直持续到排序完毕为止,这是最糟糕的情况,完全退化成了直接插入排序,复杂度为O(n2)。这个参考的基准,也就是序列里用于比较的某个特别的元素,就是支点,这个词来自力学。这样以来,选取支点就成了快速排序首当其冲要解决的问题。

选取支点常见的方案有三种,第一种情况是使用待排序序列的第一个元素或最后一个元素作为支点。采用这种方案的人非常乐观,以为最坏情况很难遇上。然而事情很多时候总是事与愿违,当一个待排序序列已经有序时就会遭遇最差情况。第二种方案是三点取中,以待排序序列中第一个元素,最中间那个元素和最后一个元素三者大小居中的那个作为支点,这就大大降低了遭遇最差情况的可能性,而且三点取中的代价很低。实际应用中,几乎所有版本的快速排序都采用了这种方案。第三种方案是随机选取支点,似乎这是最理想的情况,但是该方案一直搁浅。

显然,第一种选取支点的方案不值得我们去研究,我们先来尝试第二种选取支点的方案,稍后再尝试第三种方案。前面已经说过,当序列很短或基本有序时用直接插入排序比较快。我们可以考虑用直接插入排序来优化快速排序,否则当子序列少于三个元素时选取支点需要做特殊处理,再者,用递归来实现快速排序较为简单,而深层次递归的执行效率很低。

经过优化后三点取中快速排序过程示例如下: 27  98 96 96 40 79 91 86 29  85 56 72 45 85 60 12 14 92 97 26 89 三点取中

27  26  96 96 40 79 91 86 29 85 56 72 45 85 60 12 14 92 97 98 89 交换98和26

27  26  14 96 40 79 91 86 29 85 56 72 45 85 60 12 96 92 97 98 89 交换96和14

27  26  14 12 40 79 91 86 29 85 56 72 45 85 60 96 96 92 97 98 89 交换96和12

27  26  14 12 40 45 91 86 29 85 56 72 79 85 60 96 96 92 97 98 89 交换79和45

27  26  14 12 40 45 56 86 29 85 91 72 79 85 60 96 96 92 97 98 89 交换91和56

27  26  14 12 40 45 56 29 86 85 91 72 79 85 60 96 96 92 97 98 89 交换86和29

12  14  26 27 29 40 45 56 60 72 79 85 85 86 89 91 92 96 96 97 98 插入排序

原始的快速排序使用直接插入排序优化后,速度有了较大提升,但是最坏情况下退化成直接插入排序的诟病依然存在。解决这个问题需要用较低的代价获知排序过程中何时支点严重偏向一边,以便立即作出处理。这个难题被STL的另外一位大师David Musser在1997年解决,他使用监测递归深度的做法,当递归深度很大时说明支点严重偏斜,此时采用堆排序来保证O(nlogn)的时间复杂度。SGI STL里的sort采用了这种设计。

第三种选取支点的方案的原理非常简单,但是长期以来存在较大困难。首先,用软件产生随机数不是一件很容易的事,实际应用中只能用产生的伪随机数取代随机数,而伪随机数的质量和产生代价会影响快排的执行效率。这可能是长期以来一直没有人问津第三种选取支点方案的主要原因。再者,随机选取的支点未必十分适合需要排序的序列。在此,我们不做深入研究伪随机数的产生原理,以及随机选取的支点在多大程度上适合待排序的序列,因为二者均需要十分复杂的数学理论。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言中使用大量随机数进行快速排序可以通过以下步骤实现: 1. 首先,创建一个包含10000个随机数的数组。可以使用rand()函数结合srand()函数生成随机数,并将其存储在数组中。 示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> void generateRandomArray(int array[], int size) { srand(time(NULL)); for (int i = 0; i < size; i++) { array[i] = rand() % 100; // 这里假设随机数的范围是0-99 } } int main() { int size = 10000; int array[size]; generateRandomArray(array, size); // 在这里进行快速排序 return 0; } ``` 2. 接下来,实现快速排序算法。快速排序是一种高效的排序算法,它通过选择一个基准元素并将数组划分为两个子数组,分别递归地对这两个子数组进行排序,最终得到一个有序的数组。 示例代码: ```c void quickSort(int array[], int low, int high) { int i = low; int j = high; int pivot = array[(low + high) / 2]; // 选择中间的元素作为基准 while (i <= j) { while (array[i] < pivot) { i++; } while (array[j] > pivot) { j--; } // 交换元素 if (i <= j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; i++; j--; } } // 递归排序左半部分 if (low < j) { quickSort(array, low, j); } // 递归排序右半部分 if (i < high) { quickSort(array, i, high); } } ``` 3. 最后,在main函数中调用quickSort函数对生成的随机数数组进行快速排序。 示例代码: ```c int main() { int size = 10000; int array[size]; generateRandomArray(array, size); quickSort(array, 0, size - 1); // 在这里打印排序后的数组 return 0; } ``` 通过以上步骤,我们可以在C语言中使用大量随机数进行快速排序。需要注意的是,在处理大规模数据时可能会出现性能问题,可以考虑使用其他更高效的排序算法或优化策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值