排序算法复习(一)

排序算法是最基本的算法之一,尽管大家都很熟悉了,只是鉴于其无处不在的重要性,不妨大家一起来复习一下,到底有哪些排序算法。本人将描述自己已经了解的排序算法,并配上相应的C++代码。

没有特别说明,所有的排序结果都是非递减的。

冒泡排序(bubble sort)
对于数组a[N],冒泡过程是这样的:比较元素a[k]和a[k+1](k从0到N - 2),如果a[k] > a[k+1],进行交换,这样进行N - 1次冒泡之后,a[N-1]将是数组中最大的数。如果我们要让整个数组都变得有序,我还需要对数组中前N - 1个元素进行冒泡,每一次都排序好一个元素,一直重复下去,直到整个数组都排好。
下面是一段对应的C++代码。
// bubble-up sort algorithm
// O(T) = n*n
template<class T>
void busort(T* sz, int n)
{
    
for (int i = 0; i < n - 1; i++)
    
for (int j = 0; j < n - i - 1; j++)
    
{
        
if (compare(sz[j], sz[j + 1]) > 0)
            swap(sz[j], sz[j 
+ 1]);
    }

}
冒泡算法应用最多的应该是在面试题中,实际工程中应用很少,原因是效率太低了。其时间度是n*n,准确的说是(n-2)*(n-1)/2次循环,也就是最少需要(n-2)*(n-1)/2次比较,最坏的情况是还要加上(n-2)*(n-1)/2次交换(一次交换包括三次赋值操作)。不过冒泡算法并不需要额外的空间开销。

插入排序(insertion sort)
将一个元素插入到一个有序的数组中,形成一个新的有序数组,称之为插入排序。对于数组a[N]来说,我们将第一个元素a[0]视为初始有序数组,然后将接下来的第一个元素a[1]插入到之前的有序数组中,直到最后一个元素a[N-1]处理完,最终形成整个有序数组。
下面是一段对应的C++代码。
// insertion sort algorithm
// O(T) = n*n
template<class T>
void insort(T* a, int n)
{
    
for (int i = 2; i < n; i++)
    
{
        
// save it
        T temp = a[i];
        
// insert it
        for (int j = i - 1; j > 0 && compare(temp, a[j]) < 0; j--)
            a[j 
+ 1= a[j];
        
// get the position
        a[j + 1= temp;
    }

}
虽然其时间度也是n*n,但是相对于冒泡法,插入排序最坏的情况下才需要(n-2)*(n-1)/2次循环,最好的情况是n-2次循环。而且每次比较之后的交换操作相对于冒泡法仅需要一次赋值。空间上也没有什么额外的开销。

归并排序(merge sort)
将两个有序数组合并为一个新的有序的数组,称之为归并排序。对于数组a[N],我们考虑将其均分为两个数组b和c,假设b和c已经是有序数组,此时我们可以运用归并排序将两个有序数组合并。至于b和c,我可以嵌套运用同样的方法将其置为有序。
// merge sort algorithm

// merge an unordered array
// O(T) - nlog(n)
template<class T>
void merge(T* a, int m, int l, int n);
template
<class T>
void mergesort(T* a, int m, int n)
{
    
if (m == n)
        
return ;

    
// divide it to two halves
    int l = (m + n) / 2;

    
// sort them
    mergesort(a, m, l);
    mergesort(a, l 
+ 1, n);

    
// merge them
    merge(a, m, l, n);
}


// merge two odered arrays
template<class T>
void merge(T* a, int m, int l, int n)
{
    
if (!(m <= l && l < n))
        
return ;

    T
* b = new T[n - m + 1];

    
int k = 0, i = m, j = l + 1;
    
while (i <= l && j <= n)
    
{
        
if (compare(a[i], a[j]) <= 0)
            b[k
++= a[i++];
        
else
            b[k
++= a[j++];
    }

    
while (i <= l)
        b[k
++= a[i++];
    
while (j <= n)
        b[k
++= a[j++];
    
for (int k = 0; k < n - m + 1; k++)
        a[m 
+ k] = b[k];

    delete[] b;
}
其时间度是n*log(n),其时间虽然比上述排序办法快,但是在空间上要额外用到同样大小的数组作为临时空间,而且,不管是最好还是最坏情况,赋值操作的数量不会改变。

待续。






posted on 2008-05-08 17:15  zoom  阅读(233)  评论(0编辑  收藏  举报