常考排序算法

1 冒泡排序

算法思想:
冒泡排序与快速排序属于互换类的排序方法。冒泡排序是通过相邻数据元素的交换逐步将线性表变成有序。基本过程为:
首先,从表头开始扫描线性表,在扫描的过程中逐次比较相邻两个元素的大小。若前面元素大于后面元素,则将它们互换消去一个逆序。
然后,从后到前扫描剩下的线性表,同样在扫描过程中比较两个元素的大小,若相邻两个元素中,后面的元素小于前面的元素,则将它们互换,这样又消去一个逆序。
对剩下的线性表重复上述的过程,直到剩下的线性表变为空为止,此时的线性表已经变为有序。
代码:

template <class T>
void bub(T p[], int n)
{
    int m, k, j, i;
    T d;
    k = 0; m = n - 1;
    while (k<m)
    {
        j = m - 1; m = 0;
        for (i = k; i <= j; i++) //从前往后扫描
            if (p[i]>p[i+1]) //顺序不对,交换
            {
                d = p[i]; p[i] = p[i + 1]; p[i + 1] = d; m = i;
            }
        j = k + 1; k = 0;
        for (i = m; i >= j;i--) //从后往前扫描
            if (p[i-1]>p[i]) //顺序不对交换
            {
                d = p[i]; p[i] = p[i - 1]; p[i - 1] = d; k = i;
            }
    }

    return;
}

2 快速排序

算法思想:
从线性表中选取一个元素,设为T,对线性表进行分割,将线性表后面小于T的元素移到前面,而前面大于T的元素移动到后面,结果就将线性表分割为两部分。具体过程为:
首先在表的第一个、中间一个与最后一个元素中选取中项,设为p(k),并将p(k)赋给T,再将表中的第一个元素移到p(k)的位置上。
然后设置两个指针i和j分别指向表的起始与最后的位置。反复作以下两步:
(1)将j逐渐增大,并逐次比较p(j)与T,直到发现一个p(j)小于T为止,将p(j)移到p(i)的位置上。
(2)将i逐渐增大,并逐次比较p(i)与T,直到发现一个p(i)大于T为止,将p(i)移到p(j)的位置上。
上述两个操作交替进行,直到指针i与j指向同一个位置(即i=j)为止,此时将T移动到p(i)的位置上。
代码:

#include "bub.h"

template <class T>
void qck(T p[], int n){

    int m, i;
    T *s;
    if (n > 10) //子表长度大于10,用快速排序  
    {
        i = split(p, n); //对表进行分割  
        qck(p, i); //对前面的子表进行快速排序  
        s = p + (i + 1);
        m = n - (i + 1);
        qck(s, m); //对后面的子表进行快速排序  
    }
    else
    {
        bub(p, n);
    }
    return;
}

//表的分割  
template<class T>
static int split(T p[], int n){

    int i, j, k, l;
    T t;
    i = 0;
    j = n - 1;
    k = (i + j) / 2;
    if ((p[i] >= p[j]) && (p[j] >= p[k])) l = j;
    else if ((p[i] >= p[k]) && (p[k] >= p[j]))l = k;
    else l = i;

    t = p[l]; //选取一个元素为T  
    p[l] = p[i];
    while (i != j)
    {
        while ((i < j) && p[j] >= t) //逐渐减小j,直到发现p[j]<t  
            j = j - 1;
        if (i < j)
        {
            p[i] = p[j];
            i = i + 1;
            while ((i < j) && (p[i] <= t)) //逐渐增大i,直到发现p[i]>t  
                i = i + 1;
            if (i < j)
            {
                p[j] = p[i]; j = j - 1;
            }
        }
    }
    p[i] = t;
    return i;
}

3 插入排序

算法思想:
所谓插入排序是指将无序序列中的各元素一次插入到已经有序的线性表中。
首先将第j个元素放到一个变量T中,然后从有序字表的最后一个元素开始,往前逐个与T进行比较,将大于T的元素均依次向后移动一个位置,直到发现一个元素不大于T为止,此时就将T插入到刚移出的空位置上,有序表的长度就变为j了。这种排序方法的效率与冒泡排序法相同,最坏的情况下,简单插入排序需要n(n-1)/2次比较。
代码:

template <class T>
void insort(T p[], int n){

    int j, k;
    T t;
    for (j = 1; j < n;j++)
    {
        t = p[j];
        k = j - 1;
        while ((k>=0)&&p[k]>t)
        {
            p[k + 1] = p[k]; k = k - 1;
        }
        p[k + 1] = t;
    }
    return;
}

4 希尔排序

算法思想:
希尔排序(Shell Sort)属于插入类排序,将整个无序序列分割成若干小的子序列分别进行插入排序。
子序列的分割方法如下:
将相隔某个增量h的元素构成一个子序列。在排序过程中,逐次减小这个增量,最后当h减到1时,进行一次插入排序,排序就完成。
增量序列一般取,其中n为待排序序列的长度。
希尔排序的示意图:
这里写图片描述
代码:

template <class T>
void shel(T p[], int n){

    int k, j, i;
    T t;
    k = n / 2;
    while (k > 0)
    {
        for (j = k; j <= n - 1;j++)
        {
            t = p[j];
            i = j - k;
            while ((i >= 0) &&(p[i] > t))
            {
                p[i + k] = p[i];
                i = i - k;
            }
            p[i + k] = t;
        }
        k = k / 2;
    }
    return;
}

5 选择排序

算法思想:
对于长度为n的序列,选择排序需要扫描n-1遍,每一遍扫描均从剩下的字表中选出最小的元素,然后将该最小的元素与子表中的第一个元素进行交换。选择排序最坏情况下需要比较n(n-1)/2次。
代码:

template <class T>
void select(T p[], int n)
{
    int i, j, k;
    T d;
    for (i = 0; i < n - 1; i++)
    {
        k = i;
        for (j = i + 1; j < n; j++)
            if (p[j] < p[k]) k = j;
        if (k!=j)
        {
            d = p[i]; p[i] = p[k]; p[k] = d;
        }
    }
    return;
}

6 堆排序

算法思想:
堆排序属于选择类的排序方法。
堆的定义:
具有n个元素的序列,当且仅当满足
这里写图片描述
根据堆的定义,可以得到堆排序的方法如下:
(1)首先将一个无序序列建成堆。
(2)然后将堆顶元素(序列中最大项)与堆中最后一个元素交换(最大项应该在序列的最后)。不考虑已经换到最后的那个元素,只考虑前n-1个元素构成的子序列,显然,该子序列已不是堆,但左右子树仍然为堆,可以将该子序列调整为堆。反复做第(2)步,直到剩下的子序列为空为止。
对于大规模的线性表来说是很有效的,堆排序需要比较的次数为。
代码:

template <class T>
void hap(T p[], int n)
{
    int i, mm;
    T t;
    mm = n / 2;
    for (i = mm - 1; i >= 0; i--) sift(p, i, n - 1);  //无序序列建堆
    for (i = n - 1; i >= 1; i--)
    {
        t = p[0]; p[0] = p[i]; p[i] = t; //堆顶元素换到最后
        sift(p, 0, i - 1); //调整建堆
    }
    return;
}

template <class T>
static sift(T p[], int i, int n)
{
    int j;
    T t;
    t = p[i]; j = 2 * (i + 1) - 1;
    while (j <= n)
    {
        if ((j < n) && (p[j] < p[j + 1])) j = j + 1;
        if (t < p[j])
        {
            p[i] = p[j]; i = j; j = 2 * (i + 1) - 1;
        }
        else{
            j = n + 1;
        }
    }
    p[i] = t;
    return 0;
}

7 归并排序

所谓归并排序(Merge Sort)是指把一个长度为n的线性表看成是由n个长度为1的有序表组成,然后反复进行两两归并,最后就得到长度为n的有序线性表。由于归并是两两进行的,因此也称为2-路归并排序。
归并排序的算法又递归和非递归两种形式。非递归算法如下

template<class T>
static int merg(T p[], int low, int mid, int high, T a[])
{
    int i, j, k;
    i = low;
    j = mid + 1;
    k = low;
    while ((i <= mid) && (j <= high))
    {
        if (p[i - 1] <= p[j - 1])
        {
            a[k - 1] = p[i - 1];
            i = i + 1;
        }
        else
        {
            a[k - 1] = p[j - 1];
            j = j + 1;
        }
        k = k + 1;
    }

    if (i <= mid)
        for (j = i; j <= mid; j++)
        {
            a[k - 1] = p[j - 1];
            k = k + 1;
        }
    else if (j <= high)
        for (i = j; i <= high; i++)
        {
            a[k - 1] = p[i - 1];
            k = k + 1;
        }

    for (i = low; i <= high; i++)
    {
        p[i - 1] = a[i - 1];
    }
    return 0;
}

template <class T>
void merge(T p[], int n)
{
    int m, k, j, low, high, mid;
    T * a;
    a = new T[n];
    m = 1;
    while (m < n)
    {
        k = 2 * m;
        for (j = 1; j <= n; j = j + k)
        {
            low = j;
            high = j + k - 1;
            mid = j + m - 1;
            if (high > n)high = n;
            if (high > mid)
                merg(p, low, mid, high, a);
        }
        m = k;
    }
    delete a;
    return;
}

Reference:
http://blog.csdn.net/wuxinyicomeon/article/details/5996675/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DaveBobo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值