Algs4-2.3.22快速三向切分(J.Bently,D.McIlroy)

2023-11-27 07:30

本文主要是介绍Algs4-2.3.22快速三向切分(J.Bently,D.McIlroy),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2.3.22快速三向切分。(J.Bently,D.McIlroy)用将重复元素放置于子数组两端的方式实现一个信息量最优的排序算法。使用两个索引p和q,使得a[lo..p-1]和a[q+1..hi]的元素都和a[lo]相等。使用另外两个索引i和j,使用a[p..i-1]小于a[lo],a[j+1..q]大于a[lo]。在内循环中加入代码,在a[i]和v相当时将其与a[p]交换(并将p加1),在a[j]和v相等且a[i]和a[j]尚未和v进行比较之前将其与a[q]交换。添加在切分循环结束后将和v相等的元素交换到正确位置的代码,如图2.3.6所示。请注意:这里实现的代码和正文中给出的代码是等价的,因为这里额外的交换用于和切分元素相等的元素,而正文中的代码将额外的交换用于和切分元素不等的元素。

英文版问题:
2.3.22 Fast 3-way partitioning. ( J. Bentley and D. McIlroy) Implement an entropyoptimal
sort based on keeping item's with equal keys at both the left and right ends
of the subarray. Maintain indices p and q such that
a[lo..p-1] and a[q+1..hi] are all equal to a[lo],
an index i such that a[p..i-1] are all less than a[lo],
and an index j such that a[j+1..q] are all greater than
a[lo]. Add to the inner partitioning loop code to swap
a[i] with a[p] (and increment p) if it is equal to v and
to swap a[j] with a[q] (and decrement q) if it is equal
to v before the usual comparisons of a[i] and a[j]
with v. After the partitioning loop has terminated, add
code to swap the items with equal keys into position.
Note : This code complements the code given in the
text, in the sense that it does extra swaps for keys equal to the partitioning item’s key,
while the code in the text does extra swaps for keys that are not equal to the partitioning
item’s key.
图片
实现:
public class E2d3d22v1
{
    public static void sort(Comparable[] a)
    {
      StdRandom.shuffle(a);
      sort(a,0,a.length-1);
    }
   
    private static void sort(Comparable[] a,int lo,int hi)
    {
        //数组少于2个元素时不处理
        if (hi<=lo) return;
        //p的初值为lo+1,满足lo~p-1的元素=v
        //i的初值为lo+1,p~i-1为0长,满足p~i-1的元素<v
        //q的初值为hi,q+1~hi为0长,满足q+1~hi的元素=v
        //j的初值为hi,j+1~q为0长,满足q+1~hi的元素>v
        int p=lo+1,i=lo+1,q=hi,j=hi;
       // StdOut.printf("lo=%d,i=%d,j=%d,hi=%d\n",lo,i,j,hi);
        Comparable v=a[lo];
        while(i<=j)
        {
            //当i<j时一定需要i位置元素与v对比,当出现数组只有两个元素v,<v时,i=j,此时如果不进行对比排序后的结果就无序的,所以i=j时也需要对比。
            //由于i=j时还需要对比,那么可能会出现i越过j形成i>=j的情况。
            while(i<=j)
            {
              int cmp=a[i].compareTo(v);
              //StdOut.printf("ToRight i=%d,j=%d,cmp=%d,a[i]=%f,v=%f\n",i,j,cmp,a[i],v);
              //当i位置元素<v时,i向右移动一个位置,此时p~i-1的元素<v
              if (cmp<0) i++;
              //当i位置元素=v时,交换i,p位置的元素,i,p指针向右移动一个位置,此时lo~p-1的元素=v,p~i-1的元素<v
              else if (cmp==0) exch(a,i++,p++);
              //当位置i的元素>v时,i指针暂停右移
              else if(cmp>0) break;
            }
            //当i<j时一定需要j位置元素与v对比,
            //当出现数组只有两个元素v,>v时,i=j,由于在上一个while中i位置元素已与v进行过对比,如果j位置元素再与v进行一次对比就多比较一次了,所以j位置元素与v的比较必要性不强。
            //所以i=j时可以不进行对比了,那么意味着j向左移动时不可能会越过i位置形成i>j的情况,最多只可能是形成i=j的情况。
            while(i<j)
            {
              int cmp=a[j].compareTo(v);
             // StdOut.printf("ToRight i=%d,j=%d,cmp=%d,a[i]=%f,v=%f\n",i,j,cmp,a[i],v);
              //当j位置元素<v时,j指针暂停左移
              if (cmp<0) break;
              //当j位置元素=v时,交换j,q位置的元素,j,q指针向左移动一个位置,此时q+1~hi的元素=v,j+1~q的元素>v
              else if(cmp==0) exch(a,j--,q--);
              //当j位置元素>v时,j向左移动一个位置,此时j+1~q的元素>v
              else if(cmp>0)j-- ;
            }
            //i,j指针相遇或i越过j时形成i>=j的几种具体排列
            //1)v,<v 此情况时i>j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。
            //2)v,v,此情况时i>j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。
            //3)v,>v,此情况时i=j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。
            //4)v,>v,<v此情况时i<j需要交换i,j位置元素,并将i,j向前移动一位,此时i>j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。
            //5)v,<v,>v此情况时i=j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。
           
            //当i,j 指针相遇或越过时,结束本轮比较
            if (i>=j) break;
            //StdOut.printf("Exch i=%d,j=%d\n",i,j);
            //上述第4点。
            exch(a,i,j);
            i++;
            j--;
        }
        //依据上述5点的结论,得出位置i和i右边的元素>=v,保存i到j
        j=i;
        //左端=v元素与<v的元素段的右边交换。具体
        //从左端向右将所有=v的元素与i-1位置到左边的元素交换,
        //lo~i-1段,p无论是靠左或靠右或均分此段时,这种交换都将得到<v,=v的排列。
        i--;
        for (int k = lo; k < p; k++) exch(a, k, i--);
        //右端=v端元素与>v的元素段的左端进行交换。
        //从右端向左将所有=v的元素与j位置到右边的元素交换,
        //j~hi段,q无论是靠左或靠右或均分此段时,这种交负都将得到=v,>v的排列。
        for (int k = hi; k > q; k--) exch(a, k, j++);
      // StdOut.printf("Move lo=%d,i-1=%d,j+1=%d,hi=%d\n",lo,i-1,j+1,hi);
      // StdOut.println("Left Sort");
        //对<v的左子数组再排序,此时i处在最右边的<v的位置上。
       sort(a, lo, i);
       //StdOut.println("Right Sort");
       //对>v的右子数组再排序,此时j处在最左边的>v的位置上。
       sort(a, j, hi);
    }
   

   
    private static boolean less(Comparable v,Comparable w)
    { return v.compareTo(w)<0;}
   
    private static void exch(Comparable[] a,int i,int j)
    {
        Comparable  t=a[i];
        a[i]=a[j];
        a[j]=t;
    }
   
    private static void show(Comparable[] a)
    {
        for (int i=0;i<a.length;i++)
            StdOut.print(a[i]+" ");
        StdOut.println();
    }
   
    public static boolean isSorted(Comparable[] a)
    {
        for (int i=1;i<a.length;i++)
            if(less(a[i],a[i-1])) return false;
        return true;
    }
   
    public static void main(String[] args)
    {
        int N=Integer.parseInt(args[0]);
        Double[] a=new Double[N];
        StdOut.println(a.length);
        for(int k=0;k<N;k++)
            a[k]=StdRandom.random();

        sort(a);

        StdOut.println("isSorted=" +isSorted(a));
       // show(a);
    }
}


摘自网络的另一种实现:
public class E2d3d22v2
{
    public static void sort(Comparable[] a)
    {
      StdRandom.shuffle(a);
      sort(a,0,a.length-1);
    }
   
    private static void sort(Comparable[] a,int lo,int hi)
    {
    if (hi <= lo)  return;
    int i = lo, j = hi + 1;
    int p = lo, q = hi + 1;
    Comparable v = a[lo];
    while (true)
    {
        while (less(a[++i], v))
            if (i == hi) break;
        while (less(v, a[--j]))
            if (j == lo) break;

        // pointers cross
        if (i == j && equal(a[i], v))
            exch(a, ++p, i);
        if (i >= j) break;

        exch(a, i, j);
        if (equal(a[i], v)) exch(a, ++p, i);
        if (equal(a[j], v)) exch(a, --q, j);
    }

    //将相等的元素交换到中间
    i = j + 1;
    for (int k = lo; k <= p; k++) exch(a, k, j--);
    for (int k = hi; k >= q; k--) exch(a, k, i++);

    sort(a, lo, j);
    sort(a, i, hi);
}


   
    private static boolean less(Comparable v,Comparable w)
    { return v.compareTo(w)<0;}
   
    private static boolean equal(Comparable v,Comparable w)
    { return v.compareTo(w)==0;}

   
    private static void exch(Comparable[] a,int i,int j)
    {
        Comparable  t=a[i];
        a[i]=a[j];
        a[j]=t;
    }
   
    private static void show(Comparable[] a)
    {
        for (int i=0;i<a.length;i++)
            StdOut.print(a[i]+" ");
        StdOut.println();
    }
   
    public static boolean isSorted(Comparable[] a)
    {
        for (int i=1;i<a.length;i++)
            if(less(a[i],a[i-1])) return false;
        return true;
    }
   
    public static void main(String[] args)
    {
        int N=Integer.parseInt(args[0]);
        Double[] a=new Double[N];
        StdOut.println(a.length);
        for(int k=0;k<N;k++)
            a[k]=StdRandom.random();

        sort(a);

        StdOut.println("isSorted=" +isSorted(a));
       // show(a);
    }
}


J.Bently,D.McIlroy 发表的文章下载地址: https://cs.fit.edu/~pkc/classes/writing/papers/bentley93engineering.pdf

摘自其中的C语言实现
void iqsort2(int *x, int n)
{
int a, b, c, d, l, h, s, v;
if (n <= 1) return;
v = x[rand() % n];
a = b = 0;
c = d = n-1;
for (;;) {
while (b <= c && x[b] <= v) {
if (x[b] == v) iswap(a++, b, x);
b++;
}
while (c >= b && x[c] >= v) {
if (x[c] == v) iswap(d--, c, x);
c--;
}
if (b > c) break;
iswap(b++, c--, x);
}
s = min(a, b-a);
for(l = 0, h = b-s; s; s--) iswap(l++, h++, x);
s = min(d-c, n-1-d);
for(l = b, h = n-s; s; s--) iswap(l++, h++, x);
iqsort2(x, b-a);
iqsort2(x + n-(d-c), d-c);
}

转载于:https://www.cnblogs.com/longjin2018/p/9860276.html

这篇关于Algs4-2.3.22快速三向切分(J.Bently,D.McIlroy)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/weixin_34226182/article/details/94220686
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/427285

相关文章

使用animation.css库快速实现CSS3旋转动画效果

《使用animation.css库快速实现CSS3旋转动画效果》随着Web技术的不断发展,动画效果已经成为了网页设计中不可或缺的一部分,本文将深入探讨animation.css的工作原理,如何使用以及... 目录1. css3动画技术简介2. animation.css库介绍2.1 animation.cs

SpringBoot快速搭建TCP服务端和客户端全过程

《SpringBoot快速搭建TCP服务端和客户端全过程》:本文主要介绍SpringBoot快速搭建TCP服务端和客户端全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录TCPServerTCPClient总结由于工作需要,研究了SpringBoot搭建TCP通信的过程

一文教你Python如何快速精准抓取网页数据

《一文教你Python如何快速精准抓取网页数据》这篇文章主要为大家详细介绍了如何利用Python实现快速精准抓取网页数据,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录1. 准备工作2. 基础爬虫实现3. 高级功能扩展3.1 抓取文章详情3.2 保存数据到文件4. 完整示例

快速修复一个Panic的Linux内核的技巧

《快速修复一个Panic的Linux内核的技巧》Linux系统中运行了不当的mkinitcpio操作导致内核文件不能正常工作,重启的时候,内核启动中止于Panic状态,该怎么解决这个问题呢?下面我们就... 感谢China编程(www.chinasem.cn)网友 鸢一雨音 的投稿写这篇文章是有原因的。为了配置完

Python利用ElementTree实现快速解析XML文件

《Python利用ElementTree实现快速解析XML文件》ElementTree是Python标准库的一部分,而且是Python标准库中用于解析和操作XML数据的模块,下面小编就来和大家详细讲讲... 目录一、XML文件解析到底有多重要二、ElementTree快速入门1. 加载XML的两种方式2.

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

springboot security快速使用示例详解

《springbootsecurity快速使用示例详解》:本文主要介绍springbootsecurity快速使用示例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录创www.chinasem.cn建spring boot项目生成脚手架配置依赖接口示例代码项目结构启用s

C++快速排序超详细讲解

《C++快速排序超详细讲解》快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下... 目录一、快速排序原理二、快速排序标准代码三、代码解析四、使用while循环的快速排序1.代码代码1.由快

Win32下C++实现快速获取硬盘分区信息

《Win32下C++实现快速获取硬盘分区信息》这篇文章主要为大家详细介绍了Win32下C++如何实现快速获取硬盘分区信息,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 实现代码CDiskDriveUtils.h#pragma once #include <wtypesbase