“chaos”的算法--之非递归排序

【 声明:版权所有,欢迎转载。 联系信箱:[email protected]

在我的上一篇博客中我谈到了哈希表,采用哈希表对海量数据进行查找是一个不错的方法,它比普通查找算法的有点是不言而喻的。比如说作为一个100万的数据,如果使用普通的查找方法,那么每一个数据查找平均下来就要几十万次,如果采用二分查找20多次就可以搞定了,如果采用哈希表查找的话会更快。这个差别是很明显的。但就这三个查找方法来说,性能好的都是先对数据进行有序操作。在这篇博文中我们就来对排序算法做一个总结。

根据排序过程中数据元素是否完全在内存中分为两类:内部排序和外部排序。排序主要基于三个要素进行对比:时间复杂度,空间复杂度和算法的稳定性。但就我个人而言,我感觉排序算法主要分为递归排序和非递归排序。非递归排序,它主要按照非递归的方法对数据进行排序,也就是说主要数据的移位和循环来完成,递归方法,我们在排列当前数据的时候首先把子数据排列有序,然后才会排列当前的数据。这种不断递归调用的方法就是递归排序。 非递归排序的方法很多,这里主要介绍冒泡排序、插入排序、希尔排序;递归的方法也不少,这里介绍的方法是快速排序、归并排序和堆排序。排序的内容很多,本篇博客主要介绍非递归排序,递归排序的内容主要在下一节内容解决。

一、冒泡排序

在计算机程序设计中,我感觉冒泡排序算是最基础的排序算法了,其思想很简单,根据名字我们也知道应该是排序将大的或者小的“冒”出来。主要思想步骤如下:

1.比较相邻的前后二个数据,如果前面数据大于后面的数据,就将二个数据交换。

2.这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。

3.N=N-1,如果N不为0就重复前面二步,否则排序完成。

void bubble_sort(int array[], int length)
{
    int inner = 0, outer = 0;
    int median = 0;
                                                                                                                                                     
    if(NULL == array || 0 == length)
        return;
                                                                                                                                                     
    for(outer = length-1; outer >= 1; outer --){
        for(inner = 0; inner < outer; inner ++){
            if(array[inner] > array[inner + 1]){
                median = array[inner];
                array[inner] = array[inner + 1];
                array[inner + 1] = median;
            }
        }
    }
}

对于这样一个算法来说,或许更多的人说完美,但是就没有什么改进的地方么?答案是肯定的了。现在如果有一种情况就是发现在一次遍历循环之中,没有发生移位的现象,那么是不是可以判断这个排序可以结束呢?换句话说也就是我们待排序的数据原本就是有序数列,那我们还有必要按部就班的一步一步进行么?NO,我们当然应该说"NO"!说到这里我想大家应该已经知道该怎么做了吧,看下改进后的代码:

void bubble_sort(int array[], int length)
{
    int inner = 0, outer = 0;
    int median = 0;
    int flag = 1;  //用flag来标记进行一层遍历后是否有移位产生
                                                                                                                                              
    if(NULL == array || 0 == length)
        return;
                                                                                                                                              
    for(outer = length-1; outer >= 1 && flag; outer --){
        flag = 0;
                                                                                                                                              
        for(inner = 0; inner < outer; inner ++){
            if(array[inner] > array[inner + 1]){
                median = array[inner];
                array[inner] = array[inner + 1];
                array[inner + 1] = median;
                                                                                                                                              
                if(flag == 0)
                    flag = 1;
            }
        }
    }
}

这样的话是不是感觉就完美多了呢!!!

二、插入排序

插入排序是一种简单直观的排序算法,其思想在于每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的合适位置,知道全部记录插入完成为止。一趟排序后,并没有是一个记录到达其最终位置,这是插入类排序方法的共同的特点。

其思想实现步骤如下:

设数组为a[0…n-1]。

1.初始时,a[0]自成1个有序区,无序区为a[1..n-1]。令i=1

2.将a[i]并入当前的有序区a[0…i-1]中形成a[0…i]的有序区间。

3.i++并重复第二步直到i==n-1。排序完成。

typedef int ElemType;
//假设记录类型为int,并且记录关键字就是其本身
void InsertSort(ElemType A[], int n)
{
    ElemType x;
    for(int i=1;i<n;++i)
    {
        x=A[i];
        int j=i-1;
        while(A[j]>x)
        {
            A[j+1]=A[j];
            j--;
            if(j < 0)
                break;
        }
        A[j+1]=x;
    }
}

当然了,有哥们不太喜欢用while,更倾向于for ,其实吧都是一样的,代码如下:

void Insertsort3(int a[], int n)
{
    int i, j;
    for (i = 1; i < n; i++)
        for (j = i - 1; j >= 0 && a[j] > a[j + 1]; j--)
            Swap(a[j], a[j + 1]);
}

在这里说个题外话,之前跟一哥们聊天,他说对于递归比较恐惧,感觉知不道递归是怎么一回事,然后我就跟他说其实你每天都在用递归,只不过是你没留意罢了,当时他和他的小伙伴都惊呆了!确实如此,我们平时用的循环其实就是递归,当然了我们在这里可以做一个实例,比如说要求1到n的和,我们一般都会像下面这样写程序:

int Fun(int n)
{
    int count = 0;
    if(n < 0)
        return -1;
    for(int i = 0; i <= n; i++)
        count += i;
    return count;
}

这应该是我们大部分人惯用的方法,那么用递归式怎样呢?如下:

int Fun(int n)
{
    if(n == 0)
        return 0;
    else
        return Fun(n - 1) + n;
}

这个时候你会恍然大悟,确实如此!!!递归原来就在我身边,而卧整天还在用,这次我真的和我的小伙伴都惊呆了!

三、希尔排序

希尔排序,我个人认为可以看成是冒泡排序的变种。它的基本思想是:首先按照一个序列递减的方法逐渐进行排序。比如说有10个数据,我们按照序列5、3、1的顺序进行排序。首先是5,那么我们对1和6、2和7、3和8、4和9、5和10进行排列;第二轮是3,那么对数据1、4、7、10排列,再对2、5、8进行排列,以及3、6、9排列;第三轮就和冒泡排序一样了,以此对每个数据进行排列。它的优势就是让整个队列基本有序,减少数据移动的次数,从而降低算法的计算复杂度。

void shell_sort(int array[], int length, int step)
{
    int inner = 0;
    int outer = 0;
    int median = 0;
                                                                                            
    if(NULL == array || 0 == length)
        return;
                                                                                            
    for(; step >= 1; step -=2){
        for(int index = 0; index < step; index ++){
            if((length -1) < (index + step))
                continue;
            else{
                outer = index + step;
                while( (outer + step) <= (length - 1))
                    outer += step;
            }
                                                                                            
            for(;  outer >= (index + step);  outer -= step){
                for(inner = index; inner <= outer - step; inner += step){
                    if(array[inner] >= array[inner + step]){
                        median = array[inner];
                        array[inner] = array[inner + step];
                        array[inner + step] = median;
                    }
                }
            }
        }
    }
}


本文出自 “驿落黄昏” 博客,转载请与作者联系!

你可能感兴趣的:(数据结构,算法)