循序渐进之基础排序

  排序就是将一组数据按一定规律排列起来,它在计算机操作中被频繁调用,因而是软件设计中最为基础的算法之一。本文所述算法均以升序排序,且使用以下公共函数。
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>

using namespace std;
#define LEN (10)

// general function
template <class T>
void Display(T a[], int len)
{
    for (int i = 0; i < len; i++) {
        cout << a[i] << '/t';
    }
    cout << endl;
}

template <class T>
inline void Swap(T& a, T& b)
{
    T t = a;
    a = b;
    b = t;
}
int main(int argc, char* argv[])
{
    // initialization
    int ArrInput[LEN];
    srand((unsigned)time(NULL)); // seed the random generator with current time
    for (int i = 0; i < LEN; i++) {
        ArrInput[i] = rand();
    }
    // sort
    BubbleSort(ArrInput, LEN); // or other sort algorithm
    // display
    Display(ArrInput, LEN);

    return 0;
}

1、冒泡排序:
  冒泡排序(Bubble Sort)对一N长数列作N-1次扫描,每次扫描时都从前往后依次比较两相邻元素的大小,并在发现逆序时作交换操作。一个广泛使用的加速技巧是:在某次扫描完成后,发现本次扫描未进行任何交换操作时,算法终止。

  班里要参加广播操比赛(初高中时最烦做广播操,现在却有些怀念),站队完毕后,老师总会不断巡视整个队列,比较挨着的某两人的身高,指挥某两位对换一下位置(总会有人在此时遭受无情打击)。只是与计算机不同,老师有时会犯错,可能又会接着指挥:你们俩还是换回来吧(某人窃喜:就是嘛,我怎么可能比他矮!);计算机不会犯这种错误。

  与日常生活类似,当给出的数列已经比较有序,只需要小幅调整时,可考虑使用冒泡排序。

template <class T>
void Bubble(T a[], int len)
{ // bubble the largest number to the end of the array
    for(int i = 0; i < len-1; i++) {
        if(a[i] > a[i+1]) {
            Swap(a[i], a[i+1]);
        }
    }
}

template <class T>
void BubbleSort(T a[], int len)
{
    for(int i = len; i > 1; i--) {
        Bubble(a, i);
    }
}
// accelerated version
template <class T>
void BubbleSort(T a[], int len)
{
    int nLoopCnt = 0; // scans counter for demonstration
    bool bSorted = false; // flag to accelerate algorithm
    for(int nSize = len; nSize > 1; nSize--) {
        bSorted = true;
        for (int i = 0; i < nSize - 1; i++) { // this loop is known as 'bubble'
            if(a[i] > a[i+1]) {
                Swap(a[i], a[i+1]);
                bSorted = false;
            }
        }
        nLoopCnt++;
        if (true == bSorted) {
            break;
        }
    }
    cout << "Completed after " << nLoopCnt << " scan(s)." << endl;
}

2、选择排序:
  选择排序(Selection Sort)从N长数列中找出最大数,将其交换到N长数列最后;接着从余下的N-1长数列中再找出最大数,将其交换到N-1长数列最后;……;不断重复下去,直至最后剩余数列长度为1为止。

  在男生宿舍的卧谈会,为班中女生选美时,会自然而然地使用选择排序。

  与日常生活类似,当急切地渴望知道一个队列中的前几名时,可以使用选择排序。

template<class T>
int Max(T a[], int len)
{
    int pos = 0;
    for(int i = 1; i < len; i++) {
        if(a[pos] < a[i]) {
            pos = i;
        }
    }
    return pos;
}

template <class T>
void SelectionSort(T a[], int len)
{
    for(int i = len; i > 1; i--) {
        int j = Max(a, i);
        Swap(a[j], a[i-1]); // swap the largest number to the end of the array
    }
}
// accelerated version
template <class T>
void SelectionSort(T a[], int len)
{
    int nLoopCnt = 0; // scans counter for demonstration
    bool bSorted = false; // flag to accelerate algorithm
    for(int nSize = len; nSize > 1; nSize--) {
        bSorted = true;
        int pos = 0;
        for (int i = 1; i < nSize; i++) {
            if(a[pos] < a[i]) {
                pos = i;
            }
            else {
                bSorted = false;
            }
        }
        if (true == bSorted) {
            break;
        }
        nLoopCnt++;
        Swap(a[pos], a[nSize-1]);
    }
    cout << "Completed after " << nLoopCnt << " scan(s)." << endl;
}

3、插入排序:
  插入排序(Insertion Sort)从N长数列中依次取出所有数,按大小关系依次插入到一新数列中,并始终保持新数列有序。

  打牌时,洗完牌后,将桌上的牌(一个N长无序数列)不断拿入手中(手中的牌就是一个有序数列)就是一个插入排序的过程。

  与日常生活类似,当我们会不断收到新数据并想始终保持已有数据的有序状态时,可优先考虑使用插入排序。

template<class T>
void Insert(T a[], int len, const T& x)
{ // insert 'x' to the ascending array 'a' and keep ascending
    for (int i = len-1; i >= 0 && x < a[i]; i--) {
        a[i+1] = a[i]; // asserted 'x' has enough memory
    }
    a[i+1] = x;
}

template<class T>
void InsertionSort(T a[], int len)
{
    for (int i = 1; i < len; i++) {
        T t = a[i];
        Insert(a, i, t);
    }
}

4、计数排序:
  计数排序(Counting Sort)首先为N长数列中的每个元素统计出其等级(或称为rank,可定义为数列中所有比它小的元素数目加上在它左边出现的与它相同的元素数目),并按每个元素的等级将其放入一个有序数列中。

  由算法原理可以看出,计数排序一般适用于数组操作。虽然在人们的日常习惯中,不大容易找到计数排序的应用实例,但它有一个非常适合实现各类科学算法的先天优势,它可以返回数列在排序后的索引(类似于Matlab的sort命令,这在写某些领域的特定算法时非常有用,本人在编写ViV时使用的就是计数排序)。

template <class T>
void Rank(T a[], int len, int r[])
{
    for(int i = 0; i < len; i++) { // initialize the rank array
        r[i] = 0;
    }
    for (i = 1; i < len; i++) {
        for (int j = 0; j < i; j++) {
            if (a[j] <= a[i]) {
                r[i]++;
            }
            else {
                r[j]++;
            }
        }
    }
}

template <class T>
void CountingSort(T a[], int len, int r[])
{
    Rank(a, len, r);
    T *u = new T[len];
    for(int i = 0; i < len; i++) { // need extra memory
        u[r[i]] = a[i];
    }
    for (i = 0; i < len; i++) { // copy back
        a[i] = u[i];
    }
    delete []u;
}
// a modified version that need no extra memory
template <class T>
void CountingSort(T a[], int len, int r[])
{
    Rank(a, len, r);
    for (int i = 0; i < len; i++) {
        while (i != r[i]) { // need no extra memory
            int t = r[i];
            Swap(a[i], a[t]); // swap the a[i] to the right position
            Swap(r[i], r[t]); // correct 'r' corresponding to the change of 'a'
        }
    }
}

  以上4种排序算法最容易理解,但时间复杂度最次,均为O(n2)。由于变种繁多,且无太大实际意义,详细的空间复杂度分析与时间复杂度分析在此不作展开。在实际应用中,4种排序算法的效率并不相同;实践证明,插入排序是相对最快的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值