免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 11736 | 回复: 22
打印 上一主题 下一主题

[算法] Quick Sort 的一个注记 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-11-04 18:21 |只看该作者 |正序浏览
这是我 blog 上新发的一个随笔--- 一个“学而不思则惘”的故事。


前天参加一个讨论班,报告者在讲 Quick Sort 时,精力全集中在分割算法上了。他说:“你们一定要多体会一下,这个算法是先跟这边比,再跟那边比,又跟这边比,再跟那边比,如是直到相会。不这样的话,将无法理解 Quick Sort.

对这个说法我很不同意。当然线性时间的分割算法是 Quick Sort 最出彩,最有技巧的地方,但 Quick Sort 的 big idea 并不在这里。从大方向上看,Quick Sort 都干了什么?

    * 找一个枢纽元 p ,把数组分成两部分,左边的比 p 小,右边的比 p 大。
    * 找一个元素 r, 把数组分成两部分,比 r 小的作为子树接在 r 的左边,比 r 大的最为子树接在树的右边。

不难看出,Quick Sort 其实在建一棵二叉排序树,这是它跟其它排序算法最不同的地方。其它几种常见的排序算法都专注于如何排出一个按序的线性序列,Quick Sort 表面上也如此,但背后却藏了一棵二叉树。这也能说明为什么原始的 Quick Sort 会有一个 O(n^2) 的最坏情形,此时对应的二叉树一定非常不平衡(比如输入是基本有序的,你却用第一个元素作为枢纽元)。

其实我们可以丢掉 Quick Sort 的分割算法,通过建立二叉排序树来得到一个理论上能与 Quick Sort 抗衡的排序算法。

    * 通过插入建立一棵平衡二叉树,时间界 O(nlog n);
    * 先序遍历此树,得到排好序的序列,时间界 O(n);

这样,总的时间界也是 O(nlog n)。这个算法在实践中当然不如 Quick Sort,因为 Quick Sort 的分割算法效率很高,而且最后不用去遍历一棵二叉树,但是它对于理解 Quick Sort 是有帮助的。

[ 本帖最后由 win_hate 于 2007-11-4 18:27 编辑 ]

论坛徽章:
0
23 [报告]
发表于 2008-07-30 17:34 |只看该作者
学习了

论坛徽章:
0
22 [报告]
发表于 2008-07-30 17:10 |只看该作者
#include <iostream>
using namespace std;

//quickSort algorithm
template < class T >
int partition(T a[], int p, int r){
T x = a[r];
int i = p-1;
  for(int j=p;j<r;j++){
    if(a[j] <= x){
     i++;
     swap(a,a[j]);
    }
  }
  swap(a[i+1], a[r]);
  return i+1;
}


template< class T >
void quickSort(T a[], int p, int r){
if(p < r){
  int q = partition(a, p , r);
  quickSort(a, p , q-1);
  quickSort(a, q+1 , r);
}
}

int main()
{
    int arr[]={23,31,4,9,12,7,59};
    int const n=sizeof(arr)/sizeof(arr[0]);
    for(int i=0;i<n;++i) cout<<"arr["<<i<<"]: "<< arr<<endl;
quickSort(arr,0,n);
cout<<"after sort: "<<endl;
for(int i=0;i<n;++i) cout<<"arr["<<i<<"]: "<< arr<<endl;

}

论坛徽章:
0
21 [报告]
发表于 2008-04-23 09:07 |只看该作者
"通常快速排序为了效率,都是选取中间点作为枢纽元. 现有从1到15,15个元素.请问这15个元素如何排列,能让选取中点作为枢纽元的排序方案也只能有O(n^2)的效率?"
这个应该怎么做呢?

论坛徽章:
0
20 [报告]
发表于 2008-03-27 18:15 |只看该作者
我也同意快速排序的关键在于分割,其它的只是具体的实现方法而已。

论坛徽章:
0
19 [报告]
发表于 2008-03-27 16:03 |只看该作者
这个问题,我也是觉得快速排序的基本出发点是分而治之,至于分割方法只是其中的细节。

论坛徽章:
0
18 [报告]
发表于 2007-11-05 13:20 |只看该作者
原帖由 halve 于 2007-11-5 10:08 发表
昨天看<<啊!灵机一动>>,里头有个求最短路径的问题
用的是动态规划的方法,但最后结构上来说恰好和帕斯卡(杨辉)三角形一致
我们不能因此就说,精华在于这个帕斯卡三角形吧。。。

sorry,这里有个记忆错误 ; (
应该是求2点间的所有路径组合问题,而不是最短路径

论坛徽章:
0
17 [报告]
发表于 2007-11-05 13:18 |只看该作者

回复 #13 ypxing 的帖子

堆排序貌似用的完全二叉树。

论坛徽章:
0
16 [报告]
发表于 2007-11-05 12:53 |只看该作者
分治是个很大很抽象很广泛的指导思想,在涉及具体问题的时候,有时会不知道如何使用它

而建二叉排序树的想法则具体得多。

随机建一个二叉排序树的最坏时间,最好时间,平均时间刚好与 Quick Sort  的时间相应。

[ 本帖最后由 win_hate 于 2007-11-5 12:54 编辑 ]

论坛徽章:
0
15 [报告]
发表于 2007-11-05 12:48 |只看该作者
其实也可以这样理解:
有了分治和分割
一个二叉排序树的形成就是很自然的了

可能又跑到先有鸡还是先有蛋的问题上了

原帖由 win_hate 于 2007-11-5 12:44 发表
我说的是二叉排序树,堆排序里的那个就叫堆
  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP