快速排序

  看了《程序设计实践》的开头,就碰到一个习题叫用用循环实现快速排序,开始准备pass掉的,但是一想学习过程中要注意细节,也就决定去写了,零零散散的花了不少时间,可见其中的一些微妙之处。喜欢其中的一句话,算是激励的:“Hoare描述了用循环写快速排序是如何困难的,进而发现用递归做快速排序实在是太方便了”,也就更有一些动力了,^_^。

  首先,写了一个递归的快速排序。

int quick_sort(int array[], int start, int end)
{
        if (start >= end) return 0;

        int nPoint = array[start];
        int nLast = start+1;

        for (int i = start+1; i < end; i++)
        {
                if (array[i] < nPoint)
                {
                        swap(array[i], array[nLast]);
                        nLast++;
                }
        }
        swap(array[start], array[nLast-1]);
        quick_sort(array, start, nLast-1);
        quick_sort(array, nLast, end);
        return 1;
}

  小结:

(1)自己觉得写完之后,有一种很笨拙的感觉。特别是下标那里,不是很清晰,要调试打印,发现不对之后,再把坐标改成1啊,加个1之类的。自己觉得非常的不专业,也希望老手给点建议和宝贵经验。

(2)写完之后,对于快速排序有了一个清晰的认识:就是找到一个基准点,然后保证基准点两边都是比该点大或者比该点小的。另外一个觉得有点意思的就是,会对算法复杂度认识更清晰一些,简单的考虑一个就是:如果你要和基准点比较,起码要便利一遍(n),二分的规则就是log2n,那就是O(n*log2n)。那最坏情况n^2怎么理解呢?例如,所有元素都相等,那么每次遍历都是比较n次,而二分法在他最坏的情况下,也就是n了,所以就是O(n^2)。对于复杂度,就是静下心来看进去,最后发现也就是1+1=2的清晰逻辑,会很舒服。

  接下来,是自己实现的循环实现的快速排序。

// 循环-快速排序
int quick_sort_onetime(int array[], int start, int end);
int quick_sort_for(int array[], int start, int end){
        int nPoint[32] = {0};
        int nPointTemp[32] = {0};
        int nNum = 0;
        int k = 0;      //for nPointTemp

        int nTimes = (int)(log(end)/log(2));
        nNum = 1;
        k = 1;
        nPoint[0] = 0;
        for(int i = 0; i <= nTimes; i++)
        {
                k = 0;//根据节点循环,第一次是一个
                for (int j = 0; j < nNum; j++)
                {int nSubStart = nPoint[j];
                        int nSubN = end - nSubStart;if(j+1 < nNum)
                                nSubN = nPoint[j+1]-nSubStart;
                        int nTemp = quick_sort_onetime(array, nSubStart, nSubN);
                        nPointTemp[k++] = nPoint[j];
                        nPointTemp[k++] = nTemp+1;      //从后面一位开始
                }

                for(int i = 0; i < k; i++)
                        nPoint[i] = nPointTemp[i];
                nNum = k;
        }
        return 1;
}

int quick_sort_onetime(int array[], int start, int end)
{
        if (end <= 1) return 0;

        int nPoint = array[start];
        int nLast = start+1;for(int i1 = start; i1 < start+end; i1++)
                printf("%d
", array[i1]);

        for (int i = start+1; i < start+end; i++)
        {
                if (array[i] < nPoint)
                {
                        swap(array[i], array[nLast]);
                        nLast++;
                }
        }
        swap(array[start], array[nLast-1]);for(int i2 = start; i2 < start+end; i2++)
                printf("%d
", array[i2]);
        return nLast-1;
}    

   小结:

(1)也是非常的糟糕,像小孩子的作品。

(2)而这,自己却花了相对于不少的时间。一个是,用递归的思路写循环你就是找死。其次,用递归的复杂度去写这个问题,就明晰起来,就是每次遍历一遍,比较n次。中间有很多节点,一节一节的像个火车,每次处理一节车厢,然后找到该节车厢基准点继续把车厢截断成更小的,知道车厢是最小的一个单元的时候,也就不需要比较了。说的有点模糊,看下图:

(3)自己写完之后,搜索了一下别人的结果。下面是一位别人写的,使用栈实现的,看起来就专业很多,但思想还是差不多,主要是保存中间节点的方式不一样。【http://www.cnblogs.com/zhangchaoyang/articles/2234815.html

原文地址:https://www.cnblogs.com/pk-run/p/3679159.html