基本排序算法(冒泡,快排,插入,希尔,选择,归并)

人盡茶涼 提交于 2020-03-26 00:50:05

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

第一章:一些感慨

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

从《算法导论》再到《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 }

 

第三章:总结

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!