其他分享
首页 > 其他分享> > Programming Pearls笔记之三

Programming Pearls笔记之三

作者:互联网

原文链接:http://www.cnblogs.com/Open_Source/archive/2012/08/05/2624036.html

 

Programming Pearls笔记之三

 

Programming Pearls笔记之三

  这里是编程珠玑(Programming Pearls)第三部分(后五个专栏)的笔记.

1 Partition

  快速排序最关键的一步是Partition,将一个元素放在正确的位置,它前面的元素都小于它,它后面的元素都不小于它.

1.1 Nico Lomuto的方法

  对于一个值t,将数组分成两部分,一部分小于t,一部分大于等于t.如图:

http://images.cnblogs.com/cnblogs_com/Open_Source/201208/201208051932522015.png

图一

  相应算法为:

m = a-1
for i = [a, b]
    if x[i] < t
        swap(++m, i)

  将x[l]作为数值t,如下图:

http://images.cnblogs.com/cnblogs_com/Open_Source/201208/201208051932533278.png

图二

  这时的a即l+1.b即u.算法终结时的状态是:

http://images.cnblogs.com/cnblogs_com/Open_Source/201208/201208051932552797.png

图三

  最后还要交换x[l]和x[m],状态为:

http://images.cnblogs.com/cnblogs_com/Open_Source/201208/20120805193256190.png

图四

1.2 一些改进

  Lomuto的方法有一点问题,就是当重复元素较多时效率会较差.对于n个元素全部相同的极端情况,时间复杂度变为O(n).下面的方案会较好:

http://images.cnblogs.com/cnblogs_com/Open_Source/201208/201208051932578488.png

图五

  这时算法是:

t = x[l]; i = l; j = u+1
loop
    do i++ while i <=u && x[i] < t
    do j-- while x[j] > t
    if i > j
      break
    swap(i, j)
swap(l, j)

  当所有元素都相等时.这个算法会交换相等的元素,这是不必要的.但它会将数组从正中间分成两部分,所以时间复杂度是O(n log n).这也是严、吴版《数据结构》课本上给出的算法.

  另外为了取得较好的平均时间复杂度,可以引用随机数:swap(l,randint(l,u)).即随机将数组中的一个元素跟x[l],用它作为t.

  还有就是当u-l较小时,快速排序效率并不好,这时可以设置一个临界值,当u-l小于这个值时不再进行Partition操作而是直接返回,这样最终结果虽然不是有序的,但却是大致有序的,这时可以再用插入排序处理一遍.

2 R.Sedgewick的优化

3 第k小元素

4 抽样问题

从0..n-1中等概率随机选取m(m<n)个并升序输出,要求不能有重复数值.

4.1 Knuth的方法S

select = m
remaining = n
for i = [0, n)
    if (bigrand() % remaining) < select
        print i
        select--
    remaining--   

  其中的bigrand()是产生一个随机整数.

  巧妙之处是直接升序考查,输出,不用再排序了.

4.2 Knuth的方法P

  先将数组随机打乱,然后将前m个排序.

for i = [0, n)
    swap(i, randint(i, n-1))
sort(x, x+m)
for i = [0, m)
    printf x[i]

  Ashley Shepherd和Alex Woronow发现只要对前m个进行打乱操作就行了:

void genshuf(int m, int n)
{
  int i, j;
  int *x = new int[n];
  for (i = 0; i < n; i++)
    x[i] = i;
  for (i = 0; i < m; i++) {
    j = randint(i, n-1);
    int t = x[i]; x[i] = x[j]; x[j] = t;
  }
  sort(x, x+m);
  for (i = 0; i < m; i++)
    cout << x[i] <<"\n";
}

4.3 m接近n的情况

4.4 n未知时的情况

5 最长重复子串

  最后只要比较排序后相信的子串,就可以得出最长重复子串,即"aba".

Footnotes:

1 这个问题书中没有提到,我也没有遇到过这个问题,估计Knuth的半数值算法中会有.这个算法是我想的,如有错误,请指出.

Date: 2012-07-28 六

Author: Hu Wenbiao

Org version 7.8.11 with Emacs version 24

Validate XHTML 1.0

转载于:https://www.cnblogs.com/Open_Source/archive/2012/08/05/2624036.html

标签:++,Pearls,之三,元素,Programming,int,算法,选中,swap
来源: https://blog.csdn.net/weixin_30654419/article/details/97236125