`
zhangzhenjj
  • 浏览: 27860 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

多线程快排

阅读更多
这里的代码来源于Stack Overflow,前几天面试,有个上机题,要求考虑多核的特性对一亿长度的随机整数数组进行排序,当时的想法和这个代码一样,因为排序算法中,快排比较适合多线程实现,所以回来后在Stack Overflow 找到了这部分代码。其中关键点在这里,注意第四行
private void quicksort(int pLeft, int pRight) {
            if (pLeft < pRight) {
                int storeIndex = partition(pLeft, pRight);
                if (count.get() >= FALLBACK * N_THREADS) {
                    quicksort(pLeft, storeIndex - 1);
                    quicksort(storeIndex + 1, pRight);
                } else {
                    count.getAndAdd(2);
                    pool.execute(new QuicksortRunnable<T>(values, pLeft, storeIndex - 1, count));
                    pool.execute(new QuicksortRunnable<T>(values, storeIndex + 1, pRight, count));
                }
            }
        }

我们知道快排是对一个数组不断的切成左右两部分,然后递归进行操作,那么这里一定要考虑多长的数组排序适合new一个新的线程,毕竟new新的线程花费大量机器时间,从上面我们可以看到,作者的想法是总线程数不超过当前内核数的两倍。对于多线程的控制或主线程与子线程同步问题,作者用了具有原子性的AtomicInteger,并自己编写代码实现的控制,这里也可以用CountDownLatch去实现。代码很简单,大家一看就明白了,我就不瞎扯了,如果大家有好的想法可以随便拍砖!!!!!!
public class Sorter {
    /**
     * Number of threads to use for sorting.
     */
    private static final int N_THREADS = Runtime.getRuntime().availableProcessors();

    /**
     * Multiple to use when determining when to fall back.
     */
    private static final int FALLBACK = 2;

    /**
     * Thread pool used for executing sorting Runnables.
     */
    private static Executor pool = Executors.newFixedThreadPool(N_THREADS);

    /**
     * Main method used for sorting from clients. Input is sorted in place using multiple threads.
     *
     * @param input The array to sort.
     * @param <T>   The type of the objects being sorted, must extend Comparable.
     */
    public static <T extends Comparable<T>> void quicksort(T[] input) {
        final AtomicInteger count = new AtomicInteger(1);
        pool.execute(new QuicksortRunnable<T>(input, 0, input.length - 1, count));
        try {
            synchronized (count) {
                count.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * Sorts a section of an array using quicksort. The method used is not technically recursive as it just creates new
     * runnables and hands them off to the ThreadPoolExecutor.
     *
     * @param <T> The type of the objects being sorted, must extend Comparable.
     */
    private static class QuicksortRunnable<T extends Comparable<T>> implements Runnable {
        /**
         * The array being sorted.
         */
        private final T[] values;
        /**
         * The starting index of the section of the array to be sorted.
         */
        private final int left;
        /**
         * The ending index of the section of the array to be sorted.
         */
        private final int right;
        /**
         * The number of threads currently executing.
         */
        private final AtomicInteger count;

        /**
         * Default constructor. Sets up the runnable object for execution.
         *
         * @param values The array to sort.
         * @param left   The starting index of the section of the array to be sorted.
         * @param right  The ending index of the section of the array to be sorted.
         * @param count  The number of currently executing threads.
         */
        public QuicksortRunnable(T[] values, int left, int right, AtomicInteger count) {
            this.values = values;
            this.left = left;
            this.right = right;
            this.count = count;
        }

        /**
         * The thread's run logic. When this thread is done doing its stuff it checks to see if all other threads are as
         * well. If so, then we notify the count object so Sorter.quicksort stops blocking.
         */
        @Override
        public void run() {
            quicksort(left, right);
            synchronized (count) {
                // AtomicInteger.getAndDecrement() returns the old value. If the old value is 1, then we know that the actual value is 0.
                if (count.getAndDecrement() == 1)
                    count.notify();
            }
        }

        /**
         * Method which actually does the sorting. Falls back on recursion if there are a certain number of queued /
         * running tasks.
         *
         * @param pLeft  The left index of the sub array to sort.
         * @param pRight The right index of the sub array to sort.
         */
        private void quicksort(int pLeft, int pRight) {
            if (pLeft < pRight) {
                int storeIndex = partition(pLeft, pRight);
                if (count.get() >= FALLBACK * N_THREADS) {
                    quicksort(pLeft, storeIndex - 1);
                    quicksort(storeIndex + 1, pRight);
                } else {
                    count.getAndAdd(2);
                    pool.execute(new QuicksortRunnable<T>(values, pLeft, storeIndex - 1, count));
                    pool.execute(new QuicksortRunnable<T>(values, storeIndex + 1, pRight, count));
                }
            }
        }

        /**
         * Partitions the portion of the array between indexes left and right, inclusively, by moving all elements less
         * than values[pivotIndex] before the pivot, and the equal or greater elements after it.
         *
         * @param pLeft
         * @param pRight
         * @return The final index of the pivot value.
         */
        private int partition(int pLeft, int pRight) {
            T pivotValue = values[pRight];
            int storeIndex = pLeft;
            for (int i = pLeft; i < pRight; i++) {
                if (values[i].compareTo(pivotValue) < 0) {
                    swap(i, storeIndex);
                    storeIndex++;
                }
            }
            swap(storeIndex, pRight);
            return storeIndex;
        }

        /**
         * Simple swap method.
         *
         * @param left  The index of the first value to swap with the second value.
         * @param right The index of the second value to swap with the first value.
         */
        private void swap(int left, int right) {
            T temp = values[left];
            values[left] = values[right];
            values[right] = temp;
        }
    }
}
1
2
分享到:
评论
6 楼 allon2 2013-07-22  
太复杂了,使用bitset即可,
5 楼 求求你帮帮我 2013-07-22  
一年工作经验的表示看不懂啊?怎么破?感觉好厉害的样子。
4 楼 xisuchi 2013-07-22  
                        
3 楼 zhangzhenjj 2013-07-21  
frank-liu 写道
用java里面的forkjoin框架,专门来对付这种派生出线程的问题。

google了一下,确实给力,长见识了
2 楼 frank-liu 2013-07-21  
用java里面的forkjoin框架,专门来对付这种派生出线程的问题。
1 楼 donlianli 2013-07-21  
这哪家公司,面试题也太变态了

相关推荐

    多线程实现冒泡,快速排序

    ### 多线程实现冒泡排序与快速排序 在计算机科学领域中,排序算法是数据结构与算法课程中的一个重要组成部分。本实验通过结合操作系统中的多线程技术来实现冒泡排序与快速排序两种经典的排序算法,并通过C++编程...

    多线程快速排序

    多线程快速排序,应付网络编程的小作业是个好东西!

    Qt多线程可视化多线程排序算法演示:冒泡和快排

    资源描述:基于Qt的可视化界面,编写的冒泡排序和可视化排序的比较算法,通过生成10000个随机数,多线程进行排序比较,可直观看到时间复杂度对程序运行的影响程度。 可以学到的知识:Qt多线程,多进程,冒泡排序算法...

    C#编写多线程搜索引擎

    在IT领域,多线程是提高程序性能和并发能力的重要技术。C#作为一种强大的编程语言,提供了丰富的多线程功能,使得开发者可以构建高效的多任务应用程序。本项目“C#编写多线程搜索引擎”(WebApplication1)正是利用...

    lucene索引优化多线程多目录创建索引

    本教程主要探讨的是如何利用Lucene进行索引优化,特别是通过多线程和处理多个目录来提高索引创建效率。 首先,我们需要理解Lucene的索引原理。Lucene将文档分解为词项(tokens),并对每个词项创建倒排索引。倒排...

    基于VC_的多线程聊天程序的设计与实现

    ### 基于VC++的多线程聊天程序设计与实现 #### 一、引言 随着信息时代的到来,计算机网络技术的飞速发展极大地改变了人们的生活方式,其中,网络聊天成为了日常交流的重要组成部分。为了满足日益增长的网络聊天...

    多线程搜索引擎java实现源代码

    本项目以"多线程搜索引擎java实现源代码"为标题,旨在介绍如何使用Java编程语言构建一个具备多线程特性的搜索引擎。这个搜索引擎可以抓取网络上的信息,存储网页快照,并建立索引,以便用户快速查询所需内容。下面...

    基于VC_的多线程通信程序设计.

    基于VC++的多线程通信程序设计是一种在软件开发领域广泛应用的技术,特别是在Windows平台上,它能够显著提升程序的性能和响应速度。本文将深入探讨基于VC++的多线程通信程序设计的关键概念、技术细节以及实际应用...

    多线程小例子之多线程Ping延迟测速-易语言

    在这个例子中,我们不仅实现了多线程 Ping,还对结果进行了排序,使得响应时间短的 IP 排在前面。 易语言中,创建线程通常需要定义一个函数,这个函数是在线程中运行的主体。在本例中,这个函数可能负责 Ping 操作...

    Qt多线程编程实例_QThread用法详解

    在Qt框架中,多线程编程是提升程序性能和响应性的重要手段,特别是在处理大量计算或I/O操作时。QThread作为Qt中的线程类,提供了便捷的接口用于管理线程。本文将深入探讨QThread的用法,并通过一个实例展示如何在...

    多进程实现快速排序(北京大学操作系统课程实习)

    - **结果分析:**相较于单线程版本,多线程版本在处理大规模数据时显示出明显的优势,尤其是在多核处理器上。 2. **多进程排序:** - **运行结果:**程序同样成功完成了排序任务。 - **结果分析:**多进程版本...

    为什么说Redis是单线程的以及Redis为什么这么快!

    简单解释下第二条:上下文切换就是cpu在多线程之间进行轮流执行(枪战cpu资源),而redis单线程的,因此避免了繁琐的多线程上下文切换。 重点解释下多路复用: 多路-指的是多个socket连接,复用-指的是复用一个线程...

    Springboot實現多綫程排隊實例

    在本文中,我们将深入探讨如何使用Spring Boot框架实现多线程排队系统,特别是在一个具有等待唤醒机制的应用场景中。这个系统允许用户创建房间并分配房间,如果房间不可用,用户会被放入等待队列中。我们将重点讲解...

    并行计算块排java实现

    并行快速排序的核心思想是利用多线程技术将原始数据分割成多个子集,并行地对这些子集进行快速排序,最后合并结果得到有序数组。这种方法尤其适用于大数据量排序,能够显著减少排序所需的时间。 #### 三、代码分析 ...

    SEO伴侣V1.2(最新版)

    多线程是一种编程技术,可以同时执行多个任务,从而提高软件的执行效率。在这个版本中,工具利用这一特性,使用户在进行大量数据查询时,能够感受到显著的速度提升,节省了大量等待时间。 此外,重新编写的蜘蛛模拟...

    openmp实现块排

    OpenMP(Open Multi-Processing)是一种用于共享内存多处理器环境的并行编程模型。它通过在源代码中添加编译指令的方式支持数据共享,并提供线程管理和任务调度的功能。OpenMP的目标是简化并行程序的开发过程,使...

    MPI与OpenMP并行计算的实验报告及源程序

    "OpenMP多线程编程实验.doc"则会介绍如何利用OpenMP实现多线程并行计算,可能包含了如何启用OpenMP、并行化循环、处理数据竞争和同步等问题的实例。实验可能包含对排序算法、图像处理或者科学计算问题的并行化,分析...

    lucene - 副本.zip

    《Lucene:多线程与多目录索引创建详解》 Lucene,作为一个强大的全文搜索引擎库,被广泛应用于各类信息检索系统中。在处理大量数据时,为了提高效率,我们通常会采用多线程和多目录的方式来创建索引。本文将深入...

    C++实现的最简单的倒排索引

    在分析和理解了`myindex.cpp`的实现后,我们可以尝试优化这个基础模型,例如,增加支持多线程处理大文件,或者引入更高效的压缩算法以减小索引的存储需求。此外,还可以实现查询功能,让用户输入单词并返回包含该...

    XRM复习.pdf

    多线程简单,速度快。 ·编写,调试:多进程简单;多线程复杂。 ·可靠性:多进程间不会相互影响;多线程一个挂掉可能会导致整个进程挂掉。 ·分布式:多进程适用于多核,多机分布式;多线程适用于多核单机分布式...

Global site tag (gtag.js) - Google Analytics