• 跟着Sedgewick学算法(week 1 ElementarySort)


     链接https://www.evernote.com/shard/s408/sh/dbe0167f-20e0-41c4-a49b-75717ad98695/461148482ffb6add092bebc9d90a4a2a
     
     搜索和排序一项是算法的两大主题,重要性不言而喻。Robert在第一周的lecture 2就是从基本的排序算法说起。包括选择排序(应该也叫冒泡排序)、插入排序,希尔排序(Shell Sort),附带讲了shuffle(随机序列),以及凸集。我们一点点说。

    零、Total Order
    A total orderis a binary relation ≤that satisfies:
    1。Antisymmetry: if v ≤ w and w ≤ v, then v= w.
    2。Transitivity: if v ≤ w and w ≤ x, then v ≤ x.
    3。Totality: either v ≤ w or w ≤ vor both.  

    一、选择排序
     
    如下原始序列:
       a= [ 9 2 1 4 8 7 5 6 3]
               i=0
    经过一次swap
      a= [ 1 2 9 4 8 7 5 6 3]
                i=1
    经过两次swap(索引1和索引1交换)
      a= [ 1 2 9 4 8 7 5 6 3]
                   i=2
    从序列中选出最小的 也就是1,索引为2,a[i]与a[2]交换,i=i+1,从余下的序列中再选出最小的,也即2,a[1]与a[1]交换,也即保持不动,循环知道最后一个元素,c#简单代码:
            public void SelectSort(ref int [] a)
            {
                int count = a.Length;
                for ( int i = 0; i < count; i++)
                {
                    int min = i;
                    for ( int j = i+1; j <count; j++)
                    {
                        if (a[j] < a[min]) min = j;
                    }
                    Swap( ref a, i, min);
                }
            }
            public void Swap( ref int[] a , int i, int j)
            {
                int temp = a[i] ;
                a[i] = a[j];
                a[j] = temp;
            }
    选择最小值需要比较的次数 N-1+N-2+……+2+1+0 ~N^2/2,元素交换的次数N。
    即使输入时已经排序好的,也要经过Quadratic time。数据移动是线性的,而且不需要额外空间。

    二、插入排序
    如下原始序列:
       a= [ 9 2 1 4 8 7 5 6 3]
               i=0
    经过一次插入
      a= [ 2 9 1 4 8 7 5 6 3]
                i=1
    经过两次插入
      a= [ 1 2 9 4 8 7 5 6 3]
                   i=2
    不描述过程,太难了,直接看代码吧
           public void Swap( ref int[] a ,int i,int j)
            {
                int temp = a[i] ;
                a[i] = a[j];
                a[j] = temp;
            }
            public void InsertSort( ref int[] a)
            {
                int count = a.Length;
                for ( int i = 0; i < count; i++)
                {
                    for ( int j = i; j > 0; j--)
                    {
                       if(a[j]<a[j-1]) Swap( ref a, j,j-1);
                        else break;
                    }
                }
            }
    用插入排序,对于个随机的数列,需要1/4*N^2比较和1/4*N^2次交换,不需要额外空间。
    如果输入序列式最好的,即已经升序排好的,只需N-1次比较和0次交换
    最坏情况,如果输入是降序排好的,将需要1/2*N^2次比较和1/2*N^2交换

    三、shell排序
    感觉shell排序和插入排序差不多,算是插入排序的一种,和插入排序不同,shell排序每次不是和后继元素比较,而是和一定步长之后的元素比较,每个元素都如此,一轮过后,缩小步长,继续知道步长为1,此时也就是插入排序,得出结果。
    根据数据大小来选择步长,步长一般有:
    1.  1,2,4,8,16......也就2的幂
    2.  1,3,7,15....2的幂减1
    3. 3x+1,即1,4,13,40,121....
    还有就是
    4. Sedgewick. 1, 5, 19, 41, 109, 209, 505, 929, 2161, 3905, …
     
    据robert介绍,1不行,2一般,3还好,4最好(也就是他自己提出的)。没有证明~~~
    方便写代码,用3的步长~~
             public void ShellSort( ref int[] a)
            {
                int count = a.Length;
                int h =1;
                while (h < count / 3) h = h * 3 + 1; //先找到最大的步长
                while (h>=1)
                {
                    for ( int i = 0; i+h<count; i++)//ps纸上得来终觉浅,这一步没写好,因为a[i]和a[i+h]比较后,如果a[i+h]小于a[i],那么a[i+h]要继续和
                    {                               //a[i]之前的元素比较,以前我以为不需要呢,所以搞错了。需知此事要躬行啊啊啊
                        for ( int j = i + h; j >=h && a[j] < a[j - h]; j--)
                        {
                            Swap( ref a, j, j - h);
                        }
                    }
                    h = h / 3;
                }
            }
        
    Proposition. The worst-case number of compares used by shellsort with
    the 3x+1 increments is O(N3/2).
     
    希尔排序目前还没有accurate model!!!
    为什么对希尔排序感兴趣?
     
    1.现实中,对于较小的序列,排序很快,可以用在嵌入式系统
    2.虽然是简单的算法,但性能很不错。而且还有很多问题未解决,如算法的渐进增长率、最佳步长序列,平均性能。
    3.所以说,还有好的算法等待发现。
     

    四、随机序列
    比较简便的方法是:
    1 2 3 4 5 6 7 8 9
    对于该序列,每一个数字都随机生成一个随机数,然后按随机数大小排序。
     
    Proposition. Shuffle sort produces a uniformly random permutation
    of the input array, provided no duplicate values,where assuming real numbers uniformly at random
     
    Knuth提出的一个方法是:在第i次迭代时,随机选择0到i之间的整数r,然后交换a[i]和a[r].
    Proposition:Knuth的shuffle算法能在线性时间能得到一个均匀随机数列。
    便于分析,从i=1开始,考虑第一个元素,也就考虑索引为1位置的元素
    在开始第1次时
    i=1;r=1; 索引1的元素保持不变
    在第2次时
    i=1,2,索引1 和 2交换位置的概率为1/2,索引1的元素在1或者2位置上的概率是1/2
    在第3次时
    i=1,2,3,原始1位置上的元素换到第三个位置上的概率1/2*1/3+1/2*3=1/3
    同理,第4次
    i=1,2,3,4 原始1位置的元素,在每个位置上的概率 1/3*1/4+1/3*1/4+1/3*1/4=1/4
    依次推下去可医治,每个元素在任意位置的概率为1/N。
    简单代码如下
    public static void shuffle(ref int[] a)
    {
    int N = a.length;
    for (int i = 0; i < N; i++)
    {
    int r = Random(i + 1);
    swap(ref a, i, r);
    }
    }
    一个实例,online poker 在线扑克的程序bug。
    做到真正的shuffle其实挺难的。也可以依赖硬件,随机数产生器blabla不叙说了。

    五 凸集
     
    实数 R (或复数 C 上)在向量空间中,如果 S 中任两点的连线内的点都在集合 S 内,集合 S 称为凸集。
    一个直白叙述就是,从一个点开始,可以一直逆时针找到一个点,点与点连线,能将所以点都包住。
    下面就是凸集。
     
     
    懒得写了,给出三个点序,a->b->c,怎么判断是否是逆时针顺序的
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    了解AOP
    Struts2 拦截器与Spring AOP的区别
    Spring核心技术之IoC和AOP
    产品经理历险记-2-如何把需求聊得更细
    产品经理历险记-1-记录一次事故
    C# 使用 Lotus notes 公共邮箱发送邮件
    设计模式 5/23 原型模式
    设计模式 4/23 建造者模式
    设计模式 3/23 抽象工厂模式
    设计模式 2/23 工厂模式(二)
  • 原文地址:https://www.cnblogs.com/yanbinliu/p/3814945.html
Copyright © 2020-2023  润新知