归并排序最有效的实现

2023-11-30

所以我想知道 Java 中合并排序最有效的实现是什么(如果它的时间效率会根据语言而变化)。这个问题可能很微不足道,但我的最终目标是向更有经验的程序员学习。这是我做的两个例子:

//version I made.
public static double[] mergeSort(double[] arreglo) {
    if (arreglo.length > 1) {
        int d = (arreglo.length / 2);
        double[] arreglo1 = Arrays.copyOfRange(arreglo, 0, d),
                arreglo2 = Arrays.copyOfRange(arreglo, d, arreglo.length);
        arreglo1 = mergeSort(arreglo1);
        arreglo2 = mergeSort(arreglo2);
        return merge(arreglo1, arreglo2);
    } else {
        return arreglo;
    }
}

public static double[] merge(double[] arreglo1, double[] arreglo2) {
    double[] convi = new double[arreglo1.length + arreglo2.length];
    for (int i = 0, m1 = 0, m2 = 0; i < convi.length; i++) {
        if (arreglo1.length > m1 && arreglo2.length > m2) {
            if (arreglo1[m1] <= arreglo2[m2])
                convi[i] = arreglo1[m1++];
            else {
                convi[i] = arreglo2[m2++];
            }
        } else {
            convi[i] = (arreglo1.length == m1) ? arreglo2[m2++] : arreglo1[m1++];
        }
    }
    return convi;
}

//Taken out of Cormens book.
public static void mergeSort(int[] arreglo, int i, int f) {
    if (f > i) {
        int d = ((i + f) / 2);
        mergeSort(arreglo, i, d);
        mergeSort(arreglo, d + 1, f);
        merge(arreglo, i, d, f);
    }
}


public static void merge(int[] arreglo, int i, int m, int f) {
    int n1 = (m - i) + 1;
    int n2 = (f - m);
    int[] mitad1 = new int[n1 + 1];
    int[] mitad2 = new int[n2 + 1];
    for (int v = 0; v < n1; v++) {
        mitad1[v] = arreglo[i + v];
    }
    for (int p = 0; p < n2; p++) {
        mitad2[p] = arreglo[p + m + 1];
    }
    mitad1[n1] = Integer.MAX_VALUE;
    mitad2[n2] = Integer.MAX_VALUE;
    for (int r = i, m1 = 0, m2 = 0; r <= f; r++) {
        if (mitad1[m1] <= mitad2[m2]) {
            arreglo[r] = mitad1[m1];
            m1++;
        } else {
            arreglo[r] = mitad2[m2];
            m2++;
        }
    }
}

以下程序是从 C++ 示例翻译而来的Robert Sedgewick 的 C++ 算法,第 1-4 部分

它引入了一种类型的改进。它将整个排序数组复制到一个辅助数组中以供进一步处理。接下来,通过在辅助数组和原始数组之间交替来对辅助数组进行递归分割,这样就不会发生合并数组的额外复制操作。基本上,该算法在每次递归调用中切换输入数组和辅助数组的角色。例如,从概念上来说:

常规归并排序:

--merge

(((8) (5))((2) (3)))(((1) (7))((4) (6)))

(( 5 8 )( 2 3 ))(( 1 7 )( 4 6 ))

-- copy back and ignore previous (UNNECESSARY)

(( 5 8 )( 2 3 ))(( 1 7 )( 4 6 ))

– – – – – – – –

这个程序:

--merge

(((8) (5))((2) (3)))(((1) (7))((4) (6)))

(( 5 8 )( 2 3 ))(( 1 7 )( 4 6 ))

--向后合并

( 2 3 5 8 )( 1 4 6 7 )

(( 5 8 )( 2 3 ))(( 1 7 )( 4 6 ))    

此外,将数组分成两半后给出足够小的数组,该算法使用insertion sort因为它在小数据集上的表现比merge sort。确切何时使用的阈值insertion sort可以通过反复试验来确定。

代码:

static int M = 10;

//insertion sort to be used once the mergesort partitions become small enough
static void insertionsort(int[] a, int l, int r) {
    int i, j, temp;
    for (i = 1; i < r + 1; i++) {
        temp = a[i];
        j = i;
        while ((j > 0) && a[j - 1] > temp) 
        {
            a[j] = a[j - 1];
            j = j - 1;
        }
        a[j] = temp;
    }
}

//standard merging two sorted half arrays into single sorted array
static void merge(int[] merged_a, int start_a, int[] half_a1, int start_a1, int size_a1, 
                         int[] half_a2, int start_a2, int size_a2) {
    int i, j, k;
    int total_s = size_a1 + size_a2;
    for (i = start_a1, j = start_a2, k = start_a; k < (total_s); k++) {
        // if reached end of first half array, run through the loop 
        // filling in only from the second half array
        if (i == size_a1) {
            merged_a[k] = half_a2[j++];
            continue;
        }
        // if reached end of second half array, run through the loop 
        // filling in only from the first half array
        if (j == size_a2) {
            merged_a[k] = half_a1[i++];
            continue;
        }
        // merged array is filled with the smaller element of the two 
        // arrays, in order
        merged_a[k] = half_a1[i] < half_a2[j] ?
                      half_a1[i++] : half_a2[j++];
    }
}

//merge sort data during merging without the additional copying back to array
//all data movement is done during the course of the merges
static void mergesortNoCopy(int[] a, int[] b, int l, int r) {
    if (r - l <= M) {
        insertionsort(a + l, l, r - l);
        return;
    }
    int m = (l + r) / 2;
    //switch arrays to msort b thus recursively writing results to b
    mergesortNoCopy(b, a, l, m); //merge sort left
    mergesortNoCopy(b, a, m + 1, r); //merge sort right
    //merge partitions of b into a
    merge(a, l, b, l, m - l + 1, b, m + 1, r - m); //merge
}

static void mergesort(int[] a) {
    int[] aux = Arrays.copyOf(a, a.length);
    mergesortNoCopy(a, aux, 0, a.length - 1);
}

其他一些可能的改进:

如果已经排序则停止。

检查前半部分最大的项是否≤后半部分的最小项。 对部分有序数组有帮助。

// after split, before merge
if (a[mid] <= a[mid + 1]) return;

EDIT:这里有一个好文件我发现了不同版本的合并排序及其改进。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

归并排序最有效的实现 的相关文章

  • 为自定义驱动程序创建 GraphicsDevice

    我正在开发一个在嵌入式系统中使用 Java 的项目 我有用于屏幕和触摸输入的驱动程序 以及用于文本输入的虚拟键盘 我的屏幕驱动程序有一个Graphics2D您可以绘制的对象和repaint Rectangle 更新方法 类似地 触摸驱动器能
  • Java中的断点和逐步调试?

    抱歉我的问题名称很奇怪 我不知道如何寻找这个 因为我不知道这些东西是如何称呼的 Visual Studio 中至少有一个功能 您可以单击代码左侧并设置一个大红点的起点 然后运行程序 您可以通过按 f8 或 f5 实际上是不同的 f 来跟踪步
  • Android蓝牙java.io.IOException:bt套接字已关闭,读取返回:-1

    我正在尝试编写一个代码 仅连接到运行 Android 5 0 KitKat 的设备上的 目前 唯一配对的设备 无论我尝试了多少方法 我仍然会收到此错误 这是我尝试过的最后一个代码 它似乎完成了我看到人们报告为成功的所有事情 有人能指出我做错
  • 在 MongoDB 和 Apache Solr 之间同步数据的简单方法

    我最近开始使用 MongoDB 和 Apache Solr 我使用 MongoDB 作为数据存储 并且希望 Apache Solr 为我的数据创建索引 以实现应用程序中的搜索功能 经过一些研究 我发现 基本上有两种方法可以在 MongoDB
  • 使用链表进行堆排序

    我想知道是否有人曾经使用链表进行堆排序 如果他们可以提供代码 我已经能够使用数组进行堆排序 但尝试在链表中进行排序似乎不切实际 而且在你知道的地方很痛苦 我必须为我正在做的项目实现链接列表 任何帮助将不胜感激 我也用C 答案是 你不想在链表
  • 机器人探索算法

    我正在尝试为机器人设计一种算法 试图找到位于未知位置的旗帜 该旗帜位于一个包含障碍物的世界中 机器人的任务是夺取旗帜并将其带到他的基地 代表他的起始位置 机器人在每一步只能看到有限的邻域 他事先不知道世界是什么样子 但他有无限的内存来存储已
  • 当 minifyEnabled 为 true 时 Android 应用程序崩溃

    我正在使用多模块应用程序 并且该应用程序崩溃时minifyEnabled true in the installed模块的build gradle 以下是从游戏控制台检索到的反混淆堆栈跟踪 FATAL EXCEPTION Controlle
  • 在Python上获取字典的前x个元素

    我是Python的新手 所以我尝试用Python获取字典的前50个元素 我有一本字典 它按值降序排列 k 0 l 0 for k in len dict d l 1 if l lt 51 print dict 举个小例子 dict d m
  • Eclipse - 安装新的 JRE (Java SE 8 1.8.0)

    我正在尝试安装 Java 8 到目前为止我所做的 安装最新版本的 Eclipse 下载并安装 Java SE 运行时环境 8http www oracle com technetwork java javase downloads jre8
  • 在 Java 中通过 XSLT 分解 XML

    我需要转换具有嵌套 分层 表单结构的大型 XML 文件
  • Java、Spring:使用 Mockito 测试 DAO 的 DataAccessException

    我正在尝试增加测试覆盖率 所以我想知道 您将如何测试 DAO 中抛出的 DataAccessExceptions 例如在一个简单的 findAll 方法中 该方法仅返回数据源中的所有数据 就我而言 我使用 Spring JdbcTempla
  • 用于缓存的 Servlet 过滤器

    我正在创建一个用于缓存的 servlet 过滤器 这个想法是将响应主体缓存到memcached 响应正文由以下方式生成 结果是一个字符串 response getWriter print result 我的问题是 由于响应正文将不加修改地放
  • 如何通过 Android 按钮单击运行单独的应用程序

    我尝试在 Android 应用程序中添加两个按钮 以从单独的两个应用程序订单系统和库存系统中选择一个应用程序 如图所示 我已将这两个应用程序实现为两个单独的 Android 项目 当我尝试运行此应用程序时 它会出现直到正确选择窗口 但是当按
  • 如何停止执行的 Jar 文件

    这感觉像是一个愚蠢的问题 但我似乎无法弄清楚 当我在 Windows 上运行 jar 文件时 它不会出现在任务管理器进程中 我怎样才能终止它 我已经尝试过 TASKKILL 但它对我也不起作用 On Linux ps ef grep jav
  • Java - 从 XML 文件读取注释

    我必须从 XML 文件中提取注释 我找不到使用 JDOM 或其他东西来让它们使用的方法 目前我使用 Regex 和 FileReader 但我不认为这是正确的方法 您可以使用 JDOM 之类的东西从 XML 文件中获取注释吗 或者它仅限于元
  • 我可以限制分布式应用程序发出的请求吗?

    我的应用程序发出 Web 服务请求 提供商处理的请求有最大速率 因此我需要限制它们 当应用程序在单个服务器上运行时 我曾经在应用程序级别执行此操作 一个对象跟踪到目前为止已发出的请求数量 并在当前请求超出允许的最大负载时等待 现在 我们正在
  • JMS 中的 MessageListener 和 Consumer 有什么区别?

    我是新来的JMS 据我了解Consumers能够从队列 主题中挑选消息 那么为什么你需要一个MessageListener因为Consumers会知道他们什么时候收到消息吗 这样的实际用途是什么MessageListener 编辑 来自Me
  • Java 的 PriorityQueue 与最小堆有何不同?

    他们为什么命名PriorityQueue如果你不能插入优先级 它看起来与堆非常相似 有什么区别吗 如果没有区别那为什么叫它PriorityQueue而不是堆 默认的PriorityQueue是用Min Heap实现的 即栈顶元素是堆中最小的
  • 将对象从手机共享到 Android Wear

    我创建了一个应用程序 在此应用程序中 您拥有包含 2 个字符串 姓名和年龄 和一个位图 头像 的对象 所有内容都保存到 sqlite 数据库中 现在我希望可以在我的智能手表上访问这些对象 所以我想实现的是你可以去启动 启动应用程序并向左和向
  • try-with-resources 中出现死代码警告,但翻译后的 try-catch-finally 中没有出现死代码警告

    以下代码使用try 有资源 https docs oracle com javase specs jls se7 html jls 14 html jls 14 20 3Java 8 中引入的构造 偶尔抛出 方法被声明为抛出一个偶尔的异常

随机推荐