各个排序算法的具体实现

冒泡排序


#include<iostream>
using namespace std;
int main()
{
    int a[5] = { 5,4,3,2,1 };
    int i, j;
    for (i = 0; i < 4; i++)
    {
        bool flag = true;
        for (j = 0; j < 4 - i; j++)
        {
            if (a[j] > a[j + 1])
            {
                swap(a[j], a[j + 1]);
                flag = false;
            }
        }
        if (flag) break;
    }
    for (i = 0; i < 5; i++)
        cout << a[i] << ' ';
    return 0;
}

选择排序


#include<iostream>
using namespace std;
int main()
{
    int a[5] = { 5,4,3,2,1 };
    int i, j;
    for (i = 0; i < 4; i++)
        for (j = i + 1; j < 5; j++)
            if (a[j] < a[i])
                swap(a[j], a[i]);
    for (i = 0; i < 5; i++)
        cout << a[i] << ' ';
    return 0;
}

插入排序


#include<iostream>
using namespace std;
int main()
{
    int a[100];
    int i, j, temp;
    for (i = 0; i < 5; i++)
        cin >> a[i];
    for (j = 1; j < 5; j++)
        for (i = 0; i < j; i++)
        {
            if (a[j] < a[i])
            {
                int temp = a[j];
                for (int m = j; m > i; m--)
                    a[m] = a[m - 1];
                a[i] = temp;
                break;
            }
        }
    for (i = 0; i < 5; i++)
        cout << a[i] << ' ';
    return 0;
}

快速排序


#include<iostream>
using namespace std;
void QuickSort(vector<int>& a, int l, int r)
{
    if (l >= r) return;
    int temp = a[l];
    int i = l, j = r;
    while (i < j)
    {
        while (i<j && a[j]>temp) j--;
        if (i < j) a[i++] = a[j];
        while (i<j && a[i]<temp) i++;
        if (i < j) a[j--] = a[i];
    }
    a[i] = temp;
    QuickSort(a, l, i - 1);
    QuickSort(a, i + 1, r);
}
int main()
{
    vector<int>a{ 5,4,3,2,1 };
    QuickSort(a, 0, a.size() - 1);
    for (int i = 0; i < a.size(); i++)
        cout << a[i] << ' ';
    return 0;
}

希尔排序


/*
 * 对希尔排序中的单个组进行排序
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     n -- 数组总的长度
 *     i -- 组的起始位置
 *     gap -- 组的步长
 *
 *  组是"从i开始,将相隔gap长度的数都取出"所组成的!
 */
    void group_sort(int a[], int n, int i, int gap)
{
    int j;

    for (j = i + gap; j < n; j += gap)
    {
        // 如果a[j] < a[j-gap],则寻找a[j]位置,并将后面数据的位置都后移。
        if (a[j] < a[j - gap])
        {
            int tmp = a[j];
            int k = j - gap;
            while (k >= 0 && a[k] > tmp)
            {
                a[k + gap] = a[k];
                k -= gap;
            }
            a[k + gap] = tmp;
        }
    }
}

/*
 * 希尔排序
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     n -- 数组的长度
 */
void shell_sort2(int a[], int n)
{
    int i, gap;

    // gap为步长,每次减为原来的一半。
    for (gap = n / 2; gap > 0; gap /= 2)
    {
        // 共gap个组,对每一组都执行直接插入排序
        for (i = 0; i < gap; i++)
            group_sort(a, n, i, gap);
    }
}

堆排序


/*
 * (最大)堆的向下调整算法
 *
 * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
 *     其中,N为数组下标索引值,如数组中第1个数对应的N为0。
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
 *     end   -- 截至范围(一般为数组中最后一个元素的索引)
 */
    void maxheap_down(int a[], int start, int end)
{
    int c = start;            // 当前(current)节点的位置
    int l = 2 * c + 1;        // 左(left)孩子的位置
    int tmp = a[c];            // 当前(current)节点的大小
    for (; l <= end; c = l, l = 2 * l + 1)
    {
        // "l"是左孩子,"l+1"是右孩子
        if (l < end && a[l] < a[l + 1])
            l++;        // 左右两孩子中选择较大者,即m_heap[l+1]
        if (tmp >= a[l])
            break;        // 调整结束
        else            // 交换值
        {
            a[c] = a[l];
            a[l] = tmp;
        }
    }
}

/*
 * 堆排序(从小到大)
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     n -- 数组的长度
 */
void heap_sort_asc(int a[], int n)
{
    int i;

    // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。
    for (i = n / 2 - 1; i >= 0; i--)
        maxheap_down(a, i, n - 1);

    // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
    for (i = n - 1; i > 0; i--)
    {
        // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。
        swap(a[0], a[i]);
        // 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。
        // 即,保证a[i-1]是a[0...i-1]中的最大值。
        maxheap_down(a, 0, i - 1);
    }
}

归并排序(从下到上)


/*
 * 对数组a做若干次合并:数组a的总长度为len,将它分为若干个长度为gap的子数组;
 *             将"每2个相邻的子数组" 进行合并排序。
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     len -- 数组的长度
 *     gap -- 子数组的长度
 */
    void merge_groups(int a[], int len, int gap)
{
    int i;
    int twolen = 2 * gap;    // 两个相邻的子数组的长度

    // 将"每2个相邻的子数组" 进行合并排序。
    for (i = 0; i + 2 * gap - 1 < len; i += (2 * gap))
    {
        merge(a, i, i + gap - 1, i + 2 * gap - 1);
    }

    // 若 i+gap-1 < len-1,则剩余一个子数组没有配对。
    // 将该子数组合并到已排序的数组中。
    if (i + gap - 1 < len - 1)
    {
        merge(a, i, i + gap - 1, len - 1);
    }
}

/*
 * 归并排序(从下往上)
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     len -- 数组的长度
 */
void merge_sort_down2up(int a[], int len)
{
    int n;

    if (a == NULL || len <= 0)
        return;

    for (n = 1; n < len; n *= 2)
        merge_groups(a, len, n);
}

归并排序(从上到下)


/*
 * 将一个数组中的两个相邻有序区间合并成一个
 *
 * 参数说明:
 *     a -- 包含两个有序区间的数组
 *     start -- 第1个有序区间的起始地址。
 *     mid   -- 第1个有序区间的结束地址。也是第2个有序区间的起始地址。
 *     end   -- 第2个有序区间的结束地址。
 */
    void merge(int a[], int start, int mid, int end)
{
    int* tmp = (int*)malloc((end - start + 1) * sizeof(int));    // tmp是汇总2个有序区的临时区域
    int i = start;            // 第1个有序区的索引
    int j = mid + 1;        // 第2个有序区的索引
    int k = 0;                // 临时区域的索引

    while (i <= mid && j <= end)
    {
        if (a[i] <= a[j])
            tmp[k++] = a[i++];
        else
            tmp[k++] = a[j++];
    }

    while (i <= mid)
        tmp[k++] = a[i++];

    while (j <= end)
        tmp[k++] = a[j++];

    // 将排序后的元素,全部都整合到数组a中。
    for (i = 0; i < k; i++)
        a[start + i] = tmp[i];

    free(tmp);
}

/*
 * 归并排序(从上往下)
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     start -- 数组的起始地址
 *     endi -- 数组的结束地址
 */
void merge_sort_up2down(int a[], int start, int end)
{
    if (a == NULL || start >= end)
        return;

    int mid = (end + start) / 2;
    merge_sort_up2down(a, start, mid); // 递归排序a[start...mid]
    merge_sort_up2down(a, mid + 1, end); // 递归排序a[mid+1...end]

    // a[start...mid] 和 a[mid...end]是两个有序空间,
    // 将它们排序成一个有序空间a[start...end]
    merge(a, start, mid, end);
}

桶排序


/*
 * 桶排序
 *
 * 参数说明:
 *     a -- 待排序数组
 *     n -- 数组a的长度
 *     max -- 数组a中最大值的范围
 */
    void bucketSort(int a[], int n, int max)
{
    int i, j;
    int buckets[max];

    // 将buckets中的所有数据都初始化为0。
    memset(buckets, 0, max * sizeof(int));

    // 1. 计数
    for (i = 0; i < n; i++)
        buckets[a[i]]++;

    // 2. 排序
    for (i = 0, j = 0; i < max; i++)
    {
        while ((buckets[i]--) > 0)
            a[j++] = i;
    }
}

基数排序


/*
 * 获取数组a中最大值
 *
 * 参数说明:
 *     a -- 数组
 *     n -- 数组长度
 */
    int get_max(int a[], int n)
{
    int i, max;

    max = a[0];
    for (i = 1; i < n; i++)
        if (a[i] > max)
            max = a[i];
    return max;
}

/*
 * 对数组按照"某个位数"进行排序(桶排序)
 *
 * 参数说明:
 *     a -- 数组
 *     n -- 数组长度
 *     exp -- 指数。对数组a按照该指数进行排序。
 *
 * 例如,对于数组a={50, 3, 542, 745, 2014, 154, 63, 616};
 *    (01) 当exp=1表示按照"个位"对数组a进行排序
 *    (02) 当exp=10表示按照"十位"对数组a进行排序
 *    (03) 当exp=100表示按照"百位"对数组a进行排序
 *    ...
 */
void count_sort(int a[], int n, int exp)
{
    int output[n];             // 存储"被排序数据"的临时数组
    int i, buckets[10] = { 0 };

    // 将数据出现的次数存储在buckets[]中
    for (i = 0; i < n; i++)
        buckets[(a[i] / exp) % 10]++;

    // 更改buckets[i]。目的是让更改后的buckets[i]的值,是该数据在output[]中的位置。
    for (i = 1; i < 10; i++)
        buckets[i] += buckets[i - 1];

    // 将数据存储到临时数组output[]中
    for (i = n - 1; i >= 0; i--)
    {
        output[buckets[(a[i] / exp) % 10] - 1] = a[i];
        buckets[(a[i] / exp) % 10]--;
    }

    // 将排序好的数据赋值给a[]
    for (i = 0; i < n; i++)
        a[i] = output[i];
}

/*
 * 基数排序
 *
 * 参数说明:
 *     a -- 数组
 *     n -- 数组长度
 */
void radix_sort(int a[], int n)
{
    int exp;    // 指数。当对数组按各位进行排序时,exp=1;按十位进行排序时,exp=10;...
    int max = get_max(a, n);    // 数组a中的最大值

    // 从个位开始,对数组a按"指数"进行排序
    for (exp = 1; max / exp > 0; exp *= 10)
        count_sort(a, n, exp);
}

以上为各个排序算法的原理,在实际应用中能sort就尽量sort!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

另一个人。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值