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 }

    第三章:总结

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

  • 相关阅读:
    【Python基础编程036 ● 容器 : 字符串、列表、元组、字典 ● 定义字符串的格式】
    【Python基础编程035 ● 判断语句和循环语句 ● for循环语句】
    【Python基础编程034 ● 判断语句和循环语句 ● while循环实现猜拳游戏】
    【Python基础编程033 ● 判断语句和循环语句 ● 转义字符】
    【Python基础编程032 ● 判断语句和循环语句 ● 循环嵌套中的break和continue的使用 】
    【Python基础编程031 ● 判断语句和循环语句 ● whie循环练习-打印三角形 】
    【Python基础编程030 ● 判断语句和循环语句 ● while循环练习-打印正方形 】
    (14)python网络编程,多线程socket(待写)
    【IO压测】sql server使用Diskspd测试SQL Server IO存储
    sql server使用T-SQL读取扩展事件
  • 原文地址:https://www.cnblogs.com/likeyiyy/p/3395871.html
Copyright © 2011-2022 走看看