为什么我的快速排序这么慢?

发布于 2024-10-10 12:48:42 字数 2463 浏览 0 评论 0原文

作为面试准备的一部分,我正在练习编写排序算法,我想知道是否有人可以帮助我找出为什么这种快速排序不是很快?它似乎具有正确的运行时复杂性,但它比我的合并排序慢大约 2 的常数因子。我也很感激任何可以改进我的代码但不一定回答问题的评论。

非常感谢您的帮助!如果我犯了任何礼仪错误,请随时告诉我。这是我的第一个问题。

private class QuickSort implements Sort {

        @Override
        public int[] sortItems(int[] ts) {
            List<Integer> toSort = new ArrayList<Integer>();
            for (int i : ts) {
                toSort.add(i);
            }
            toSort = partition(toSort);
            int[] ret = new int[ts.length];
            for (int i = 0; i < toSort.size(); i++) {
                ret[i] = toSort.get(i);
            }
            return ret;
        }

        private List<Integer> partition(List<Integer> toSort) {
            if (toSort.size() <= 1)
                return toSort;
            int pivotIndex = myRandom.nextInt(toSort.size());
            Integer pivot = toSort.get(pivotIndex);
            toSort.remove(pivotIndex);
            List<Integer> left = new ArrayList<Integer>();
            List<Integer> right = new ArrayList<Integer>();
            for (int i : toSort) {
                if (i > pivot)
                    right.add(i);
                else
                    left.add(i);
            }
            left = partition(left);
            right = partition(right);
            left.add(pivot);
            left.addAll(right);
            return left;
        }

}

非常感谢所有提供帮助的人!

这是我为后代改进的课程:

private class QuickSort implements Sort {

        @Override
        public int[] sortItems(int[] ts) {
            int[] ret = ts.clone();
            partition(ret,0,ret.length);
            return ret;
        }

        private void partition(int[] toSort,int start,int end) {
            if(end-start<1) return;
            int pivotIndex = start+myRandom.nextInt(end-start);
            int pivot = toSort[pivotIndex];
            int curSorted = start;
            swap(toSort,pivotIndex,start);
            for(int j = start+1; j < end; j++) {
                if(toSort[j]<pivot) {
                    if(j!=curSorted+1) 
                        swap(toSort,curSorted,curSorted+1);
                    swap(toSort,j,curSorted++);
                }
            }
            // Now pivot is at curSorted
            partition(toSort,start,curSorted);
            partition(toSort,curSorted+1,end);
        }
    }

I am practicing writing sorting algorithms as part of some interview preparation, and I am wondering if anybody can help me spot why this quick sort is not very fast? It appears to have the correct runtime complexity, but it is slower than my merge sort by a constant factor of about 2. I would also appreciate any comments that would improve my code that don't necessarily answer the question.

Thanks a lot for your help! Please don't hesitate to let me know if I have made any etiquette mistakes. This is my first question here.

private class QuickSort implements Sort {

        @Override
        public int[] sortItems(int[] ts) {
            List<Integer> toSort = new ArrayList<Integer>();
            for (int i : ts) {
                toSort.add(i);
            }
            toSort = partition(toSort);
            int[] ret = new int[ts.length];
            for (int i = 0; i < toSort.size(); i++) {
                ret[i] = toSort.get(i);
            }
            return ret;
        }

        private List<Integer> partition(List<Integer> toSort) {
            if (toSort.size() <= 1)
                return toSort;
            int pivotIndex = myRandom.nextInt(toSort.size());
            Integer pivot = toSort.get(pivotIndex);
            toSort.remove(pivotIndex);
            List<Integer> left = new ArrayList<Integer>();
            List<Integer> right = new ArrayList<Integer>();
            for (int i : toSort) {
                if (i > pivot)
                    right.add(i);
                else
                    left.add(i);
            }
            left = partition(left);
            right = partition(right);
            left.add(pivot);
            left.addAll(right);
            return left;
        }

}

Thanks a ton, everybody who helped!

This is my much improved class for posterity:

private class QuickSort implements Sort {

        @Override
        public int[] sortItems(int[] ts) {
            int[] ret = ts.clone();
            partition(ret,0,ret.length);
            return ret;
        }

        private void partition(int[] toSort,int start,int end) {
            if(end-start<1) return;
            int pivotIndex = start+myRandom.nextInt(end-start);
            int pivot = toSort[pivotIndex];
            int curSorted = start;
            swap(toSort,pivotIndex,start);
            for(int j = start+1; j < end; j++) {
                if(toSort[j]<pivot) {
                    if(j!=curSorted+1) 
                        swap(toSort,curSorted,curSorted+1);
                    swap(toSort,j,curSorted++);
                }
            }
            // Now pivot is at curSorted
            partition(toSort,start,curSorted);
            partition(toSort,curSorted+1,end);
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

陌上青苔 2024-10-17 12:48:42

快速排序的最大优点之一是它可以作为就地算法实现。不要创建新列表,而是就地对元素进行排序。

One of the biggest advantages of Quicksort is that it can be implemented as an in-place algorithm. Don't create new lists, sort the elements in-place instead.

睡美人的小仙女 2024-10-17 12:48:42

除了不重复使用列表之外,您还可以在每个步骤中在 Integer 和 int 之间进行转换:

        for (int i : toSort) {  // converts from Integer to int
            if (i > pivot)
                right.add(i);  // converts from int to Integer
            else
                left.add(i);   // converts from int to Integer
        }

请注意,从 int 到 Integer 的转换通常需要创建一个新对象。

最后 random.nextInt() 可能是一个不平凡的操作。如果 toSort 超过一定大小,则最好仅选择随机主元,否则使用更简单的主元选择策略(测量它!)。

In addition to not reusing lists, you convert between Integer and int in each step:

        for (int i : toSort) {  // converts from Integer to int
            if (i > pivot)
                right.add(i);  // converts from int to Integer
            else
                left.add(i);   // converts from int to Integer
        }

Note that conversion from int to Integer in general requires a new object to be created.

And finally random.nextInt() might be a non-trivial operation. Perhaps it would be better to only select a random pivot if the toSort exceeds a certain size and use a simpler pivor selection strategy otherwise (Measure it!).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文