快速排序之“采取“尾递归”和“三数取中”技术的快速排序”

2023-11-13

快速排序之“采取“尾递归”和“三数取中”技术的快速排序”  
     下面针对快速排序进行一些优化。
      QUICKSORT算法包含两个对其自身的递归调用,即调用PARTITION后,左边的子数组和右边的子数组分别被递归排序。QUICKSORT中的第二次递归调用并不是必须的,可以用迭代控制结构来代替它,这种技术叫做“尾递归”,大多数的编译器也使用了这项技术。最坏的情况下,就是划分不好的时候,递归深度为O(n),能够二分的话递归深度为O(lgn),但是怎么才能得到好的划分呢?前面在快速排序中用了个随机化技术,“三数取中”能够让随机化更加理想。有这两项技术护体,快速排序不管在时间复杂度还是空间复杂度上都能得到优化。所谓“三数取中”是指,从子数组中随机选出三个元素,取其中间数作为主元,这算是前面随机化版本的升级版,即使是升级版,也只能影响快速排序时间复杂度O(nlgn)的常数因子。
     下面以一个程序代码实现来讲解。
     

#include <string.h>
#include <time.h>

#define BUFFER_SIZE 10

int Partition(int *a,int p,int r)
{
 int tmp=0;
 int i=0;
 int j=0;
 
 i=p-1;
 for(j=p;j<r;j++)
 {
  if(a[j]<=a[r])
  {
   i++;
   tmp=a[i];
   a[i]=a[j];
   a[j]=tmp;
  }
 }
 tmp=a[i+1];
 a[i+1]=a[r];
 a[r]=tmp;
 
 return i+1;
}

int RandomPartition(int *a,int p,int r)
{
 int min=0;
 int mid=0;
 int max=0;
 int i=0;
 int j=0;
 int k=0;
 int tmp=0;
 
 srand((unsigned)time(NULL));
 i=rand()%(r-p+1)+p;
 j=rand()%(r-p+1)+p;
 k=rand()%(r-p+1)+p;
 
 min=a[i];
 mid=a[j];
 max=a[k];
 
 min=(min<mid)?min:mid;
 mid=(mid<max)?mid:max;
 mid=(mid>min)?mid:min;
 
 if(a[i]==mid)
 {
  tmp=a[i];
  a[i]=a[r];
  a[r]=tmp;
 }
 else if(a[j]==mid)
 {
  tmp=a[j];
  a[j]=a[r];
  a[r]=tmp;
 }
 else if(a[k]==mid)
 {
  tmp=a[k];
  a[k]=a[r];
  a[r]=tmp;
 }
 
 return Partition(a,p,r);
}

void QuickSort(int *a,int p,int r)
{
 int q=0;
 while(p<r)//直到把右半边数组划分成最多只有一个元素为止,就排完了!不能用if哦,用if的话,右半边数组就只被划分一次。
 {
  q=RandomPartition(a,p,r);
  QuickSort(a,p,q-1);
  p=q+1;
 }
}

int main()
{
 int i=0;
 int j=0;
 int a[BUFFER_SIZE]; 
 //随机生成数组 
 srand((unsigned)time(NULL));
 for(j=0;j<BUFFER_SIZE;j++)
 {
  a[j]=rand()%100;
 } 
 printf("随机生成的数组:\n");
 for(i=0;i<BUFFER_SIZE;i++)
 {
  printf("%d ",a[i]);
 } 
 printf("\n");
 
 QuickSort(a,0,BUFFER_SIZE-1);
 printf("对数组进行快速排序:\n"); 
 for(i=0;i<BUFFER_SIZE;i++)
 {
  printf("%d ",a[i]);
 }
 
 system("pause");
 return 0;


优化的尾递归:
QUICKSORT (A, p, r )
    while p < r
        do Partition and sort the small subarray ?rst
        q ← PARTITION(A, p, r )
        if q ? p < r ? q
            then QUICKSORT (A, p, q ? 1)
                    p ← q + 1
        else QUICKSORT (A, q + 1, r )
                    r ← q ? 1
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

快速排序之“采取“尾递归”和“三数取中”技术的快速排序” 的相关文章

  • 如何通过pthreads管理两个或多个消费者?

    我有一个正在寻求解决的通用问题 即从标准输入或常规文件流发送到应用程序的二进制数据块 应用程序又将二进制数据转换为文本 使用线程 我想在将文本传输到下一个应用程序之前对其进行处理 该应用程序会进一步修改该文本 依此类推 作为一个简单的测试用
  • 调用不通过空指针访问成员的非静态方法是否合法/定义良好的 C++?

    我最近遇到了以下代码 class Foo public void bar other stuff void Foo bar if this do some stuff without accessing any data members r
  • 如何在Ireport中给出多选参数空值的条件?

    我正在使用以下方法编写报告iReport http en wikipedia org wiki JasperReports Third party tools我想在其中添加空值条件 它使用单选选项 city P p city or P p
  • 原则 2 OneToMany 级联 SET NULL

    错误 无法删除或更新父行 外键约束失败 课程 class Teacher ORM OneToMany targetEntity publication mappedBy teacher protected publications clas
  • 如何读取大型平面文件

    我有一个平面文件 其中包含 339276 行文本 大小为 62 1 MB 我试图读入所有行 根据我所拥有的某些条件解析它们 然后将它们插入数据库 我最初尝试使用 bufio Scan 循环和 bufio Text 来获取该行 但缓冲区空间不
  • 通过 NULL 指针访问类成员

    我正在尝试 C 发现下面的代码非常奇怪 class Foo public virtual void say virtual hi std cout lt lt Virtual Hi void say hi std cout lt lt Hi
  • 结构体如何存储在内存中?

    我有一个struct iof header在我的代码中 我确定它的宽度是 24 字节 我执行 sizeof iof header 它返回 32 字节宽 问题1为什么是 32 字节宽而不是 24 字节宽 问题2包括其成员在内 结构体如何存储在
  • 当没有数据时,空 json 对象而不是 null -> 如何使用 gson 反序列化

    我正在尝试使用 Google 的 gson 库解析 json 数据 但 json 数据表现不佳 当一切正常时 它确实看起来像这样 parent child one some String child two 4711 child one应该
  • 使用 rpy2 将 NULL 从 Python 转换为 R

    在 R 中经常NULL值用作默认值 使用 Python 和 RPy2 如何显式提供NULL争论 None不可兑换 NotImplementedError 字符串 NULL 只会被转换为字符串 并在执行过程中导致错误 采取以下示例 使用tsi
  • 金属着色语言 - 更改缓冲区大小

    是否可以在运行时更改缓冲区大小 我们在注册期间分配缓冲区大小device device MTLCreateSystemDefaultDevice queue device makeCommandQueue do let library de
  • 将 Null 与 MySQL 触发器中的另一个值进行比较

    所以这是我的问题 我在更新表行时比较新值和旧值 但新值或旧值有时会为空 所以下面的代码不起作用 我可以解决这个问题吗 谢谢 BEFORE UPDATE ON mytable FOR EACH ROW BEGIN IF OLD assigne
  • 为什么C++中没有“NULL引用”?

    我正在阅读 C 常见问题解答 8 6 什么时候应该使用引用 什么时候应该使用指针 http www parashift com c faq lite refs vs ptrs html 特别是以下声明 可以时使用引用 必要时使用指针 上述情
  • MacVim:跨窗口共享命名寄存器?

    我想跨 MacVim 窗口共享命名寄存器缓冲区 就像我在单个实例中跨缓冲区一样 换句话说 假设我标记了一个位置 m 然后去其他地方 我将一些文本拉入寄存器 a 从当前点到 m a m 然后我转到另一个窗口 不 我不是指同一窗口中的另一个分割
  • 在 C++ 中检查空指针的首选方法是什么?

    选项A if NULL pSomethingColumn Yes we use Yoda conditions if NULL pSomethingColumn Or if pSomethingColumn if pSomethingCol
  • 了解 netty 通道缓冲区和水印

    我正在尝试了解网络缓冲区和水印 作为一个测试用例 我有一个 netty 服务器 它向客户端写入数据 客户端被阻止 基本上每次读取之间有 10 秒的睡眠时间 在正常 I O 下 如果接收方被阻塞 TCP 发送方将受到限制 由于流量控制 发送速
  • 如何使用 Java 本机接口将字节数组传递到以 char* 作为参数的 C 函数中?

    所以我需要使用JNI从java调用C函数 当传入不同的数据类型 创建本机变量 头文件 共享库等等 时 我已经能够成功地做到这一点 但无法让它与字节数组一起使用 这是我的 C 函数 include
  • 无法使用 Node.JS 将 null 值发送到 MySQL 数据库

    我正在尝试发送null使用 Node JS 到我的 MySQL 数据库 con query INSERT INTO Routes routeTrigger VALUES null title test function err result
  • 如何在 psycopg 中使用 SELECT 查询找到空值?

    我在 python 中使用 psycopg2 库INSERT当我用 None 插入 null 值时 查询效果很好 但是当我想做的时候SELECTnull 值 None 不返回任何值 cur execute SELECT id FROM re
  • 查询外键列可以为NULL的地方

    我想获取数据 如果orgid 2或者如果根本没有行uid orgid is an integer 我能想到的最接近的事情就是做IS NULL但我没有得到数据uid没有一个orgid排 任何想法 select u uid u fname u
  • python pandas 中的双端队列

    我正在使用Python的deque 实现一个简单的循环缓冲区 from collections import deque import numpy as np test sequence np array range 100 2 resha

随机推荐