zoukankan      html  css  js  c++  java
  • 基本排序算法(冒泡,快排,插入,希尔,选择,归并)

    这篇文章仅仅为心中自证,不是算法教学,也不想误人子弟,谢谢各位。

    第一章:一些感慨

      我断断续续学习算法两年多了,这说起来是多么苦涩,是我笨嘛?一直不知道算法是什么东西。

    从《算法导论》再到《C算法》不清楚看了多少遍,它们就是我过不去的坎吗?

      

      不敢说什么大话,但是我有一个心得,学习算法,一定要理解,理解比会写更重要,会写,很有可能仅仅是记忆好,

    但是过一段时间忘了, 就对这个算法完全没有印象了,我就是这样。

      所以我以后学习算法,一定抱着理解的心态,理解了,就很好。

    第二章:基本排序算法

    2.1 冒泡排序

      人们常说,冒泡排序是最初级的排序算法,人们说这句话的时候是从时间复杂度这个角度来说的,这么说或许没错,

    但是,冒泡排序是相当漂亮的排序,这个“漂亮”是说,假如把排序算法可视化起来,x轴从小到大,依次对应0到n,y轴对应的是a[x],

    然后排序开始了,你会发现冒泡很飘逸,看起来很赏心悦目,大概人们都喜欢美丽的泡泡吧。

      冒泡排序的中心思想:不写中心思想至少也有十年了吧,记得高中之后语文老师就不搞什么中心思想之类的。

    但是我还是要写一写冒泡排序的中心思想,而且,现在我不看资料,我想描述一下,看一看我到底能不能描述。

      冒泡排序的思想是这样的,从数组a[0]开始,比较相邻的两项的大小顺序,假如顺序不对,则交换两项。

    5 4 6 3 2

      比如上面的数组,先比较a[0]和a[1],发现a[0]大于a[1],我们认为从小到大排,所以顺序就不对了,那就交换吧,交换之后就是

    4 5 6 3 2

      再然后就是比较a[1]和a[2]了,就这样,一次冒泡,最大项就冒到了顶部。

      很明显,我们需要两层循环,可是第二次循环的时候,我们就没必要从0到n了,因为我们知道a[n-1]项已经是最大的了。

     1 void BubbleSort(Item a[],int left,int right)
     2 {
     3       int i = 0,j = 0;
     4       for(i = left; i < right; i++) 
     5       {
     6             for(j = left;j < right -i - 1; j++)
     7             {
     8                    compexch(a[j],a[j+1]);
     9             }
    10       }  
    11 }
    12 void BubbleSort(Item a[],int left,int right)
    13 {
    14       int i = 0,j = 0;
    15       for(i = left; i < right; i++) 
    16       {
    17             for(j = right;j > i; j--)
    18             {
    19                    compexch(a[j-1],a[j]);
    20             }
    21       }  
    22 }

    2.2 快速排序

      记得有谁说过,快速排序是在冒泡排序的基础上的,这个,我信了。

          快速排序的中心思想:在我看来快速排序的中心思想是很简单的,我不知道快排的发明人是怎么想出来的。

          快排的思想是,选择数组中的一个数,把它放到排序结束后它应该在的位置。

          这是一句很有意思的话,我怎么知道一个数排序结束后它在哪呢?其实可以知道的,

          我们希望一次排序结束后,这个数左边的所有数都比这个数小,这个数右边所有的数都比这个数大。

          然后我们对它的左边用快排,然后对他的右边用快排。

          最原始的写法是这样的。

     1 int partition(int * a,int l,int r)
     2 {
     3     int i = l-1,j = r;
     4     int v = a[r];
     5     for(;;)
     6     {
     7         while(a[++i] < v);
     8         while(v < a[--j])
     9             if(j == l)
    10             break;
    11         if(i >= j)
    12             break;
    13         EXCH(a[i],a[j]);
    14     }
    15     EXCH(a[i],a[r]);
    16     return i;
    17 }
    18 void QuickSort(int * a,int l,int r)
    19 {
    20     int i;
    21     if(r <= l)
    22         return;
    23     i = partition(a,l,r);
    24     QuickSort(a,l,i-1);
    25     QuickSort(a,i+1,r);
    26 }

      partition函数的中心思想:partition函数的功能,就是从数组中选取一个数,然后让左边的全部小于它,右边的全部大于它,然后返回位置就行了。

    但是上面的partition真是大有问题,在正序和逆序的时候,很多人都哭了,所以常见的做法是,选取的这个数是随机选取的。

    一个或许可能的解决方案是这个,(我又空手敲代码了,我有可能写出来吗?)(没有,我又看了好多资料,调试了好久。)

    int partition(int * a,int l,int r)
    {
        int i = l-1;
        int j = r;
        int m = l+rand()%(r-l+1);
        EXCH(a[m],a[r]);
        int v = a[r];
        for(;;)
        {
            while(a[++i] < v);
            while(v < a[--j])
                if(j == l)
                    break;
            if(i >= j)
                break;
            EXCH(a[i],a[j]);
            PrintArray(a);
        }
        EXCH(a[i],a[r]);
        PrintArray(a);
        return i;
    }

     2.3 插入排序

           或许,我根本不适合学习算法,还是放弃吧,写完这一章。

           插入排序的中心思想:我是这样理解的,待排序项一直左移,已经排好的一直右移,直到某一项小于待排序项。

           从第二项开始一直执行这样的操作。

           缺点:数组移动。

     1 void InsertSort(int * a,int l,int r)
     2 {
     3      for(int i = l+1;i < r; i++)
     4      {
     5            int j = i;
     6            int v = a[j];
     7            while(--j >= 0)
     8            {
     9                  if(v < a[j])
    10                  {
    11                       a[j+1] = a[j];
    12                  }
    13                  else
    14                  {
    15                        break;
    16                  }
    17            }
    18            ++j;
    19            a[j] = v;
    20            PrintArray(a);
    21      }
    22 }

    2.4 希尔排序

          希尔排序是分组的插入排序,

          划分公式可以是n*x+1,一个划分可能的划分是1 4 7 10 13 16,另一个可能的划分是1 5 9 13 17 21。

    2.5 选择排序

          选择排序,首先选取数组第一小元素放到第一项,数组第二小的元素放到第二项。

          

    void Array::SelectSort()
    {
        int i = 0;
        int j = 0;
        for(i = 0; i < 10; i++)
        {
            int min = i;
            for(j = i+1;j < 10; j++)
            {
                if(first[j] < first[min])
                {
                    min = j;
                }
            }
            first[i].Exchange(first[min]);
        }
    }

    2.6 归并排序

          归并排序和快速排序的形式相反,两个递归之后跟一个归并函数。

          归并函数的要点是,对已经排序过的数组进行排序。可以原位归并,或者借助一个数组。

          下面的代码来自《C算法》不知道打错了没有。

     1 void mergesort(Item * a,int l,int r)
     2 {
     3      int m = (r+l)/2;
     4      if(r <= l)
     5      {
     6            mergesort(a,l,m);
     7            mergesort(a,m+1,r);
     8            merge(a,l,m,r);
     9      }
    10 }
    11 merge(Item * a, int l, int m, int r)
    12 {
    13      int i,j,k;
    14      for(i = m+1; i > l; i--)
    15           aux[i-1] = a[i-1];
    16      for(i = m; j < r;j++)
    17           aux[r+m-j] = a[j+1];
    18      //上面两行代码,为的是生成bitonic序列,下面才是排序开始。
    19      for(k = l; k < r;k++)
    20           if(less(aux[j],aux[i]))
    21                a[k] = aux[j--];
    22           else
    23                a[k] = aux[i++];
    24 }

    第三章:总结

    心有千千结,心思总难知,这篇文章仅仅为心中自证,不是算法教学,也不想误人子弟,谢谢各位。  

  • 相关阅读:
    天梯赛5-12 愿天下有情人都是失散多年的兄妹 【dfs】
    poj2718 Smallest Difference【贪心】
    HDU problem 5635 LCP Array【思维】
    codeforces 782C Andryusha and Colored Balloons【构造】
    HDU 4278 Faulty Odometer【进制转换】
    codeforces B. The Meeting Place Cannot Be Changed【二分】
    POJ 3264 Balanced Lineup 【线段树】
    HDU 1850
    CodeForces-714C
    HDU Problem 1247 Hat's Words 【字典树】
  • 原文地址:https://www.cnblogs.com/likeyiyy/p/3395871.html
Copyright © 2011-2022 走看看